123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839 |
- package bridge
- import (
- "net"
- "strings"
- "sync"
- "github.com/docker/libnetwork/driverapi"
- "github.com/docker/libnetwork/ipallocator"
- "github.com/docker/libnetwork/netutils"
- "github.com/docker/libnetwork/pkg/netlabel"
- "github.com/docker/libnetwork/pkg/options"
- "github.com/docker/libnetwork/portmapper"
- "github.com/docker/libnetwork/sandbox"
- "github.com/docker/libnetwork/types"
- "github.com/vishvananda/netlink"
- )
- const (
- networkType = "bridge"
- vethPrefix = "veth"
- vethLen = 7
- containerVeth = "eth0"
- maxAllocatePortAttempts = 10
- )
- var (
- ipAllocator *ipallocator.IPAllocator
- portMapper *portmapper.PortMapper
- )
- // Configuration info for the "bridge" driver.
- type Configuration struct {
- BridgeName string
- AddressIPv4 *net.IPNet
- FixedCIDR *net.IPNet
- FixedCIDRv6 *net.IPNet
- EnableIPv6 bool
- EnableIPTables bool
- EnableIPMasquerade bool
- EnableICC bool
- EnableIPForwarding bool
- AllowNonDefaultBridge bool
- Mtu int
- DefaultGatewayIPv4 net.IP
- DefaultGatewayIPv6 net.IP
- DefaultBindingIP net.IP
- }
- // EndpointConfiguration represents the user specified configuration for the sandbox endpoint
- type EndpointConfiguration struct {
- MacAddress net.HardwareAddr
- PortBindings []netutils.PortBinding
- ExposedPorts []netutils.TransportPort
- }
- // ContainerConfiguration represents the user specified configuration for a container
- type ContainerConfiguration struct {
- ParentEndpoints []string
- ChildEndpoints []string
- }
- type bridgeEndpoint struct {
- id types.UUID
- intf *sandbox.Interface
- macAddress net.HardwareAddr
- config *EndpointConfiguration // User specified parameters
- containerConfig *ContainerConfiguration
- portMapping []netutils.PortBinding // Operation port bindings
- }
- type bridgeNetwork struct {
- id types.UUID
- bridge *bridgeInterface // The bridge's L3 interface
- endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id
- sync.Mutex
- }
- type driver struct {
- config *Configuration
- network *bridgeNetwork
- sync.Mutex
- }
- func init() {
- ipAllocator = ipallocator.New()
- portMapper = portmapper.New()
- }
- // New provides a new instance of bridge driver
- func New() (string, driverapi.Driver) {
- return networkType, &driver{}
- }
- // Validate performs a static validation on the configuration parameters.
- // Whatever can be assessed a priori before attempting any programming.
- func (c *Configuration) Validate() error {
- if c.Mtu < 0 {
- return ErrInvalidMtu
- }
- // If bridge v4 subnet is specified
- if c.AddressIPv4 != nil {
- // If Container restricted subnet is specified, it must be a subset of bridge subnet
- if c.FixedCIDR != nil {
- // Check Network address
- if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
- return ErrInvalidContainerSubnet
- }
- // Check it is effectively a subset
- brNetLen, _ := c.AddressIPv4.Mask.Size()
- cnNetLen, _ := c.FixedCIDR.Mask.Size()
- if brNetLen > cnNetLen {
- return ErrInvalidContainerSubnet
- }
- }
- // If default gw is specified, it must be part of bridge subnet
- if c.DefaultGatewayIPv4 != nil {
- if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
- return ErrInvalidGateway
- }
- }
- }
- // If default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet
- if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
- if c.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) {
- return ErrInvalidGateway
- }
- }
- return nil
- }
- func (n *bridgeNetwork) getEndpoint(eid types.UUID) (*bridgeEndpoint, error) {
- n.Lock()
- defer n.Unlock()
- if eid == "" {
- return nil, InvalidEndpointIDError(eid)
- }
- if ep, ok := n.endpoints[eid]; ok {
- return ep, nil
- }
- return nil, nil
- }
- func (d *driver) Config(option map[string]interface{}) error {
- var config *Configuration
- d.Lock()
- defer d.Unlock()
- if d.config != nil {
- return ErrConfigExists
- }
- genericData := option[netlabel.GenericData]
- if genericData != nil {
- switch opt := genericData.(type) {
- case options.Generic:
- opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{})
- if err != nil {
- return err
- }
- config = opaqueConfig.(*Configuration)
- case *Configuration:
- config = opt
- default:
- return ErrInvalidDriverConfig
- }
- if err := config.Validate(); err != nil {
- return err
- }
- d.config = config
- }
- return nil
- }
- func (d *driver) getNetwork(id types.UUID) (*bridgeNetwork, error) {
- // Just a dummy function to return the only network managed by Bridge driver.
- // But this API makes the caller code unchanged when we move to support multiple networks.
- d.Lock()
- defer d.Unlock()
- return d.network, nil
- }
- // Create a new network using bridge plugin
- func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
- var err error
- // Driver must be configured
- d.Lock()
- if d.config == nil {
- d.Unlock()
- return ErrInvalidNetworkConfig
- }
- config := d.config
- // Sanity checks
- if d.network != nil {
- d.Unlock()
- return ErrNetworkExists
- }
- // Create and set network handler in driver
- d.network = &bridgeNetwork{id: id, endpoints: make(map[types.UUID]*bridgeEndpoint)}
- d.Unlock()
- // On failure make sure to reset driver network handler to nil
- defer func() {
- if err != nil {
- d.Lock()
- d.network = nil
- d.Unlock()
- }
- }()
- // Create or retrieve the bridge L3 interface
- bridgeIface := newInterface(config)
- d.network.bridge = bridgeIface
- // Prepare the bridge setup configuration
- bridgeSetup := newBridgeSetup(config, bridgeIface)
- // If the bridge interface doesn't exist, we need to start the setup steps
- // by creating a new device and assigning it an IPv4 address.
- bridgeAlreadyExists := bridgeIface.exists()
- if !bridgeAlreadyExists {
- bridgeSetup.queueStep(setupDevice)
- }
- // Even if a bridge exists try to setup IPv4.
- bridgeSetup.queueStep(setupBridgeIPv4)
- // Conditionnally queue setup steps depending on configuration values.
- for _, step := range []struct {
- Condition bool
- Fn setupStep
- }{
- // Enable IPv6 on the bridge if required. We do this even for a
- // previously existing bridge, as it may be here from a previous
- // installation where IPv6 wasn't supported yet and needs to be
- // assigned an IPv6 link-local address.
- {config.EnableIPv6, setupBridgeIPv6},
- // We ensure that the bridge has the expectedIPv4 and IPv6 addresses in
- // the case of a previously existing device.
- {bridgeAlreadyExists, setupVerifyAndReconcile},
- // Setup the bridge to allocate containers IPv4 addresses in the
- // specified subnet.
- {config.FixedCIDR != nil, setupFixedCIDRv4},
- // Setup the bridge to allocate containers global IPv6 addresses in the
- // specified subnet.
- {config.FixedCIDRv6 != nil, setupFixedCIDRv6},
- // Setup IPTables.
- {config.EnableIPTables, setupIPTables},
- // Setup IP forwarding.
- {config.EnableIPForwarding, setupIPForwarding},
- // Setup DefaultGatewayIPv4
- {config.DefaultGatewayIPv4 != nil, setupGatewayIPv4},
- // Setup DefaultGatewayIPv6
- {config.DefaultGatewayIPv6 != nil, setupGatewayIPv6},
- } {
- if step.Condition {
- bridgeSetup.queueStep(step.Fn)
- }
- }
- // Block bridge IP from being allocated.
- bridgeSetup.queueStep(allocateBridgeIP)
- // Apply the prepared list of steps, and abort at the first error.
- bridgeSetup.queueStep(setupDeviceUp)
- if err = bridgeSetup.apply(); err != nil {
- return err
- }
- return nil
- }
- func (d *driver) DeleteNetwork(nid types.UUID) error {
- var err error
- // Get network handler and remove it from driver
- d.Lock()
- n := d.network
- d.network = nil
- d.Unlock()
- // On failure set network handler back in driver, but
- // only if is not already taken over by some other thread
- defer func() {
- if err != nil {
- d.Lock()
- if d.network == nil {
- d.network = n
- }
- d.Unlock()
- }
- }()
- // Sanity check
- if n == nil {
- err = driverapi.ErrNoNetwork
- return err
- }
- // Cannot remove network if endpoints are still present
- if len(n.endpoints) != 0 {
- err = ActiveEndpointsError(n.id)
- return err
- }
- // Programming
- err = netlink.LinkDel(n.bridge.Link)
- return err
- }
- func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions map[string]interface{}) (*sandbox.Info, error) {
- var (
- ipv6Addr *net.IPNet
- err error
- )
- // Get the network handler and make sure it exists
- d.Lock()
- n := d.network
- config := d.config
- d.Unlock()
- if n == nil {
- return nil, driverapi.ErrNoNetwork
- }
- // Sanity check
- n.Lock()
- if n.id != nid {
- n.Unlock()
- return nil, InvalidNetworkIDError(nid)
- }
- n.Unlock()
- // Check if endpoint id is good and retrieve correspondent endpoint
- ep, err := n.getEndpoint(eid)
- if err != nil {
- return nil, err
- }
- // Endpoint with that id exists either on desired or other sandbox
- if ep != nil {
- return nil, driverapi.ErrEndpointExists
- }
- // Try to convert the options to endpoint configuration
- epConfig, err := parseEndpointOptions(epOptions)
- if err != nil {
- return nil, err
- }
- // Create and add the endpoint
- n.Lock()
- endpoint := &bridgeEndpoint{id: eid, config: epConfig}
- n.endpoints[eid] = endpoint
- n.Unlock()
- // On failure make sure to remove the endpoint
- defer func() {
- if err != nil {
- n.Lock()
- delete(n.endpoints, eid)
- n.Unlock()
- }
- }()
- // Generate a name for what will be the host side pipe interface
- name1, err := generateIfaceName()
- if err != nil {
- return nil, err
- }
- // Generate a name for what will be the sandbox side pipe interface
- name2, err := generateIfaceName()
- if err != nil {
- return nil, err
- }
- // Generate and add the interface pipe host <-> sandbox
- veth := &netlink.Veth{
- LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
- PeerName: name2}
- if err = netlink.LinkAdd(veth); err != nil {
- return nil, err
- }
- // Get the host side pipe interface handler
- host, err := netlink.LinkByName(name1)
- if err != nil {
- return nil, err
- }
- defer func() {
- if err != nil {
- netlink.LinkDel(host)
- }
- }()
- // Get the sandbox side pipe interface handler
- sbox, err := netlink.LinkByName(name2)
- if err != nil {
- return nil, err
- }
- defer func() {
- if err != nil {
- netlink.LinkDel(sbox)
- }
- }()
- // Set the sbox's MAC. If specified, use the one configured by user, otherwise use a random one
- mac := electMacAddress(epConfig)
- err = netlink.LinkSetHardwareAddr(sbox, mac)
- if err != nil {
- return nil, err
- }
- endpoint.macAddress = mac
- // Add bridge inherited attributes to pipe interfaces
- if config.Mtu != 0 {
- err = netlink.LinkSetMTU(host, config.Mtu)
- if err != nil {
- return nil, err
- }
- err = netlink.LinkSetMTU(sbox, config.Mtu)
- if err != nil {
- return nil, err
- }
- }
- // Attach host side pipe interface into the bridge
- if err = netlink.LinkSetMaster(host,
- &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName}}); err != nil {
- return nil, err
- }
- // v4 address for the sandbox side pipe interface
- ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil)
- if err != nil {
- return nil, err
- }
- ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
- // v6 address for the sandbox side pipe interface
- if config.EnableIPv6 {
- var ip6 net.IP
- network := n.bridge.bridgeIPv6
- if config.FixedCIDRv6 != nil {
- network = config.FixedCIDRv6
- }
- ones, _ := network.Mask.Size()
- if ones <= 80 {
- ip6 = make(net.IP, len(network.IP))
- copy(ip6, network.IP)
- for i, h := range mac {
- ip6[i+10] = h
- }
- }
- ip6, err := ipAllocator.RequestIP(network, ip6)
- if err != nil {
- return nil, err
- }
- ipv6Addr = &net.IPNet{IP: ip6, Mask: network.Mask}
- }
- // Create the sandbox side pipe interface
- intf := &sandbox.Interface{}
- intf.SrcName = name2
- intf.DstName = containerVeth
- intf.Address = ipv4Addr
- // Store the interface in endpoint, this is needed for cleanup on DeleteEndpoint()
- endpoint.intf = intf
- // Generate the sandbox info to return
- sinfo := &sandbox.Info{Interfaces: []*sandbox.Interface{intf}}
- // Set the default gateway(s) for the sandbox
- sinfo.Gateway = n.bridge.gatewayIPv4
- if config.EnableIPv6 {
- intf.AddressIPv6 = ipv6Addr
- sinfo.GatewayIPv6 = n.bridge.gatewayIPv6
- }
- // Program any required port mapping and store them in the endpoint
- endpoint.portMapping, err = allocatePorts(epConfig, sinfo, config.DefaultBindingIP)
- if err != nil {
- return nil, err
- }
- return sinfo, nil
- }
- func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
- var err error
- // Get the network handler and make sure it exists
- d.Lock()
- n := d.network
- config := d.config
- d.Unlock()
- if n == nil {
- return driverapi.ErrNoNetwork
- }
- // Sanity Check
- n.Lock()
- if n.id != nid {
- n.Unlock()
- return InvalidNetworkIDError(nid)
- }
- n.Unlock()
- // Check endpoint id and if an endpoint is actually there
- ep, err := n.getEndpoint(eid)
- if err != nil {
- return err
- }
- if ep == nil {
- return EndpointNotFoundError(eid)
- }
- // Remove it
- n.Lock()
- delete(n.endpoints, eid)
- n.Unlock()
- // On failure make sure to set back ep in n.endpoints, but only
- // if it hasn't been taken over already by some other thread.
- defer func() {
- if err != nil {
- n.Lock()
- if _, ok := n.endpoints[eid]; !ok {
- n.endpoints[eid] = ep
- }
- n.Unlock()
- }
- }()
- // Remove port mappings. Do not stop endpoint delete on unmap failure
- releasePorts(ep)
- // Release the v4 address allocated to this endpoint's sandbox interface
- err = ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, ep.intf.Address.IP)
- if err != nil {
- return err
- }
- // Release the v6 address allocated to this endpoint's sandbox interface
- if config.EnableIPv6 {
- err := ipAllocator.ReleaseIP(n.bridge.bridgeIPv6, ep.intf.AddressIPv6.IP)
- if err != nil {
- return err
- }
- }
- // Try removal of link. Discard error: link pair might have
- // already been deleted by sandbox delete.
- link, err := netlink.LinkByName(ep.intf.SrcName)
- if err == nil {
- netlink.LinkDel(link)
- }
- return nil
- }
- func (d *driver) EndpointInfo(nid, eid types.UUID) (map[string]interface{}, error) {
- // Get the network handler and make sure it exists
- d.Lock()
- n := d.network
- d.Unlock()
- if n == nil {
- return nil, driverapi.ErrNoNetwork
- }
- // Sanity check
- n.Lock()
- if n.id != nid {
- n.Unlock()
- return nil, InvalidNetworkIDError(nid)
- }
- n.Unlock()
- // Check if endpoint id is good and retrieve correspondent endpoint
- ep, err := n.getEndpoint(eid)
- if err != nil {
- return nil, err
- }
- if ep == nil {
- return nil, driverapi.ErrNoEndpoint
- }
- m := make(map[string]interface{})
- if ep.portMapping != nil {
- // Return a copy of the operational data
- pmc := make([]netutils.PortBinding, 0, len(ep.portMapping))
- for _, pm := range ep.portMapping {
- pmc = append(pmc, pm.GetCopy())
- }
- m[netlabel.PortMap] = pmc
- }
- if len(ep.macAddress) != 0 {
- m[netlabel.MacAddress] = ep.macAddress
- }
- return m, nil
- }
- // Join method is invoked when a Sandbox is attached to an endpoint.
- func (d *driver) Join(nid, eid types.UUID, sboxKey string, options map[string]interface{}) (*driverapi.JoinInfo, error) {
- d.Lock()
- config := d.config
- d.Unlock()
- if !config.EnableICC {
- return nil, d.link(nid, eid, options, true)
- }
- return nil, nil
- }
- // Leave method is invoked when a Sandbox detaches from an endpoint.
- func (d *driver) Leave(nid, eid types.UUID, options map[string]interface{}) error {
- d.Lock()
- config := d.config
- d.Unlock()
- if !config.EnableICC {
- return d.link(nid, eid, options, false)
- }
- return nil
- }
- func (d *driver) link(nid, eid types.UUID, options map[string]interface{}, enable bool) error {
- var cc *ContainerConfiguration
- network, err := d.getNetwork(nid)
- if err != nil {
- return err
- }
- endpoint, err := network.getEndpoint(eid)
- if err != nil {
- return err
- }
- if endpoint == nil {
- return EndpointNotFoundError(eid)
- }
- if enable {
- cc, err = parseContainerOptions(options)
- if err != nil {
- return err
- }
- } else {
- cc = endpoint.containerConfig
- }
- if cc == nil {
- return nil
- }
- if endpoint.config != nil && endpoint.config.ExposedPorts != nil {
- for _, p := range cc.ParentEndpoints {
- var parentEndpoint *bridgeEndpoint
- parentEndpoint, err = network.getEndpoint(types.UUID(p))
- if err != nil {
- return err
- }
- if parentEndpoint == nil {
- err = InvalidEndpointIDError(p)
- return err
- }
- d.Lock()
- l := newLink(parentEndpoint.intf.Address.IP.String(),
- endpoint.intf.Address.IP.String(),
- endpoint.config.ExposedPorts, d.config.BridgeName)
- d.Unlock()
- if enable {
- err = l.Enable()
- if err != nil {
- return err
- }
- defer func() {
- if err != nil {
- l.Disable()
- }
- }()
- } else {
- l.Disable()
- }
- }
- }
- for _, c := range cc.ChildEndpoints {
- var childEndpoint *bridgeEndpoint
- childEndpoint, err = network.getEndpoint(types.UUID(c))
- if err != nil {
- return err
- }
- if childEndpoint == nil {
- err = InvalidEndpointIDError(c)
- return err
- }
- if childEndpoint.config == nil || childEndpoint.config.ExposedPorts == nil {
- continue
- }
- d.Lock()
- l := newLink(endpoint.intf.Address.IP.String(),
- childEndpoint.intf.Address.IP.String(),
- childEndpoint.config.ExposedPorts, d.config.BridgeName)
- d.Unlock()
- if enable {
- err = l.Enable()
- if err != nil {
- return err
- }
- defer func() {
- if err != nil {
- l.Disable()
- }
- }()
- } else {
- l.Disable()
- }
- }
- if enable {
- endpoint.containerConfig = cc
- }
- return nil
- }
- func (d *driver) Type() string {
- return networkType
- }
- func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfiguration, error) {
- if epOptions == nil {
- return nil, nil
- }
- ec := &EndpointConfiguration{}
- if opt, ok := epOptions[netlabel.MacAddress]; ok {
- if mac, ok := opt.(net.HardwareAddr); ok {
- ec.MacAddress = mac
- } else {
- return nil, ErrInvalidEndpointConfig
- }
- }
- if opt, ok := epOptions[netlabel.PortMap]; ok {
- if bs, ok := opt.([]netutils.PortBinding); ok {
- ec.PortBindings = bs
- } else {
- return nil, ErrInvalidEndpointConfig
- }
- }
- if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
- if ports, ok := opt.([]netutils.TransportPort); ok {
- ec.ExposedPorts = ports
- } else {
- return nil, ErrInvalidEndpointConfig
- }
- }
- return ec, nil
- }
- func parseContainerOptions(cOptions map[string]interface{}) (*ContainerConfiguration, error) {
- if cOptions == nil {
- return nil, nil
- }
- genericData := cOptions[netlabel.GenericData]
- if genericData == nil {
- return nil, nil
- }
- switch opt := genericData.(type) {
- case options.Generic:
- opaqueConfig, err := options.GenerateFromModel(opt, &ContainerConfiguration{})
- if err != nil {
- return nil, err
- }
- return opaqueConfig.(*ContainerConfiguration), nil
- case *ContainerConfiguration:
- return opt, nil
- default:
- return nil, nil
- }
- }
- func electMacAddress(epConfig *EndpointConfiguration) net.HardwareAddr {
- if epConfig != nil && epConfig.MacAddress != nil {
- return epConfig.MacAddress
- }
- return netutils.GenerateRandomMAC()
- }
- // Generates a name to be used for a virtual ethernet
- // interface. The name is constructed by 'veth' appended
- // by a randomly generated hex value. (example: veth0f60e2c)
- func generateIfaceName() (string, error) {
- for i := 0; i < 3; i++ {
- name, err := netutils.GenerateRandomName(vethPrefix, vethLen)
- if err != nil {
- continue
- }
- if _, err := net.InterfaceByName(name); err != nil {
- if strings.Contains(err.Error(), "no such") {
- return name, nil
- }
- return "", err
- }
- }
- return "", ErrIfaceName
- }
|