Vendoring libnetwork v0.7.0-dev.5

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2016-03-08 18:47:02 -08:00
parent 0771230daa
commit 5a65408941
47 changed files with 1215 additions and 273 deletions

View file

@ -29,14 +29,14 @@ clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de
clone git github.com/imdario/mergo 0.2.1
#get libnetwork packages
clone git github.com/docker/libnetwork v0.7.0-dev.3
clone git github.com/docker/libnetwork v0.7.0-dev.5
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
clone git github.com/hashicorp/serf 7151adcef72687bf95f451a2e0ba15cb19412bf2
clone git github.com/docker/libkv c2aac5dbbaa5c872211edea7c0f32b3bd67e7410
clone git github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
clone git github.com/vishvananda/netlink bfd70f556483c008636b920dda142fdaa0d59ef9
clone git github.com/vishvananda/netlink 631962935bff4f3d20ff32a72e8944f6d2836a26
clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
clone git github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d

View file

@ -1432,7 +1432,7 @@ func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) {
c.Assert(waitRun("second"), check.IsNil)
out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "www.google.com")
c.Assert(err, check.NotNil)
c.Assert(out, checker.Contains, "100% packet loss")
c.Assert(out, checker.Contains, "ping: bad address")
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
c.Assert(err, check.IsNil)
}

View file

@ -1,5 +1,25 @@
# Changelog
## 0.7.0-dev.5 (2016-03-08)
- Fixes https://github.com/docker/docker/issues/20847
- Fixes https://github.com/docker/docker/issues/20997
- Fixes issues unveiled by docker integ test over 0.7.0-dev.4
## 0.7.0-dev.4 (2016-03-07)
- Changed ownership of exposed ports and port-mapping options from Endpoint to Sandbox
- Implement DNS RR in the Docker embedded DNS server
- Fixes https://github.com/docker/libnetwork/issues/984 (multi container overlay veth leak)
- Libnetwork to program container's interface MAC address
- Fixed bug in iptables.Exists() logic
- Fixes https://github.com/docker/docker/issues/20694
- Source external DNS queries from container namespace
- Added inbuilt nil IPAM driver
- Windows drivers integration fixes
- Extract hostname from (hostname.domainname). Related to https://github.com/docker/docker/issues/14282
- Fixed race in sandbox statistics read
- Fixes https://github.com/docker/libnetwork/issues/892 (docker start fails when ipv6.disable=1)
- Fixed error message on bridge network creation conflict
## 0.7.0-dev.3 (2016-02-17)
- Fixes https://github.com/docker/docker/issues/20350
- Fixes https://github.com/docker/docker/issues/20145
@ -90,7 +110,7 @@
- DEPRECATE service discovery from default bridge network
- Introduced new network UX
- Support for multiple networks in bridge driver
- Local persistance with boltdb
- Local persistence with boltdb
## 0.4.0 (2015-07-24)

View file

@ -17,6 +17,7 @@
"mrjana",
"mavenugo",
"sanimej",
"chenchun",
]
[people]
@ -37,6 +38,11 @@
Email = "lk4d4@docker.com"
GitHub = "LK4D4"
[people.chenchun]
Name = "Chun Chen"
Email = "ramichen@tencent.com"
GitHub = "chenchun"
[people.icecrime]
Name = "Arnaud Porterie"
Email = "arnaud@docker.com"

View file

@ -163,7 +163,7 @@ func (s *sequence) toByteArray() ([]byte, error) {
func (s *sequence) fromByteArray(data []byte) error {
l := len(data)
if l%12 != 0 {
return fmt.Errorf("cannot deserialize byte sequence of lenght %d (%v)", l, data)
return fmt.Errorf("cannot deserialize byte sequence of length %d (%v)", l, data)
}
p := s

View file

@ -170,7 +170,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
if c.cfg != nil && c.cfg.Cluster.Watcher != nil {
if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
// Failing to initalize discovery is a bad situation to be in.
// Failing to initialize discovery is a bad situation to be in.
// But it cannot fail creating the Controller
log.Errorf("Failed to Initialize Discovery : %v", err)
}

View file

@ -31,7 +31,7 @@ type DataStore interface {
DeleteObjectAtomic(kvObject KVObject) error
// DeleteTree deletes a record
DeleteTree(kvObject KVObject) error
// Watchable returns whether the store is watchable are not
// Watchable returns whether the store is watchable or not
Watchable() bool
// Watch for changes on a KVObject
Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error)

View file

@ -3,7 +3,6 @@ package libnetwork
import (
"fmt"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/types"
)
@ -28,15 +27,15 @@ var procGwNetwork = make(chan (bool), 1)
- its deleted when an endpoint with GW joins the container
*/
func (sb *sandbox) setupDefaultGW(srcEp *endpoint) error {
var createOptions []EndpointOption
c := srcEp.getNetwork().getController()
func (sb *sandbox) setupDefaultGW() error {
// check if the conitainer already has a GW endpoint
if ep := sb.getEndpointInGWNetwork(); ep != nil {
return nil
}
c := sb.controller
// Look for default gw network. In case of error (includes not found),
// retry and create it if needed in a serialized execution.
n, err := c.NetworkByName(libnGWNetwork)
@ -46,19 +45,7 @@ func (sb *sandbox) setupDefaultGW(srcEp *endpoint) error {
}
}
if opt, ok := srcEp.generic[netlabel.PortMap]; ok {
if pb, ok := opt.([]types.PortBinding); ok {
createOptions = append(createOptions, CreateOptionPortMapping(pb))
}
}
if opt, ok := srcEp.generic[netlabel.ExposedPorts]; ok {
if exp, ok := opt.([]types.TransportPort); ok {
createOptions = append(createOptions, CreateOptionExposedPorts(exp))
}
}
createOptions = append(createOptions, CreateOptionAnonymous())
createOptions := []EndpointOption{CreateOptionAnonymous()}
eplen := gwEPlen
if len(sb.containerID) < gwEPlen {
@ -74,9 +61,13 @@ func (sb *sandbox) setupDefaultGW(srcEp *endpoint) error {
if err := epLocal.sbJoin(sb); err != nil {
return fmt.Errorf("container %s: endpoint join on GW Network failed: %v", sb.containerID, err)
}
return nil
}
// If present, removes the endpoint connecting the sandbox to the default gw network.
// Unless it is the endpoint designated to provide the external connectivity.
// If the sandbox is being deleted, removes the endpoint unconditionally.
func (sb *sandbox) clearDefaultGW() error {
var ep *endpoint
@ -84,6 +75,10 @@ func (sb *sandbox) clearDefaultGW() error {
return nil
}
if ep == sb.getGatewayEndpoint() && !sb.inDelete {
return nil
}
if err := ep.sbLeave(sb, false); err != nil {
return fmt.Errorf("container %s: endpoint leaving GW Network failed: %v", sb.containerID, err)
}
@ -98,7 +93,7 @@ func (sb *sandbox) needDefaultGW() bool {
for _, ep := range sb.getConnectedEndpoints() {
if ep.endpointInGWNetwork() {
continue
return false
}
if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
continue
@ -165,3 +160,16 @@ func (c *controller) defaultGwNetwork() (Network, error) {
}
return n, err
}
// Returns the endpoint which is providing external connectivity to the sandbox
func (sb *sandbox) getGatewayEndpoint() *endpoint {
for _, ep := range sb.getConnectedEndpoints() {
if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
continue
}
if len(ep.Gateway()) != 0 {
return ep
}
}
return nil
}

View file

@ -16,7 +16,7 @@ type DiscoveryType int
const (
// NodeDiscovery represents Node join/leave events provided by discovery
NodeDiscovery = iota + 1
// DatastoreConfig represents a add/remove datastore event
// DatastoreConfig represents an add/remove datastore event
DatastoreConfig
)

View file

@ -42,6 +42,14 @@ type Driver interface {
// Leave method is invoked when a Sandbox detaches from an endpoint.
Leave(nid, eid string) error
// ProgramExternalConnectivity invokes the driver method which does the necessary
// programming to allow the external connectivity dictated by the passed options
ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error
// RevokeExternalConnectivity aks the driver to remove any external connectivity
// programming that was done so far
RevokeExternalConnectivity(nid, eid string) error
// Type returns the the type of this driver, the network type this driver manages
Type() string
}
@ -88,8 +96,8 @@ type JoinInfo interface {
// SetGatewayIPv6 sets the default IPv6 gateway when a container joins the endpoint.
SetGatewayIPv6(net.IP) error
// AddStaticRoute adds a routes to the sandbox.
// It may be used in addtion to or instead of a default gateway (as above).
// AddStaticRoute adds a route to the sandbox.
// It may be used in addition to or instead of a default gateway (as above).
AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error
// DisableGatewayService tells libnetwork not to provide Default GW for the container

View file

@ -64,7 +64,7 @@ func (i *IPAMData) UnmarshalJSON(data []byte) error {
return nil
}
// Validate checks wheter the IPAMData structure contains congruent data
// Validate checks whether the IPAMData structure contains congruent data
func (i *IPAMData) Validate() error {
var isV6 bool
if i.Pool == nil {
@ -93,7 +93,7 @@ func (i *IPAMData) Validate() error {
return nil
}
// IsV6 returns wheter this is an IPv6 IPAMData structure
// IsV6 returns whether this is an IPv6 IPAMData structure
func (i *IPAMData) IsV6() bool {
return nil == i.Pool.IP.To4()
}

View file

@ -9,6 +9,7 @@ import (
"github.com/docker/libnetwork/netlabel"
builtinIpam "github.com/docker/libnetwork/ipams/builtin"
nullIpam "github.com/docker/libnetwork/ipams/null"
remoteIpam "github.com/docker/libnetwork/ipams/remote"
)
@ -73,6 +74,7 @@ func initIpams(ic ipamapi.Callback, lDs, gDs interface{}) error {
for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
builtinIpam.Init,
remoteIpam.Init,
nullIpam.Init,
} {
if err := fn(ic, lDs, gDs); err != nil {
return err

View file

@ -74,9 +74,7 @@ type networkConfiguration struct {
// endpointConfiguration represents the user specified configuration for the sandbox endpoint
type endpointConfiguration struct {
MacAddress net.HardwareAddr
PortBindings []types.PortBinding
ExposedPorts []types.TransportPort
MacAddress net.HardwareAddr
}
// containerConfiguration represents the user specified configuration for a container
@ -85,6 +83,12 @@ type containerConfiguration struct {
ChildEndpoints []string
}
// cnnectivityConfiguration represents the user specified configuration regarding the external connectivity
type connectivityConfiguration struct {
PortBindings []types.PortBinding
ExposedPorts []types.TransportPort
}
type bridgeEndpoint struct {
id string
srcName string
@ -93,6 +97,7 @@ type bridgeEndpoint struct {
macAddress net.HardwareAddr
config *endpointConfiguration // User specified parameters
containerConfig *containerConfiguration
extConnConfig *connectivityConfiguration
portMapping []types.PortBinding // Operation port bindings
}
@ -183,7 +188,7 @@ func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
return fmt.Errorf("same configuration")
}
// Also empty, becasue only one network with empty name is allowed
// Also empty, because only one network with empty name is allowed
if c.BridgeName == o.BridgeName {
return fmt.Errorf("networks have same bridge name")
}
@ -450,7 +455,7 @@ func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error)
func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 {
return types.ForbiddenErrorf("bridge driver doesnt support multiple subnets")
return types.ForbiddenErrorf("bridge driver doesn't support multiple subnets")
}
if len(ipamV4Data) == 0 {
@ -543,6 +548,9 @@ func (d *driver) getNetworks() []*bridgeNetwork {
// Create a new network using bridge plugin
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
return types.BadRequestErrorf("ipv4 pool is empty")
}
// Sanity checks
d.Lock()
if _, ok := d.networks[id]; ok {
@ -581,7 +589,7 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
nw.Unlock()
if err := nwConfig.Conflicts(config); err != nil {
return types.ForbiddenErrorf("cannot create network %s (%s): conflicts with network %s (%s): %s",
nwConfig.BridgeName, config.ID, nw.id, nw.config.BridgeName, err.Error())
config.ID, config.BridgeName, nwConfig.ID, nwConfig.BridgeName, err.Error())
}
}
@ -948,28 +956,19 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
}
}
// Create the sandbox side pipe interface
// Store the sandbox side pipe interface parameters
endpoint.srcName = containerIfName
endpoint.macAddress = ifInfo.MacAddress()
endpoint.addr = ifInfo.Address()
endpoint.addrv6 = ifInfo.AddressIPv6()
// Down the interface before configuring mac address.
if err = netlink.LinkSetDown(sbox); err != nil {
return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err)
}
// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
// Set the sbox's MAC if not provided. If specified, use the one configured by user, otherwise generate one based on IP.
if endpoint.macAddress == nil {
endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
if err = ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
return err
}
}
err = netlink.LinkSetHardwareAddr(sbox, endpoint.macAddress)
if err != nil {
return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
}
// Up the host interface after finishing all netlink configuration
if err = netlink.LinkSetUp(host); err != nil {
@ -996,17 +995,11 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
}
endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
if err := ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
return err
}
}
// Program any required port mapping and store them in the endpoint
endpoint.portMapping, err = n.allocatePorts(epConfig, endpoint, config.DefaultBindingIP, d.config.EnableUserlandProxy)
if err != nil {
return err
}
return nil
}
@ -1061,9 +1054,6 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
}
}()
// Remove port mappings. Do not stop endpoint delete on unmap failure
n.releasePorts(ep)
// Try removal of link. Discard error: it is a best effort.
// Also make sure defer does not see this error either.
if link, err := netlink.LinkByName(ep.srcName); err == nil {
@ -1104,10 +1094,10 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro
m := make(map[string]interface{})
if ep.config.ExposedPorts != nil {
if ep.extConnConfig != nil && ep.extConnConfig.ExposedPorts != nil {
// Return a copy of the config data
epc := make([]types.TransportPort, 0, len(ep.config.ExposedPorts))
for _, tp := range ep.config.ExposedPorts {
epc := make([]types.TransportPort, 0, len(ep.extConnConfig.ExposedPorts))
for _, tp := range ep.extConnConfig.ExposedPorts {
epc = append(epc, tp.GetCopy())
}
m[netlabel.ExposedPorts] = epc
@ -1147,6 +1137,11 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return EndpointNotFoundError(eid)
}
endpoint.containerConfig, err = parseContainerOptions(options)
if err != nil {
return err
}
iNames := jinfo.InterfaceName()
err = iNames.SetNames(endpoint.srcName, containerVethPrefix)
if err != nil {
@ -1163,10 +1158,6 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return err
}
if !network.config.EnableICC {
return d.link(network, endpoint, options, true)
}
return nil
}
@ -1189,32 +1180,87 @@ func (d *driver) Leave(nid, eid string) error {
}
if !network.config.EnableICC {
return d.link(network, endpoint, nil, false)
if err = d.link(network, endpoint, false); err != nil {
return err
}
}
return nil
}
func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options map[string]interface{}, enable bool) error {
var (
cc *containerConfiguration
err error
)
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
defer osl.InitOSContext()()
if enable {
cc, err = parseContainerOptions(options)
if err != nil {
return err
}
} else {
cc = endpoint.containerConfig
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)
}
endpoint.extConnConfig, err = parseConnectivityOptions(options)
if err != nil {
return err
}
// Program any required port mapping and store them in the endpoint
endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIP, d.config.EnableUserlandProxy)
if err != nil {
return err
}
if !network.config.EnableICC {
return d.link(network, endpoint, true)
}
return nil
}
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
defer osl.InitOSContext()()
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)
}
err = network.releasePorts(endpoint)
if err != nil {
logrus.Warn(err)
}
return nil
}
func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, enable bool) error {
var err error
cc := endpoint.containerConfig
if cc == nil {
return nil
}
ec := endpoint.extConnConfig
if ec == nil {
return nil
}
if endpoint.config != nil && endpoint.config.ExposedPorts != nil {
if ec.ExposedPorts != nil {
for _, p := range cc.ParentEndpoints {
var parentEndpoint *bridgeEndpoint
parentEndpoint, err = network.getEndpoint(p)
@ -1228,7 +1274,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
l := newLink(parentEndpoint.addr.IP.String(),
endpoint.addr.IP.String(),
endpoint.config.ExposedPorts, network.config.BridgeName)
ec.ExposedPorts, network.config.BridgeName)
if enable {
err = l.Enable()
if err != nil {
@ -1255,13 +1301,13 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
err = InvalidEndpointIDError(c)
return err
}
if childEndpoint.config == nil || childEndpoint.config.ExposedPorts == nil {
if childEndpoint.extConnConfig == nil || childEndpoint.extConnConfig.ExposedPorts == nil {
continue
}
l := newLink(endpoint.addr.IP.String(),
childEndpoint.addr.IP.String(),
childEndpoint.config.ExposedPorts, network.config.BridgeName)
childEndpoint.extConnConfig.ExposedPorts, network.config.BridgeName)
if enable {
err = l.Enable()
if err != nil {
@ -1277,10 +1323,6 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
}
}
if enable {
endpoint.containerConfig = cc
}
return nil
}
@ -1313,22 +1355,6 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfigurat
}
}
if opt, ok := epOptions[netlabel.PortMap]; ok {
if bs, ok := opt.([]types.PortBinding); ok {
ec.PortBindings = bs
} else {
return nil, &ErrInvalidEndpointConfig{}
}
}
if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
if ports, ok := opt.([]types.TransportPort); ok {
ec.ExposedPorts = ports
} else {
return nil, &ErrInvalidEndpointConfig{}
}
}
return ec, nil
}
@ -1354,6 +1380,32 @@ func parseContainerOptions(cOptions map[string]interface{}) (*containerConfigura
}
}
func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) {
if cOptions == nil {
return nil, nil
}
cc := &connectivityConfiguration{}
if opt, ok := cOptions[netlabel.PortMap]; ok {
if pb, ok := opt.([]types.PortBinding); ok {
cc.PortBindings = pb
} else {
return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt)
}
}
if opt, ok := cOptions[netlabel.ExposedPorts]; ok {
if ports, ok := opt.([]types.TransportPort); ok {
cc.ExposedPorts = ports
} else {
return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt)
}
}
return cc, nil
}
func electMacAddress(epConfig *endpointConfiguration, ip net.IP) net.HardwareAddr {
if epConfig != nil && epConfig.MacAddress != nil {
return epConfig.MacAddress

View file

@ -14,8 +14,8 @@ var (
defaultBindingIP = net.IPv4(0, 0, 0, 0)
)
func (n *bridgeNetwork) allocatePorts(epConfig *endpointConfiguration, ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
if epConfig == nil || epConfig.PortBindings == nil {
func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
return nil, nil
}
@ -24,7 +24,7 @@ func (n *bridgeNetwork) allocatePorts(epConfig *endpointConfiguration, ep *bridg
defHostIP = reqDefBindIP
}
return n.allocatePortsInternal(epConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
return n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
}
func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {

View file

@ -63,6 +63,14 @@ func (d *driver) Leave(nid, eid string) error {
return nil
}
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
return nil
}
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
return nil
}
func (d *driver) Type() string {
return networkType
}

View file

@ -63,6 +63,14 @@ func (d *driver) Leave(nid, eid string) error {
return nil
}
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
return nil
}
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
return nil
}
func (d *driver) Type() string {
return networkType
}

View file

@ -78,7 +78,7 @@ func setFilters(cname, brName string, remove bool) error {
opt = "-D"
}
// Everytime we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
// Every time we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
if !remove {
for _, chain := range []string{"OUTPUT", "FORWARD"} {
exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain)

View file

@ -54,7 +54,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return err
}
ep.ifName = overlayIfName
ep.ifName = containerIfName
// Set the container interface and its peer MTU to 1450 to allow
// for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) +

View file

@ -63,6 +63,9 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
if id == "" {
return fmt.Errorf("invalid network id")
}
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
return types.BadRequestErrorf("ipv4 pool is empty")
}
// Since we perform lazy configuration make sure we try
// configuring the driver when we enter CreateNetwork
@ -111,6 +114,14 @@ func (d *driver) DeleteNetwork(nid string) error {
return n.releaseVxlanID()
}
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
return nil
}
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
return nil
}
func (n *network) incEndpointCount() {
n.Lock()
defer n.Unlock()

View file

@ -153,6 +153,29 @@ type LeaveResponse struct {
Response
}
// ProgramExternalConnectivityRequest describes the API for programming the external connectivity for the given endpoint.
type ProgramExternalConnectivityRequest struct {
NetworkID string
EndpointID string
Options map[string]interface{}
}
// ProgramExternalConnectivityResponse is the answer to ProgramExternalConnectivityRequest.
type ProgramExternalConnectivityResponse struct {
Response
}
// RevokeExternalConnectivityRequest describes the API for revoking the external connectivity for the given endpoint.
type RevokeExternalConnectivityRequest struct {
NetworkID string
EndpointID string
}
// RevokeExternalConnectivityResponse is the answer to RevokeExternalConnectivityRequest.
type RevokeExternalConnectivityResponse struct {
Response
}
// DiscoveryNotification represents a discovery notification
type DiscoveryNotification struct {
DiscoveryType discoverapi.DiscoveryType

View file

@ -3,6 +3,7 @@ package remote
import (
"fmt"
"net"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/plugins"
@ -13,6 +14,10 @@ import (
"github.com/docker/libnetwork/types"
)
const (
missingMethod = "404 page not found"
)
type driver struct {
endpoint *plugins.Client
networkType string
@ -247,6 +252,35 @@ func (d *driver) Leave(nid, eid string) error {
return d.call("Leave", leave, &api.LeaveResponse{})
}
// ProgramExternalConnectivity is invoked to program the rules to allow external connectivity for the endpoint.
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
data := &api.ProgramExternalConnectivityRequest{
NetworkID: nid,
EndpointID: eid,
Options: options,
}
err := d.call("ProgramExternalConnectivity", data, &api.ProgramExternalConnectivityResponse{})
if err != nil && strings.Contains(err.Error(), missingMethod) {
// It is not mandatory yet to support this method
return nil
}
return err
}
// RevokeExternalConnectivity method is invoked to remove any external connectivity programming related to the endpoint.
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
data := &api.RevokeExternalConnectivityRequest{
NetworkID: nid,
EndpointID: eid,
}
err := d.call("RevokeExternalConnectivity", data, &api.RevokeExternalConnectivityResponse{})
if err != nil && strings.Contains(err.Error(), missingMethod) {
// It is not mandatory yet to support this method
return nil
}
return err
}
func (d *driver) Type() string {
return d.networkType
}

View file

@ -36,11 +36,20 @@ type networkConfiguration struct {
RDID string
}
// endpointConfiguration represents the user specified configuration for the sandbox endpoint
type endpointConfiguration struct {
MacAddress net.HardwareAddr
PortBindings []types.PortBinding
ExposedPorts []types.TransportPort
}
type hnsEndpoint struct {
id string
profileID string
macAddress net.HardwareAddr
addr *net.IPNet
id string
profileID string
macAddress net.HardwareAddr
config *endpointConfiguration // User specified parameters
portMapping []types.PortBinding // Operation port bindings
addr *net.IPNet
}
type hnsNetwork struct {
@ -58,7 +67,7 @@ type driver struct {
}
func isValidNetworkType(networkType string) bool {
if "L2Bridge" == networkType || "L2Tunnel" == networkType || "NAT" == networkType || "Transparent" == networkType {
if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "transparent" == networkType {
return true
}
@ -126,7 +135,7 @@ func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string
func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
if len(ipamV6Data) > 0 {
return types.ForbiddenErrorf("windowsshim driver doesnt support v6 subnets")
return types.ForbiddenErrorf("windowsshim driver doesn't support v6 subnets")
}
if len(ipamV4Data) == 0 {
@ -177,8 +186,11 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
for _, ipData := range ipV4Data {
subnet := hcsshim.Subnet{
AddressPrefix: ipData.Pool.String(),
GatewayAddress: ipData.Gateway.IP.String(),
AddressPrefix: ipData.Pool.String(),
}
if ipData.Gateway != nil {
subnet.GatewayAddress = ipData.Gateway.IP.String()
}
subnets = append(subnets, subnet)
@ -276,6 +288,64 @@ func convertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, e
return pbs, nil
}
func parsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) {
var bindings []types.PortBinding
hcsPolicy := &hcsshim.NatPolicy{}
for _, elem := range policies {
if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" {
continue
}
binding := types.PortBinding{
HostPort: hcsPolicy.ExternalPort,
HostPortEnd: hcsPolicy.ExternalPort,
Port: hcsPolicy.InternalPort,
Proto: types.ParseProtocol(hcsPolicy.Protocol),
HostIP: net.IPv4(0, 0, 0, 0),
}
bindings = append(bindings, binding)
}
return bindings, nil
}
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, fmt.Errorf("Invalid endpoint configuration")
}
}
if opt, ok := epOptions[netlabel.PortMap]; ok {
if bs, ok := opt.([]types.PortBinding); ok {
ec.PortBindings = bs
} else {
return nil, fmt.Errorf("Invalid endpoint configuration")
}
}
if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
if ports, ok := opt.([]types.TransportPort); ok {
ec.ExposedPorts = ports
} else {
return nil, fmt.Errorf("Invalid endpoint configuration")
}
}
return ec, nil
}
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
n, err := d.getNetwork(nid)
if err != nil {
@ -292,16 +362,16 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
VirtualNetwork: n.config.HnsID,
}
// Convert the port mapping for the network
if opt, ok := epOptions[netlabel.PortMap]; ok {
if bs, ok := opt.([]types.PortBinding); ok {
endpointStruct.Policies, err = convertPortBindings(bs)
if err != nil {
return err
}
} else {
return fmt.Errorf("Invalid endpoint configuration for endpoint id%s", eid)
}
ec, err := parseEndpointOptions(epOptions)
if err != nil {
return err
}
endpointStruct.Policies, err = convertPortBindings(ec.PortBindings)
if err != nil {
return err
}
configurationb, err := json.Marshal(endpointStruct)
@ -325,7 +395,16 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
addr: &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
macAddress: mac,
}
endpoint.profileID = hnsresponse.Id
endpoint.config = ec
endpoint.portMapping, err = parsePortBindingPolicies(hnsresponse.Policies)
if err != nil {
hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "")
return err
}
n.Lock()
n.endpoints[eid] = endpoint
n.Unlock()
@ -365,13 +444,34 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro
return nil, err
}
endpoint, err := network.getEndpoint(eid)
ep, err := network.getEndpoint(eid)
if err != nil {
return nil, err
}
data := make(map[string]interface{}, 1)
data["hnsid"] = endpoint.profileID
data["hnsid"] = ep.profileID
if ep.config.ExposedPorts != nil {
// Return a copy of the config data
epc := make([]types.TransportPort, 0, len(ep.config.ExposedPorts))
for _, tp := range ep.config.ExposedPorts {
epc = append(epc, tp.GetCopy())
}
data[netlabel.ExposedPorts] = epc
}
if ep.portMapping != nil {
// Return a copy of the operational data
pmc := make([]types.PortBinding, 0, len(ep.portMapping))
for _, pm := range ep.portMapping {
pmc = append(pmc, pm.GetCopy())
}
data[netlabel.PortMap] = pmc
}
if len(ep.macAddress) != 0 {
data[netlabel.MacAddress] = ep.macAddress
}
return data, nil
}
@ -412,6 +512,14 @@ func (d *driver) Leave(nid, eid string) error {
return nil
}
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
return nil
}
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
return nil
}
func (d *driver) Type() string {
return d.name
}

View file

@ -8,9 +8,9 @@ import (
func getInitializers() []initializer {
return []initializer{
{null.Init, "null"},
{windows.GetInit("Transparent"), "Transparent"},
{windows.GetInit("L2Bridge"), "L2Bridge"},
{windows.GetInit("L2Tunnel"), "L2Tunnel"},
{windows.GetInit("NAT"), "NAT"},
{windows.GetInit("transparent"), "transparent"},
{windows.GetInit("l2bridge"), "l2bridge"},
{windows.GetInit("l2tunnel"), "l2tunnel"},
{windows.GetInit("nat"), "nat"},
}
}

View file

@ -359,22 +359,16 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
sb.joinLeaveStart()
defer sb.joinLeaveEnd()
return ep.sbJoin(sbox, options...)
return ep.sbJoin(sb, options...)
}
func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
var err error
sb, ok := sbox.(*sandbox)
if !ok {
return types.BadRequestErrorf("not a valid Sandbox interface")
}
network, err := ep.getNetworkFromStore()
func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
n, err := ep.getNetworkFromStore()
if err != nil {
return fmt.Errorf("failed to get network from store during join: %v", err)
}
ep, err = network.getEndpointFromStore(ep.ID())
ep, err = n.getEndpointFromStore(ep.ID())
if err != nil {
return fmt.Errorf("failed to get endpoint from store during join: %v", err)
}
@ -384,11 +378,8 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
ep.Unlock()
return types.ForbiddenErrorf("another container is attached to the same network endpoint")
}
ep.Unlock()
ep.Lock()
ep.network = network
ep.sandboxID = sbox.ID()
ep.network = n
ep.sandboxID = sb.ID()
ep.joinInfo = &endpointJoinInfo{}
epid := ep.id
ep.Unlock()
@ -400,32 +391,29 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
}
}()
network.Lock()
nid := network.id
network.Unlock()
nid := n.ID()
ep.processOptions(options...)
driver, err := network.driver(true)
d, err := n.driver(true)
if err != nil {
return fmt.Errorf("failed to join endpoint: %v", err)
}
err = driver.Join(nid, epid, sbox.Key(), ep, sbox.Labels())
err = d.Join(nid, epid, sb.Key(), ep, sb.Labels())
if err != nil {
return err
}
defer func() {
if err != nil {
// Do not alter global err variable, it's needed by the previous defer
if err := driver.Leave(nid, epid); err != nil {
if err := d.Leave(nid, epid); err != nil {
log.Warnf("driver leave failed while rolling back join: %v", err)
}
}
}()
// Watch for service records
network.getController().watchSvcRecord(ep)
n.getController().watchSvcRecord(ep)
address := ""
if ip := ep.getFirstInterfaceAddress(); ip != nil {
@ -434,27 +422,23 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
if err = sb.updateHostsFile(address); err != nil {
return err
}
if err = sb.updateDNS(network.enableIPv6); err != nil {
if err = sb.updateDNS(n.enableIPv6); err != nil {
return err
}
if err = network.getController().updateToStore(ep); err != nil {
if err = n.getController().updateToStore(ep); err != nil {
return err
}
// Current endpoint providing external connectivity for the sandbox
extEp := sb.getGatewayEndpoint()
sb.Lock()
heap.Push(&sb.endpoints, ep)
sb.Unlock()
defer func() {
if err != nil {
for i, e := range sb.getConnectedEndpoints() {
if e == ep {
sb.Lock()
heap.Remove(&sb.endpoints, i)
sb.Unlock()
return
}
}
sb.removeEndpoint(ep)
}
}()
@ -463,9 +447,39 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
}
if sb.needDefaultGW() {
return sb.setupDefaultGW(ep)
return sb.setupDefaultGW()
}
return nil
moveExtConn := sb.getGatewayEndpoint() != extEp
if moveExtConn {
if extEp != nil {
log.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
if err = d.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil {
return types.InternalErrorf(
"driver failed revoking external connectivity on endpoint %s (%s): %v",
extEp.Name(), extEp.ID(), err)
}
defer func() {
if err != nil {
if e := d.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil {
log.Warnf("Failed to roll-back external connectivity on endpoint %s (%s): %v",
extEp.Name(), extEp.ID(), e)
}
}
}()
}
if !n.internal {
log.Debugf("Programming external connectivity on endpoint %s (%s)", ep.Name(), ep.ID())
if err = d.ProgramExternalConnectivity(n.ID(), ep.ID(), sb.Labels()); err != nil {
return types.InternalErrorf(
"driver failed programming external connectivity on endpoint %s (%s): %v",
ep.Name(), ep.ID(), err)
}
}
}
return sb.clearDefaultGW()
}
func (ep *endpoint) rename(name string) error {
@ -533,15 +547,10 @@ func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
sb.joinLeaveStart()
defer sb.joinLeaveEnd()
return ep.sbLeave(sbox, false, options...)
return ep.sbLeave(sb, false, options...)
}
func (ep *endpoint) sbLeave(sbox Sandbox, force bool, options ...EndpointOption) error {
sb, ok := sbox.(*sandbox)
if !ok {
return types.BadRequestErrorf("not a valid Sandbox interface")
}
func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) error {
n, err := ep.getNetworkFromStore()
if err != nil {
return fmt.Errorf("failed to get network from store during leave: %v", err)
@ -559,8 +568,8 @@ func (ep *endpoint) sbLeave(sbox Sandbox, force bool, options ...EndpointOption)
if sid == "" {
return types.ForbiddenErrorf("cannot leave endpoint with no attached sandbox")
}
if sid != sbox.ID() {
return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sbox.ID())
if sid != sb.ID() {
return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sb.ID())
}
ep.processOptions(options...)
@ -575,7 +584,19 @@ func (ep *endpoint) sbLeave(sbox Sandbox, force bool, options ...EndpointOption)
ep.network = n
ep.Unlock()
// Current endpoint providing external connectivity to the sandbox
extEp := sb.getGatewayEndpoint()
moveExtConn := extEp != nil && (extEp.ID() == ep.ID())
if d != nil {
if moveExtConn {
log.Debugf("Revoking external connectivity on endpoint %s (%s)", ep.Name(), ep.ID())
if err := d.RevokeExternalConnectivity(n.id, ep.id); err != nil {
log.Warnf("driver failed revoking external connectivity on endpoint %s (%s): %v",
ep.Name(), ep.ID(), err)
}
}
if err := d.Leave(n.id, ep.id); err != nil {
if _, ok := err.(types.MaskableError); !ok {
log.Warnf("driver error disconnecting container %s : %v", ep.name, err)
@ -597,7 +618,24 @@ func (ep *endpoint) sbLeave(sbox Sandbox, force bool, options ...EndpointOption)
}
sb.deleteHostsEntries(n.getSvcRecords(ep))
return nil
if !sb.inDelete && sb.needDefaultGW() {
if sb.getEPwithoutGateway() == nil {
return fmt.Errorf("endpoint without GW expected, but not found")
}
return sb.setupDefaultGW()
}
// New endpoint providing external connectivity for the sandbox
extEp = sb.getGatewayEndpoint()
if moveExtConn && extEp != nil {
log.Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
if err := d.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil {
log.Warnf("driver failed programming external connectivity on endpoint %s: (%s) %v",
extEp.Name(), extEp.ID(), err)
}
}
return sb.clearDefaultGW()
}
func (n *network) validateForceDelete(locator string) error {
@ -643,7 +681,7 @@ func (ep *endpoint) Delete(force bool) error {
}
if sb != nil {
if e := ep.sbLeave(sb, force); e != nil {
if e := ep.sbLeave(sb.(*sandbox), force); e != nil {
log.Warnf("failed to leave sandbox for endpoint %s : %v", name, e)
}
}
@ -929,9 +967,13 @@ func (ep *endpoint) releaseAddress() {
log.Warnf("Failed to retrieve ipam driver to release interface address on delete of endpoint %s (%s): %v", ep.Name(), ep.ID(), err)
return
}
if err := ipam.ReleaseAddress(ep.iface.v4PoolID, ep.iface.addr.IP); err != nil {
log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addr.IP, ep.Name(), ep.ID(), err)
if ep.iface.addr != nil {
if err := ipam.ReleaseAddress(ep.iface.v4PoolID, ep.iface.addr.IP); err != nil {
log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addr.IP, ep.Name(), ep.ID(), err)
}
}
if ep.iface.addrv6 != nil && ep.iface.addrv6.IP.IsGlobalUnicast() {
if err := ipam.ReleaseAddress(ep.iface.v6PoolID, ep.iface.addrv6.IP); err != nil {
log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addrv6.IP, ep.Name(), ep.ID(), err)

View file

@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"regexp"
"strings"
"sync"
)
@ -78,10 +79,17 @@ func Build(path, IP, hostname, domainname string, extraContent []Record) error {
//set main record
var mainRec Record
mainRec.IP = IP
// User might have provided a FQDN in hostname or split it across hostname
// and domainname. We want the FQDN and the bare hostname.
fqdn := hostname
if domainname != "" {
mainRec.Hosts = fmt.Sprintf("%s.%s %s", hostname, domainname, hostname)
fqdn = fmt.Sprintf("%s.%s", fqdn, domainname)
}
parts := strings.SplitN(fqdn, ".", 2)
if len(parts) == 2 {
mainRec.Hosts = fmt.Sprintf("%s %s", fqdn, parts[0])
} else {
mainRec.Hosts = hostname
mainRec.Hosts = fqdn
}
if _, err := mainRec.WriteTo(content); err != nil {
return err
@ -151,6 +159,10 @@ func Delete(path string, recs []Record) error {
loop:
for s.Scan() {
b := s.Bytes()
if len(b) == 0 {
continue
}
if b[0] == '#' {
buf.Write(b)
buf.Write(eol)

View file

@ -8,7 +8,7 @@ import (
"github.com/docker/libnetwork/datastore"
)
// Idm manages the reservation/release of numerical ids from a contiguos set
// Idm manages the reservation/release of numerical ids from a contiguous set
type Idm struct {
start uint64
end uint64

View file

@ -40,7 +40,7 @@ type addrSpace struct {
}
// AddressRange specifies first and last ip ordinal which
// identify a range in a a pool of addresses
// identifies a range in a pool of addresses
type AddressRange struct {
Sub *net.IPNet
Start, End uint64
@ -85,7 +85,7 @@ func (s *SubnetKey) String() string {
return k
}
// FromString populate the SubnetKey object reading it from string
// FromString populates the SubnetKey object reading it from string
func (s *SubnetKey) FromString(str string) error {
if str == "" || !strings.Contains(str, "/") {
return types.BadRequestErrorf("invalid string form for subnetkey: %s", str)

View file

@ -62,7 +62,7 @@ func getAddressVersion(ip net.IP) ipVersion {
}
// Adds the ordinal IP to the current array
// 192.168.0.0 + 53 => 192.168.53
// 192.168.0.0 + 53 => 192.168.0.53
func addIntToIP(array []byte, ordinal uint64) {
for i := len(array) - 1; i >= 0; i-- {
array[i] |= (byte)(ordinal & 0xff)

View file

@ -15,6 +15,8 @@ import (
const (
// DefaultIPAM is the name of the built-in default ipam driver
DefaultIPAM = "default"
// NullIPAM is the name of the built-in null ipam driver
NullIPAM = "null"
// PluginEndpointType represents the Endpoint Type used by Plugin system
PluginEndpointType = "IpamDriver"
// RequestAddressType represents the Address Type used when requesting an address
@ -33,7 +35,7 @@ type Callback interface {
* IPAM Errors
**************/
// Weel-known errors returned by IPAM
// Well-known errors returned by IPAM
var (
ErrIpamInternalError = types.InternalErrorf("IPAM Internal Error")
ErrInvalidAddressSpace = types.BadRequestErrorf("Invalid Address Space")

View file

@ -0,0 +1,71 @@
// Package null implements the null ipam driver. Null ipam driver satisfies ipamapi contract,
// but does not effectively reserve/allocate any address pool or address
package null
import (
"fmt"
"net"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/ipamapi"
"github.com/docker/libnetwork/types"
)
var (
defaultAS = "null"
defaultPool, _ = types.ParseCIDR("0.0.0.0/0")
defaultPoolID = fmt.Sprintf("%s/%s", defaultAS, defaultPool.String())
)
type allocator struct{}
func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
return defaultAS, defaultAS, nil
}
func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
if addressSpace != defaultAS {
return "", nil, nil, types.BadRequestErrorf("unknown address space: %s", addressSpace)
}
if pool != "" {
return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle specific address pool requests")
}
if subPool != "" {
return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle specific address subpool requests")
}
if v6 {
return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle IPv6 address pool pool requests")
}
return defaultPoolID, defaultPool, nil, nil
}
func (a *allocator) ReleasePool(poolID string) error {
return nil
}
func (a *allocator) RequestAddress(poolID string, ip net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
if poolID != defaultPoolID {
return nil, nil, types.BadRequestErrorf("unknown pool id: %s", poolID)
}
return nil, nil, nil
}
func (a *allocator) ReleaseAddress(poolID string, ip net.IP) error {
if poolID != defaultPoolID {
return types.BadRequestErrorf("unknown pool id: %s", poolID)
}
return nil
}
func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}
func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}
// Init registers a remote ipam when its plugin is activated
func Init(ic ipamapi.Callback, l, g interface{}) error {
return ic.RegisterIpamDriver(ipamapi.NullIPAM, &allocator{})
}

View file

@ -6,6 +6,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/discoverapi"
"github.com/docker/libnetwork/ipamapi"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/types"
)
@ -33,7 +34,7 @@ func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
}
// RequestPool returns an address pool along with its unique id. This is a null ipam driver. It allocates the
// subnet user asked and does not validate anything. Doesnt support subpool allocation
// subnet user asked and does not validate anything. Doesn't support subpool allocation
func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
if subPool != "" || v6 {
@ -64,14 +65,19 @@ func (a *allocator) ReleasePool(poolID string) error {
// RequestAddress returns an address from the specified pool ID.
// Always allocate the 0.0.0.0/32 ip if no preferred address was specified
func (a *allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
log.Debugf("RequestAddress(%s, %v, %v) %s", poolID, prefAddress, opts, opts["RequestAddressType"])
log.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts)
_, ipNet, err := net.ParseCIDR(poolID)
if err != nil {
return nil, nil, err
}
if prefAddress == nil {
// TODO Windows: Remove this once the bug in docker daemon is fixed
// that causes it to throw an exception on nil gateway
if opts[ipamapi.RequestAddressType] == netlabel.Gateway {
return ipNet, nil, nil
} else if prefAddress == nil {
return nil, nil, nil
}
return &net.IPNet{IP: prefAddress, Mask: ipNet.Mask}, nil, nil
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
"net"
"os/exec"
"regexp"
"strconv"
"strings"
"sync"
@ -36,6 +37,7 @@ const (
var (
iptablesPath string
supportsXlock = false
supportsCOpt = false
// used to lock iptables commands if xtables lock is not supported
bestEffortLock sync.Mutex
// ErrIptablesNotFound is returned when the rule is not found.
@ -60,7 +62,6 @@ func (e ChainError) Error() string {
}
func initCheck() error {
if iptablesPath == "" {
path, err := exec.LookPath("iptables")
if err != nil {
@ -68,6 +69,12 @@ func initCheck() error {
}
iptablesPath = path
supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
mj, mn, mc, err := GetVersion()
if err != nil {
logrus.Warnf("Failed to read iptables version: %v", err)
return nil
}
supportsCOpt = supportsCOption(mj, mn, mc)
}
return nil
}
@ -299,20 +306,21 @@ func Exists(table Table, chain string, rule ...string) bool {
table = Filter
}
// iptables -C, --check option was added in v.1.4.11
// http://ftp.netfilter.org/pub/iptables/changes-iptables-1.4.11.txt
initCheck()
// try -C
// if exit status is 0 then return true, the rule exists
if _, err := Raw(append([]string{
"-t", string(table), "-C", chain}, rule...)...); err == nil {
return true
if supportsCOpt {
// if exit status is 0 then return true, the rule exists
_, err := Raw(append([]string{"-t", string(table), "-C", chain}, rule...)...)
return err == nil
}
// parse "iptables -S" for the rule (this checks rules in a specific chain
// in a specific table)
ruleString := strings.Join(rule, " ")
ruleString = chain + " " + ruleString
// parse "iptables -S" for the rule (it checks rules in a specific chain
// in a specific table and it is very unreliable)
return existsRaw(table, chain, rule...)
}
func existsRaw(table Table, chain string, rule ...string) bool {
ruleString := fmt.Sprintf("%s %s\n", chain, strings.Join(rule, " "))
existingRules, _ := exec.Command(iptablesPath, "-t", string(table), "-S", chain).Output()
return strings.Contains(string(existingRules), ruleString)
@ -380,3 +388,25 @@ func ExistChain(chain string, table Table) bool {
}
return false
}
// GetVersion reads the iptables version numbers
func GetVersion() (major, minor, micro int, err error) {
out, err := Raw("--version")
if err == nil {
major, minor, micro = parseVersionNumbers(string(out))
}
return
}
func parseVersionNumbers(input string) (major, minor, micro int) {
re := regexp.MustCompile(`v\d*.\d*.\d*`)
line := re.FindString(input)
fmt.Sscanf(line, "v%d.%d.%d", &major, &minor, &micro)
return
}
// iptables -C, --check option was added in v.1.4.11
// http://ftp.netfilter.org/pub/iptables/changes-iptables-1.4.11.txt
func supportsCOption(mj, mn, mc int) bool {
return mj > 1 || (mj == 1 && (mn > 4 || (mn == 4 && mc >= 11)))
}

View file

@ -600,7 +600,7 @@ func (n *network) driver(load bool) (driverapi.Driver, error) {
return nil, err
}
} else if !ok {
// dont fail if driver loading is not required
// don't fail if driver loading is not required
return nil, nil
}
@ -851,14 +851,25 @@ func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool
if iface := ep.Iface(); iface.Address() != nil {
myAliases := ep.MyAliases()
if isAdd {
if !ep.isAnonymous() {
// If anonymous endpoint has an alias use the first alias
// for ip->name mapping. Not having the reverse mapping
// breaks some apps
if ep.isAnonymous() {
if len(myAliases) > 0 {
n.addSvcRecords(myAliases[0], iface.Address().IP, true)
}
} else {
n.addSvcRecords(epName, iface.Address().IP, true)
}
for _, alias := range myAliases {
n.addSvcRecords(alias, iface.Address().IP, false)
}
} else {
if !ep.isAnonymous() {
if ep.isAnonymous() {
if len(myAliases) > 0 {
n.deleteSvcRecords(myAliases[0], iface.Address().IP, true)
}
} else {
n.deleteSvcRecords(epName, iface.Address().IP, true)
}
for _, alias := range myAliases {

View file

@ -21,6 +21,7 @@ type nwIface struct {
dstName string
master string
dstMaster string
mac net.HardwareAddr
address *net.IPNet
addressIPv6 *net.IPNet
routes []*net.IPNet
@ -64,6 +65,13 @@ func (i *nwIface) Master() string {
return i.master
}
func (i *nwIface) MacAddress() net.HardwareAddr {
i.Lock()
defer i.Unlock()
return types.GetMacCopy(i.mac)
}
func (i *nwIface) Address() *net.IPNet {
i.Lock()
defer i.Unlock()
@ -304,6 +312,7 @@ func configureInterface(iface netlink.Link, i *nwIface) error {
ErrMessage string
}{
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())},
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, i.Address())},
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, i.AddressIPv6())},
{setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())},
@ -326,6 +335,13 @@ func setInterfaceMaster(iface netlink.Link, i *nwIface) error {
LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
}
func setInterfaceMAC(iface netlink.Link, i *nwIface) error {
if i.MacAddress() == nil {
return nil
}
return netlink.LinkSetHardwareAddr(iface, i.MacAddress())
}
func setInterfaceIP(iface netlink.Link, i *nwIface) error {
if i.Address() == nil {
return nil

View file

@ -42,6 +42,12 @@ func (n *networkNamespace) Master(name string) IfaceOption {
}
}
func (n *networkNamespace) MacAddress(mac net.HardwareAddr) IfaceOption {
return func(i *nwIface) {
i.mac = mac
}
}
func (n *networkNamespace) Address(addr *net.IPNet) IfaceOption {
return func(i *nwIface) {
i.address = addr

View file

@ -76,6 +76,9 @@ type IfaceOptionSetter interface {
// Bridge returns an option setter to set if the interface is a bridge.
Bridge(bool) IfaceOption
// MacAddress returns an option setter to set the MAC address.
MacAddress(net.HardwareAddr) IfaceOption
// Address returns an option setter to set IPv4 address.
Address(*net.IPNet) IfaceOption

View file

@ -2,8 +2,11 @@ package libnetwork
import (
"fmt"
"math/rand"
"net"
"strings"
"sync"
"time"
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/iptables"
@ -31,23 +34,35 @@ type Resolver interface {
}
const (
resolverIP = "127.0.0.11"
dnsPort = "53"
ptrIPv4domain = ".in-addr.arpa."
ptrIPv6domain = ".ip6.arpa."
respTTL = 600
maxExtDNS = 3 //max number of external servers to try
resolverIP = "127.0.0.11"
dnsPort = "53"
ptrIPv4domain = ".in-addr.arpa."
ptrIPv6domain = ".ip6.arpa."
respTTL = 600
maxExtDNS = 3 //max number of external servers to try
extIOTimeout = 3 * time.Second
defaultRespSize = 512
)
type extDNSEntry struct {
ipStr string
extConn net.Conn
extOnce sync.Once
}
// resolver implements the Resolver interface
type resolver struct {
sb *sandbox
extDNS []string
server *dns.Server
conn *net.UDPConn
tcpServer *dns.Server
tcpListen *net.TCPListener
err error
sb *sandbox
extDNSList [maxExtDNS]extDNSEntry
server *dns.Server
conn *net.UDPConn
tcpServer *dns.Server
tcpListen *net.TCPListener
err error
}
func init() {
rand.Seed(time.Now().Unix())
}
// NewResolver creates a new instance of the Resolver
@ -136,7 +151,13 @@ func (r *resolver) Stop() {
}
func (r *resolver) SetExtServers(dns []string) {
r.extDNS = dns
l := len(dns)
if l > maxExtDNS {
l = maxExtDNS
}
for i := 0; i < l; i++ {
r.extDNSList[i].ipStr = dns[i]
}
}
func (r *resolver) NameServer() string {
@ -151,22 +172,36 @@ func setCommonFlags(msg *dns.Msg) {
msg.RecursionAvailable = true
}
func shuffleAddr(addr []net.IP) []net.IP {
for i := len(addr) - 1; i > 0; i-- {
r := rand.Intn(i + 1)
addr[i], addr[r] = addr[r], addr[i]
}
return addr
}
func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
addr := r.sb.ResolveName(name)
if addr == nil {
return nil, nil
}
log.Debugf("Lookup for %s: IP %s", name, addr.String())
log.Debugf("Lookup for %s: IP %v", name, addr)
resp := new(dns.Msg)
resp.SetReply(query)
setCommonFlags(resp)
rr := new(dns.A)
rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
rr.A = addr
resp.Answer = append(resp.Answer, rr)
if len(addr) > 1 {
addr = shuffleAddr(addr)
}
for _, ip := range addr {
rr := new(dns.A)
rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
rr.A = ip
resp.Answer = append(resp.Answer, rr)
}
return resp, nil
}
@ -200,10 +235,23 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error)
return resp, nil
}
func truncateResp(resp *dns.Msg, maxSize int, isTCP bool) {
if !isTCP {
resp.Truncated = true
}
// trim the Answer RRs one by one till the whole message fits
// within the reply size
for resp.Len() > maxSize {
resp.Answer = resp.Answer[:len(resp.Answer)-1]
}
}
func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
var (
resp *dns.Msg
err error
extConn net.Conn
resp *dns.Msg
err error
)
if query == nil || len(query.Question) == 0 {
@ -221,28 +269,82 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
return
}
if resp == nil {
if len(r.extDNS) == 0 {
return
proto := w.LocalAddr().Network()
maxSize := 0
if proto == "tcp" {
maxSize = dns.MaxMsgSize - 1
} else if proto == "udp" {
optRR := query.IsEdns0()
if optRR != nil {
maxSize = int(optRR.UDPSize())
}
num := maxExtDNS
if len(r.extDNS) < maxExtDNS {
num = len(r.extDNS)
if maxSize < defaultRespSize {
maxSize = defaultRespSize
}
for i := 0; i < num; i++ {
log.Debugf("Querying ext dns %s:%s for %s[%d]", w.LocalAddr().Network(), r.extDNS[i], name, query.Question[0].Qtype)
}
c := &dns.Client{Net: w.LocalAddr().Network()}
addr := fmt.Sprintf("%s:%d", r.extDNS[i], 53)
resp, _, err = c.Exchange(query, addr)
if err == nil {
resp.Compress = true
if resp != nil {
if resp.Len() > maxSize {
truncateResp(resp, maxSize, proto == "tcp")
}
} else {
for i := 0; i < maxExtDNS; i++ {
extDNS := &r.extDNSList[i]
if extDNS.ipStr == "" {
break
}
log.Errorf("external resolution failed, %s", err)
log.Debugf("Querying ext dns %s:%s for %s[%d]", proto, extDNS.ipStr, name, query.Question[0].Qtype)
extConnect := func() {
addr := fmt.Sprintf("%s:%d", extDNS.ipStr, 53)
extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
}
// For udp clients connection is persisted to reuse for further queries.
// Accessing extDNS.extConn be a race here between go rouines. Hence the
// connection setup is done in a Once block and fetch the extConn again
extConn = extDNS.extConn
if extConn == nil || proto == "tcp" {
if proto == "udp" {
extDNS.extOnce.Do(func() {
r.sb.execFunc(extConnect)
extDNS.extConn = extConn
})
extConn = extDNS.extConn
} else {
r.sb.execFunc(extConnect)
}
if err != nil {
log.Debugf("Connect failed, %s", err)
continue
}
}
// Timeout has to be set for every IO operation.
extConn.SetDeadline(time.Now().Add(extIOTimeout))
co := &dns.Conn{Conn: extConn}
defer func() {
if proto == "tcp" {
co.Close()
}
}()
err = co.WriteMsg(query)
if err != nil {
log.Debugf("Send to DNS server failed, %s", err)
continue
}
resp, err = co.ReadMsg()
if err != nil {
log.Debugf("Read from DNS server failed, %s", err)
continue
}
resp.Compress = true
break
}
if resp == nil {
return
}

View file

@ -10,6 +10,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/etchosts"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/types"
)
@ -37,7 +38,7 @@ type Sandbox interface {
Delete() error
// ResolveName searches for the service name in the networks to which the sandbox
// is connected to.
ResolveName(name string) net.IP
ResolveName(name string) []net.IP
// ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
// notation; the format used for DNS PTR records
ResolveIP(name string) string
@ -118,6 +119,7 @@ type containerConfig struct {
useDefaultSandBox bool
useExternalKey bool
prio int // higher the value, more the priority
exposedPorts []types.TransportPort
}
func (sb *sandbox) ID() string {
@ -136,18 +138,27 @@ func (sb *sandbox) Key() string {
}
func (sb *sandbox) Labels() map[string]interface{} {
return sb.config.generic
sb.Lock()
sb.Unlock()
opts := make(map[string]interface{}, len(sb.config.generic))
for k, v := range sb.config.generic {
opts[k] = v
}
return opts
}
func (sb *sandbox) Statistics() (map[string]*types.InterfaceStatistics, error) {
m := make(map[string]*types.InterfaceStatistics)
if sb.osSbox == nil {
sb.Lock()
osb := sb.osSbox
sb.Unlock()
if osb == nil {
return m, nil
}
var err error
for _, i := range sb.osSbox.Info().Interfaces() {
for _, i := range osb.Info().Interfaces() {
if m[i.DstName()], err = i.Statistics(); err != nil {
return m, err
}
@ -326,6 +337,18 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
return eps
}
func (sb *sandbox) removeEndpoint(ep *endpoint) {
sb.Lock()
defer sb.Unlock()
for i, e := range sb.endpoints {
if e == ep {
heap.Remove(&sb.endpoints, i)
return
}
}
}
func (sb *sandbox) getEndpoint(id string) *endpoint {
sb.Lock()
defer sb.Unlock()
@ -391,8 +414,12 @@ func (sb *sandbox) ResolveIP(ip string) string {
return svc
}
func (sb *sandbox) ResolveName(name string) net.IP {
var ip net.IP
func (sb *sandbox) execFunc(f func()) {
sb.osSbox.InvokeFunc(f)
}
func (sb *sandbox) ResolveName(name string) []net.IP {
var ip []net.IP
// Embedded server owns the docker network domain. Resolution should work
// for both container_name and container_name.network_name
@ -440,7 +467,7 @@ func (sb *sandbox) ResolveName(name string) net.IP {
return nil
}
func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool) net.IP {
func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool) []net.IP {
for _, ep := range epList {
name := req
n := ep.getNetwork()
@ -463,7 +490,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
}
} else {
// If it is a regular lookup and if the requested name is an alias
// dont perform a svc lookup for this endpoint.
// don't perform a svc lookup for this endpoint.
ep.Lock()
if _, ok := ep.aliases[req]; ok {
ep.Unlock()
@ -481,7 +508,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
ip, ok := sr.svcMap[name]
n.Unlock()
if ok {
return ip[0]
return ip
}
}
return nil
@ -606,6 +633,9 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
}
if i.mac != nil {
ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac))
}
if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
@ -621,14 +651,9 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
}
}
for _, gwep := range sb.getConnectedEndpoints() {
if len(gwep.Gateway()) > 0 {
if gwep != ep {
break
}
if err := sb.updateGateway(gwep); err != nil {
return err
}
if ep == sb.getGatewayEndpoint() {
if err := sb.updateGateway(ep); err != nil {
return err
}
}
@ -647,7 +672,7 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
ep := sb.getEndpoint(origEp.id)
if ep == nil {
return fmt.Errorf("could not find the sandbox endpoint data for endpoint %s",
ep.name)
origEp.id)
}
sb.Lock()
@ -739,6 +764,13 @@ func (sb *sandbox) joinLeaveEnd() {
}
}
func (sb *sandbox) hasPortConfigs() bool {
opts := sb.Labels()
_, hasExpPorts := opts[netlabel.ExposedPorts]
_, hasPortMaps := opts[netlabel.PortMap]
return hasExpPorts || hasPortMaps
}
// OptionHostname function returns an option setter for hostname option to
// be passed to NewSandbox method.
func OptionHostname(name string) SandboxOption {
@ -848,7 +880,42 @@ func OptionUseExternalKey() SandboxOption {
// net container creation method. Container Labels are a good example.
func OptionGeneric(generic map[string]interface{}) SandboxOption {
return func(sb *sandbox) {
sb.config.generic = generic
if sb.config.generic == nil {
sb.config.generic = make(map[string]interface{}, len(generic))
}
for k, v := range generic {
sb.config.generic[k] = v
}
}
}
// OptionExposedPorts function returns an option setter for the container exposed
// ports option to be passed to container Create method.
func OptionExposedPorts(exposedPorts []types.TransportPort) SandboxOption {
return func(sb *sandbox) {
if sb.config.generic == nil {
sb.config.generic = make(map[string]interface{})
}
// Defensive copy
eps := make([]types.TransportPort, len(exposedPorts))
copy(eps, exposedPorts)
// Store endpoint label and in generic because driver needs it
sb.config.exposedPorts = eps
sb.config.generic[netlabel.ExposedPorts] = eps
}
}
// OptionPortMapping function returns an option setter for the mapping
// ports option to be passed to container Create method.
func OptionPortMapping(portBindings []types.PortBinding) SandboxOption {
return func(sb *sandbox) {
if sb.config.generic == nil {
sb.config.generic = make(map[string]interface{})
}
// Store a copy of the bindings as generic data to pass to the driver
pbs := make([]types.PortBinding, len(portBindings))
copy(pbs, portBindings)
sb.config.generic[netlabel.PortMap] = pbs
}
}

View file

@ -130,7 +130,7 @@ func (c *controller) acceptClientConnections(sock string, l net.Listener) {
conn, err := l.Accept()
if err != nil {
if _, err1 := os.Stat(sock); os.IsNotExist(err1) {
logrus.Debugf("Unix socket %s doesnt exist. cannot accept client connections", sock)
logrus.Debugf("Unix socket %s doesn't exist. cannot accept client connections", sock)
return
}
logrus.Errorf("Error accepting connection %v", err)

View file

@ -389,7 +389,7 @@ const (
// NEXTHOP indicates a StaticRoute with an IP next hop.
NEXTHOP = iota
// CONNECTED indicates a StaticRoute with a interface for directly connected peers.
// CONNECTED indicates a StaticRoute with an interface for directly connected peers.
CONNECTED
)
@ -458,25 +458,25 @@ type NotFoundError interface {
NotFound()
}
// ForbiddenError is an interface for errors which denote an valid request that cannot be honored
// ForbiddenError is an interface for errors which denote a valid request that cannot be honored
type ForbiddenError interface {
// Forbidden makes implementer into ForbiddenError type
Forbidden()
}
// NoServiceError is an interface for errors returned when the required service is not available
// NoServiceError is an interface for errors returned when the required service is not available
type NoServiceError interface {
// NoService makes implementer into NoServiceError type
NoService()
}
// TimeoutError is an interface for errors raised because of timeout
// TimeoutError is an interface for errors raised because of timeout
type TimeoutError interface {
// Timeout makes implementer into TimeoutError type
Timeout()
}
// NotImplementedError is an interface for errors raised because of requested functionality is not yet implemented
// NotImplementedError is an interface for errors raised because of requested functionality is not yet implemented
type NotImplementedError interface {
// NotImplemented makes implementer into NotImplementedError type
NotImplemented()

View file

@ -101,6 +101,10 @@ func AddrList(link Link, family int) ([]Addr, error) {
continue
}
if family != FAMILY_ALL && msg.Family != uint8(family) {
continue
}
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil {
return nil, err

View file

@ -56,6 +56,7 @@ func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
ceil := cattrs.Ceil / 8
buffer := cattrs.Buffer
cbuffer := cattrs.Cbuffer
if ceil == 0 {
ceil = rate
}

View file

@ -1,6 +1,7 @@
package netlink
import (
"errors"
"syscall"
"github.com/vishvananda/netlink/nl"
@ -65,15 +66,32 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
if htb, ok := class.(*HtbClass); ok {
opt := nl.TcHtbCopt{}
opt.Rate.Rate = uint32(htb.Rate)
opt.Ceil.Rate = uint32(htb.Ceil)
opt.Buffer = htb.Buffer
opt.Cbuffer = htb.Cbuffer
opt.Quantum = htb.Quantum
opt.Level = htb.Level
opt.Prio = htb.Prio
// TODO: Handle Debug properly. For now default to 0
/* Calculate {R,C}Tab and set Rate and Ceil */
cell_log := -1
ccell_log := -1
linklayer := nl.LINKLAYER_ETHERNET
mtu := 1600
var rtab [256]uint32
var ctab [256]uint32
tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)}
if CalcRtable(&tcrate, rtab, cell_log, uint32(mtu), linklayer) < 0 {
return errors.New("HTB: failed to calculate rate table.")
}
opt.Rate = tcrate
tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)}
if CalcRtable(&tcceil, ctab, ccell_log, uint32(mtu), linklayer) < 0 {
return errors.New("HTB: failed to calculate ceil rate table.")
}
opt.Ceil = tcceil
nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize())
nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab))
nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab))
}
req.AddData(options)
return nil

View file

@ -204,6 +204,7 @@ type Vxlan struct {
RSC bool
L2miss bool
L3miss bool
UDPCSum bool
NoAge bool
GBP bool
Age int

View file

@ -142,6 +142,54 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
return err
}
// LinkSetVfHardwareAddr sets the hardware address of a vf for the link.
// Equivalent to: `ip link set $link vf $vf mac $hwaddr`
func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Index = int32(base.Index)
req.AddData(msg)
data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfMac{
Vf: uint32(vf),
}
copy(vfmsg.Mac[:], []byte(hwaddr))
nl.NewRtAttrChild(info, nl.IFLA_VF_MAC, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
return err
}
// LinkSetVfVlan sets the vlan of a vf for the link.
// Equivalent to: `ip link set $link vf $vf vlan $vlan`
func LinkSetVfVlan(link Link, vf, vlan int) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Index = int32(base.Index)
req.AddData(msg)
data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfVlan{
Vf: uint32(vf),
Vlan: uint32(vlan),
}
nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
return err
}
// LinkSetMaster sets the master of the link device.
// Equivalent to: `ip link set $link master $master`
func LinkSetMaster(link Link, master *Bridge) error {
@ -277,10 +325,12 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
if vxlan.UDPCSum {
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum))
}
if vxlan.GBP {
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GBP, boolAttr(vxlan.GBP))
}
if vxlan.NoAge {
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
} else if vxlan.Age > 0 {
@ -815,6 +865,7 @@ func LinkList() ([]Link, error) {
// LinkUpdate is used to pass information back from LinkSubscribe()
type LinkUpdate struct {
nl.IfInfomsg
Header syscall.NlMsghdr
Link
}
@ -844,7 +895,7 @@ func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
if err != nil {
return
}
ch <- LinkUpdate{IfInfomsg: *ifmsg, Link: link}
ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: m.Header, Link: link}
}
}
}()
@ -935,6 +986,8 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
vxlan.L2miss = int8(datum.Value[0]) != 0
case nl.IFLA_VXLAN_L3MISS:
vxlan.L3miss = int8(datum.Value[0]) != 0
case nl.IFLA_VXLAN_UDP_CSUM:
vxlan.UDPCSum = int8(datum.Value[0]) != 0
case nl.IFLA_VXLAN_GBP:
vxlan.GBP = int8(datum.Value[0]) != 0
case nl.IFLA_VXLAN_AGEING:

View file

@ -1,7 +1,13 @@
package nl
import (
"unsafe"
)
const (
DEFAULT_CHANGE = 0xFFFFFFFF
// doesn't exist in syscall
IFLA_VFINFO_LIST = 0x16
)
const (
@ -182,3 +188,209 @@ const (
GRE_FLAGS = 0x00F8
GRE_VERSION = 0x0007
)
const (
IFLA_VF_INFO_UNSPEC = iota
IFLA_VF_INFO
IFLA_VF_INFO_MAX = IFLA_VF_INFO
)
const (
IFLA_VF_UNSPEC = iota
IFLA_VF_MAC /* Hardware queue specific attributes */
IFLA_VF_VLAN
IFLA_VF_TX_RATE /* Max TX Bandwidth Allocation */
IFLA_VF_SPOOFCHK /* Spoof Checking on/off switch */
IFLA_VF_LINK_STATE /* link state enable/disable/auto switch */
IFLA_VF_RATE /* Min and Max TX Bandwidth Allocation */
IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query
* on/off switch
*/
IFLA_VF_STATS /* network device statistics */
IFLA_VF_MAX = IFLA_VF_STATS
)
const (
IFLA_VF_LINK_STATE_AUTO = iota /* link state of the uplink */
IFLA_VF_LINK_STATE_ENABLE /* link always up */
IFLA_VF_LINK_STATE_DISABLE /* link always down */
IFLA_VF_LINK_STATE_MAX = IFLA_VF_LINK_STATE_DISABLE
)
const (
IFLA_VF_STATS_RX_PACKETS = iota
IFLA_VF_STATS_TX_PACKETS
IFLA_VF_STATS_RX_BYTES
IFLA_VF_STATS_TX_BYTES
IFLA_VF_STATS_BROADCAST
IFLA_VF_STATS_MULTICAST
IFLA_VF_STATS_MAX = IFLA_VF_STATS_MULTICAST
)
const (
SizeofVfMac = 0x24
SizeofVfVlan = 0x0c
SizeofVfTxRate = 0x08
SizeofVfRate = 0x0c
SizeofVfSpoofchk = 0x08
SizeofVfLinkState = 0x08
SizeofVfRssQueryEn = 0x08
)
// struct ifla_vf_mac {
// __u32 vf;
// __u8 mac[32]; /* MAX_ADDR_LEN */
// };
type VfMac struct {
Vf uint32
Mac [32]byte
}
func (msg *VfMac) Len() int {
return SizeofVfMac
}
func DeserializeVfMac(b []byte) *VfMac {
return (*VfMac)(unsafe.Pointer(&b[0:SizeofVfMac][0]))
}
func (msg *VfMac) Serialize() []byte {
return (*(*[SizeofVfMac]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_vlan {
// __u32 vf;
// __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
// __u32 qos;
// };
type VfVlan struct {
Vf uint32
Vlan uint32
Qos uint32
}
func (msg *VfVlan) Len() int {
return SizeofVfVlan
}
func DeserializeVfVlan(b []byte) *VfVlan {
return (*VfVlan)(unsafe.Pointer(&b[0:SizeofVfVlan][0]))
}
func (msg *VfVlan) Serialize() []byte {
return (*(*[SizeofVfVlan]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_tx_rate {
// __u32 vf;
// __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
// };
type VfTxRate struct {
Vf uint32
Rate uint32
}
func (msg *VfTxRate) Len() int {
return SizeofVfTxRate
}
func DeserializeVfTxRate(b []byte) *VfTxRate {
return (*VfTxRate)(unsafe.Pointer(&b[0:SizeofVfTxRate][0]))
}
func (msg *VfTxRate) Serialize() []byte {
return (*(*[SizeofVfTxRate]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_rate {
// __u32 vf;
// __u32 min_tx_rate; /* Min Bandwidth in Mbps */
// __u32 max_tx_rate; /* Max Bandwidth in Mbps */
// };
type VfRate struct {
Vf uint32
MinTxRate uint32
MaxTxRate uint32
}
func (msg *VfRate) Len() int {
return SizeofVfRate
}
func DeserializeVfRate(b []byte) *VfRate {
return (*VfRate)(unsafe.Pointer(&b[0:SizeofVfRate][0]))
}
func (msg *VfRate) Serialize() []byte {
return (*(*[SizeofVfRate]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_spoofchk {
// __u32 vf;
// __u32 setting;
// };
type VfSpoofchk struct {
Vf uint32
Setting uint32
}
func (msg *VfSpoofchk) Len() int {
return SizeofVfSpoofchk
}
func DeserializeVfSpoofchk(b []byte) *VfSpoofchk {
return (*VfSpoofchk)(unsafe.Pointer(&b[0:SizeofVfSpoofchk][0]))
}
func (msg *VfSpoofchk) Serialize() []byte {
return (*(*[SizeofVfSpoofchk]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_link_state {
// __u32 vf;
// __u32 link_state;
// };
type VfLinkState struct {
Vf uint32
LinkState uint32
}
func (msg *VfLinkState) Len() int {
return SizeofVfLinkState
}
func DeserializeVfLinkState(b []byte) *VfLinkState {
return (*VfLinkState)(unsafe.Pointer(&b[0:SizeofVfLinkState][0]))
}
func (msg *VfLinkState) Serialize() []byte {
return (*(*[SizeofVfLinkState]byte)(unsafe.Pointer(msg)))[:]
}
// struct ifla_vf_rss_query_en {
// __u32 vf;
// __u32 setting;
// };
type VfRssQueryEn struct {
Vf uint32
Setting uint32
}
func (msg *VfRssQueryEn) Len() int {
return SizeofVfRssQueryEn
}
func DeserializeVfRssQueryEn(b []byte) *VfRssQueryEn {
return (*VfRssQueryEn)(unsafe.Pointer(&b[0:SizeofVfRssQueryEn][0]))
}
func (msg *VfRssQueryEn) Serialize() []byte {
return (*(*[SizeofVfRssQueryEn]byte)(unsafe.Pointer(msg)))[:]
}

View file

@ -110,9 +110,6 @@ func XfrmStateDel(state *XfrmState) error {
func XfrmStateList(family int) ([]XfrmState, error) {
req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
if err != nil {
return nil, err