зеркало из https://github.com/microsoft/docker.git
Merge pull request #15584 from mavenugo/ln-vendor-in
Vendoring in libnetwork 22dc04d06067b40a9e7ef575aee6d1bb69d4dcc3
This commit is contained in:
Коммит
d1fada4bf7
|
@ -392,19 +392,19 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error)
|
|||
|
||||
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
|
||||
option := options.Generic{
|
||||
"EnableIPForwarding": config.Bridge.EnableIPForward}
|
||||
"EnableIPForwarding": config.Bridge.EnableIPForward,
|
||||
"EnableIPTables": config.Bridge.EnableIPTables,
|
||||
"EnableUserlandProxy": config.Bridge.EnableUserlandProxy}
|
||||
|
||||
if err := controller.ConfigureNetworkDriver("bridge", options.Generic{netlabel.GenericData: option}); err != nil {
|
||||
return fmt.Errorf("Error initializing bridge driver: %v", err)
|
||||
}
|
||||
|
||||
netOption := options.Generic{
|
||||
"BridgeName": config.Bridge.Iface,
|
||||
"Mtu": config.Mtu,
|
||||
"EnableIPTables": config.Bridge.EnableIPTables,
|
||||
"EnableIPMasquerade": config.Bridge.EnableIPMasq,
|
||||
"EnableICC": config.Bridge.InterContainerCommunication,
|
||||
"EnableUserlandProxy": config.Bridge.EnableUserlandProxy,
|
||||
"BridgeName": config.Bridge.Iface,
|
||||
"Mtu": config.Mtu,
|
||||
"EnableIPMasquerade": config.Bridge.EnableIPMasq,
|
||||
"EnableICC": config.Bridge.InterContainerCommunication,
|
||||
}
|
||||
|
||||
if config.Bridge.IP != "" {
|
||||
|
|
|
@ -21,14 +21,14 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith
|
|||
clone hg code.google.com/p/gosqlite 74691fb6f837
|
||||
|
||||
#get libnetwork packages
|
||||
clone git github.com/docker/libnetwork bd3eecc96f3c05a4acef1bedcf74397bc6850d22
|
||||
clone git github.com/docker/libnetwork 22dc04d06067b40a9e7ef575aee6d1bb69d4dcc3
|
||||
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 60c7c881345b3c67defc7f93a8297debf041d43c
|
||||
clone git github.com/vishvananda/netns 493029407eeb434d0c2d44e02ea072ff2488d322
|
||||
clone git github.com/vishvananda/netlink 20397a138846e4d6590e01783ed023ed7e1c38a6
|
||||
clone git github.com/vishvananda/netlink 329b40d4e308deb2abe80dbb1f74078e5ab13164
|
||||
clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
|
||||
clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
|
||||
clone git github.com/coreos/go-etcd v2.0.0
|
||||
|
|
|
@ -64,7 +64,7 @@ There are many networking solutions available to suit a broad range of use-cases
|
|||
epInfo, err := ep.DriverInfo()
|
||||
mapData, ok := epInfo[netlabel.PortMap]
|
||||
if ok {
|
||||
portMapping, ok := mapData.([]netutils.PortBinding)
|
||||
portMapping, ok := mapData.([]types.PortBinding)
|
||||
if ok {
|
||||
fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping)
|
||||
}
|
||||
|
|
|
@ -22,20 +22,24 @@ var (
|
|||
|
||||
const (
|
||||
// Resource name regex
|
||||
// Gorilla mux encloses the passed pattern with '^' and '$'. So we need to do some tricks
|
||||
// to have mux eventually build a query regex which matches empty or word string (`^$|[\w]+`)
|
||||
regex = "[a-zA-Z_0-9-]+"
|
||||
qregx = "$|" + regex
|
||||
// Router URL variable definition
|
||||
nwName = "{" + urlNwName + ":" + regex + "}"
|
||||
nwID = "{" + urlNwID + ":" + regex + "}"
|
||||
nwPID = "{" + urlNwPID + ":" + regex + "}"
|
||||
epName = "{" + urlEpName + ":" + regex + "}"
|
||||
epID = "{" + urlEpID + ":" + regex + "}"
|
||||
epPID = "{" + urlEpPID + ":" + regex + "}"
|
||||
cnID = "{" + urlCnID + ":" + regex + "}"
|
||||
nwName = "{" + urlNwName + ":" + regex + "}"
|
||||
nwNameQr = "{" + urlNwName + ":" + qregx + "}"
|
||||
nwID = "{" + urlNwID + ":" + regex + "}"
|
||||
nwPIDQr = "{" + urlNwPID + ":" + qregx + "}"
|
||||
epName = "{" + urlEpName + ":" + regex + "}"
|
||||
epNameQr = "{" + urlEpName + ":" + qregx + "}"
|
||||
epID = "{" + urlEpID + ":" + regex + "}"
|
||||
epPIDQr = "{" + urlEpPID + ":" + qregx + "}"
|
||||
cnID = "{" + urlCnID + ":" + regex + "}"
|
||||
|
||||
// Though this name can be anything, in order to support default network,
|
||||
// we will keep it as name
|
||||
urlNwName = "name"
|
||||
// Internal URL variable name, they can be anything
|
||||
// Internal URL variable name.They can be anything as
|
||||
// long as they do not collide with query fields.
|
||||
urlNwName = "network-name"
|
||||
urlNwID = "network-id"
|
||||
urlNwPID = "network-partial-id"
|
||||
urlEpName = "endpoint-name"
|
||||
|
@ -89,17 +93,17 @@ func (h *httpHandler) initRouter() {
|
|||
}{
|
||||
"GET": {
|
||||
// Order matters
|
||||
{"/networks", []string{"name", nwName}, procGetNetworks},
|
||||
{"/networks", []string{"partial-id", nwPID}, procGetNetworks},
|
||||
{"/networks", []string{"name", nwNameQr}, procGetNetworks},
|
||||
{"/networks", []string{"partial-id", nwPIDQr}, procGetNetworks},
|
||||
{"/networks", nil, procGetNetworks},
|
||||
{"/networks/" + nwID, nil, procGetNetwork},
|
||||
{"/networks/" + nwID + "/endpoints", []string{"name", epName}, procGetEndpoints},
|
||||
{"/networks/" + nwID + "/endpoints", []string{"partial-id", epPID}, procGetEndpoints},
|
||||
{"/networks/" + nwID + "/endpoints", []string{"name", epNameQr}, procGetEndpoints},
|
||||
{"/networks/" + nwID + "/endpoints", []string{"partial-id", epPIDQr}, procGetEndpoints},
|
||||
{"/networks/" + nwID + "/endpoints", nil, procGetEndpoints},
|
||||
{"/networks/" + nwID + "/endpoints/" + epID, nil, procGetEndpoint},
|
||||
{"/services", []string{"network", nwName}, procGetServices},
|
||||
{"/services", []string{"name", epName}, procGetServices},
|
||||
{"/services", []string{"partial-id", epPID}, procGetServices},
|
||||
{"/services", []string{"network", nwNameQr}, procGetServices},
|
||||
{"/services", []string{"name", epNameQr}, procGetServices},
|
||||
{"/services", []string{"partial-id", epPIDQr}, procGetServices},
|
||||
{"/services", nil, procGetServices},
|
||||
{"/services/" + epID, nil, procGetService},
|
||||
{"/services/" + epID + "/backend", nil, procGetContainers},
|
||||
|
@ -150,22 +154,7 @@ func makeHandler(ctrl libnetwork.NetworkController, fct processor) http.HandlerF
|
|||
}
|
||||
}
|
||||
|
||||
mvars := mux.Vars(req)
|
||||
rvars := req.URL.Query()
|
||||
// workaround a mux issue which filters out valid queries with empty value
|
||||
for k := range rvars {
|
||||
if _, ok := mvars[k]; !ok {
|
||||
if rvars.Get(k) == "" {
|
||||
mvars[k] = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res, rsp := fct(ctrl, mvars, body)
|
||||
if !rsp.isOK() {
|
||||
http.Error(w, rsp.Status, rsp.StatusCode)
|
||||
return
|
||||
}
|
||||
res, rsp := fct(ctrl, mux.Vars(req), body)
|
||||
if res != nil {
|
||||
writeJSON(w, rsp.StatusCode, res)
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
|
@ -38,7 +40,9 @@ var (
|
|||
|
||||
// configuration info for the "bridge" driver.
|
||||
type configuration struct {
|
||||
EnableIPForwarding bool
|
||||
EnableIPForwarding bool
|
||||
EnableIPTables bool
|
||||
EnableUserlandProxy bool
|
||||
}
|
||||
|
||||
// networkConfiguration for network specific configuration
|
||||
|
@ -48,7 +52,6 @@ type networkConfiguration struct {
|
|||
FixedCIDR *net.IPNet
|
||||
FixedCIDRv6 *net.IPNet
|
||||
EnableIPv6 bool
|
||||
EnableIPTables bool
|
||||
EnableIPMasquerade bool
|
||||
EnableICC bool
|
||||
Mtu int
|
||||
|
@ -56,7 +59,6 @@ type networkConfiguration struct {
|
|||
DefaultGatewayIPv6 net.IP
|
||||
DefaultBindingIP net.IP
|
||||
AllowNonDefaultBridge bool
|
||||
EnableUserlandProxy bool
|
||||
}
|
||||
|
||||
// endpointConfiguration represents the user specified configuration for the sandbox endpoint
|
||||
|
@ -89,13 +91,16 @@ type bridgeNetwork struct {
|
|||
config *networkConfiguration
|
||||
endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id
|
||||
portMapper *portmapper.PortMapper
|
||||
driver *driver // The network's driver
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
config *configuration
|
||||
network *bridgeNetwork
|
||||
networks map[types.UUID]*bridgeNetwork
|
||||
config *configuration
|
||||
network *bridgeNetwork
|
||||
natChain *iptables.ChainInfo
|
||||
filterChain *iptables.ChainInfo
|
||||
networks map[types.UUID]*bridgeNetwork
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -110,10 +115,13 @@ func newDriver() driverapi.Driver {
|
|||
|
||||
// Init registers a new instance of bridge driver
|
||||
func Init(dc driverapi.DriverCallback) error {
|
||||
// try to modprobe bridge first
|
||||
// see gh#12177
|
||||
if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").CombinedOutput(); err != nil {
|
||||
logrus.Warnf("Running modprobe bridge nf_nat br_netfilter failed with message: %s, error: %v", out, err)
|
||||
if _, err := os.Stat("/proc/sys/net/bridge"); err != nil {
|
||||
if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil {
|
||||
logrus.Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err)
|
||||
}
|
||||
}
|
||||
if out, err := exec.Command("modprobe", "-va", "nf_nat").CombinedOutput(); err != nil {
|
||||
logrus.Warnf("Running modprobe nf_nat failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
||||
}
|
||||
if err := iptables.FirewalldInit(); err != nil {
|
||||
logrus.Debugf("Fail to initialize firewalld: %v, using raw iptables instead", err)
|
||||
|
@ -218,16 +226,6 @@ func (c *networkConfiguration) fromMap(data map[string]interface{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
if i, ok := data["EnableIPTables"]; ok && i != nil {
|
||||
if s, ok := i.(string); ok {
|
||||
if c.EnableIPTables, err = strconv.ParseBool(s); err != nil {
|
||||
return types.BadRequestErrorf("failed to parse EnableIPTables value: %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
return types.BadRequestErrorf("invalid type for EnableIPTables value")
|
||||
}
|
||||
}
|
||||
|
||||
if i, ok := data["EnableIPMasquerade"]; ok && i != nil {
|
||||
if s, ok := i.(string); ok {
|
||||
if c.EnableIPMasquerade, err = strconv.ParseBool(s); err != nil {
|
||||
|
@ -329,6 +327,25 @@ func (c *networkConfiguration) fromMap(data map[string]interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainInfo, error) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
if n.driver == nil {
|
||||
return nil, nil, types.BadRequestErrorf("no driver found")
|
||||
}
|
||||
|
||||
return n.driver.natChain, n.driver.filterChain, nil
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) getNetworkBridgeName() string {
|
||||
n.Lock()
|
||||
config := n.config
|
||||
n.Unlock()
|
||||
|
||||
return config.BridgeName
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) getEndpoint(eid types.UUID) (*bridgeEndpoint, error) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
@ -413,6 +430,7 @@ func (c *networkConfiguration) conflictsWithNetworks(id types.UUID, others []*br
|
|||
|
||||
func (d *driver) Config(option map[string]interface{}) error {
|
||||
var config *configuration
|
||||
var err error
|
||||
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
@ -439,10 +457,19 @@ func (d *driver) Config(option map[string]interface{}) error {
|
|||
d.config = config
|
||||
} else {
|
||||
config = &configuration{}
|
||||
d.config = config
|
||||
}
|
||||
|
||||
if config.EnableIPForwarding {
|
||||
return setupIPForwarding(config)
|
||||
err = setupIPForwarding()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.EnableIPTables {
|
||||
d.natChain, d.filterChain, err = setupIPChains(config)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -475,7 +502,6 @@ func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error)
|
|||
case map[string]interface{}:
|
||||
config = &networkConfiguration{
|
||||
EnableICC: true,
|
||||
EnableIPTables: true,
|
||||
EnableIPMasquerade: true,
|
||||
}
|
||||
err = config.fromMap(opt)
|
||||
|
@ -573,6 +599,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
endpoints: make(map[types.UUID]*bridgeEndpoint),
|
||||
config: config,
|
||||
portMapper: portmapper.New(),
|
||||
driver: d,
|
||||
}
|
||||
|
||||
d.Lock()
|
||||
|
@ -655,14 +682,14 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
{enableIPv6Forwarding, setupIPv6Forwarding},
|
||||
|
||||
// Setup Loopback Adresses Routing
|
||||
{!config.EnableUserlandProxy, setupLoopbackAdressesRouting},
|
||||
{!d.config.EnableUserlandProxy, setupLoopbackAdressesRouting},
|
||||
|
||||
// Setup IPTables.
|
||||
{config.EnableIPTables, network.setupIPTables},
|
||||
{d.config.EnableIPTables, network.setupIPTables},
|
||||
|
||||
//We want to track firewalld configuration so that
|
||||
//if it is started/reloaded, the rules can be applied correctly
|
||||
{config.EnableIPTables, network.setupFirewalld},
|
||||
{d.config.EnableIPTables, network.setupFirewalld},
|
||||
|
||||
// Setup DefaultGatewayIPv4
|
||||
{config.DefaultGatewayIPv4 != nil, setupGatewayIPv4},
|
||||
|
@ -671,10 +698,10 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
{config.DefaultGatewayIPv6 != nil, setupGatewayIPv6},
|
||||
|
||||
// Add inter-network communication rules.
|
||||
{config.EnableIPTables, setupNetworkIsolationRules},
|
||||
{d.config.EnableIPTables, setupNetworkIsolationRules},
|
||||
|
||||
//Configure bridge networking filtering if ICC is off and IP tables are enabled
|
||||
{!config.EnableICC && config.EnableIPTables, setupBridgeNetFiltering},
|
||||
{!config.EnableICC && d.config.EnableIPTables, setupBridgeNetFiltering},
|
||||
} {
|
||||
if step.Condition {
|
||||
bridgeSetup.queueStep(step.Fn)
|
||||
|
@ -833,6 +860,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
// Get the network handler and make sure it exists
|
||||
d.Lock()
|
||||
n, ok := d.networks[nid]
|
||||
dconfig := d.config
|
||||
d.Unlock()
|
||||
|
||||
if !ok {
|
||||
|
@ -945,7 +973,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
|
||||
}
|
||||
|
||||
if !config.EnableUserlandProxy {
|
||||
if !dconfig.EnableUserlandProxy {
|
||||
err = setHairpinMode(host, true)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1018,7 +1046,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
}
|
||||
|
||||
// Program any required port mapping and store them in the endpoint
|
||||
endpoint.portMapping, err = n.allocatePorts(epConfig, endpoint, config.DefaultBindingIP, config.EnableUserlandProxy)
|
||||
endpoint.portMapping, err = n.allocatePorts(epConfig, endpoint, config.DefaultBindingIP, d.config.EnableUserlandProxy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1101,9 +1129,9 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
|||
}
|
||||
|
||||
// Try removal of link. Discard error: link pair might have
|
||||
// already been deleted by sandbox delete.
|
||||
link, err := netlink.LinkByName(ep.srcName)
|
||||
if err == nil {
|
||||
// already been deleted by sandbox delete. Make sure defer
|
||||
// does not see this error either.
|
||||
if link, err := netlink.LinkByName(ep.srcName); err == nil {
|
||||
netlink.LinkDel(link)
|
||||
}
|
||||
|
||||
|
@ -1381,34 +1409,9 @@ func parseContainerOptions(cOptions map[string]interface{}) (*containerConfigura
|
|||
}
|
||||
}
|
||||
|
||||
// Generate a IEEE802 compliant MAC address from the given IP address.
|
||||
//
|
||||
// The generator is guaranteed to be consistent: the same IP will always yield the same
|
||||
// MAC address. This is to avoid ARP cache issues.
|
||||
func generateMacAddr(ip net.IP) net.HardwareAddr {
|
||||
hw := make(net.HardwareAddr, 6)
|
||||
|
||||
// The first byte of the MAC address has to comply with these rules:
|
||||
// 1. Unicast: Set the least-significant bit to 0.
|
||||
// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
|
||||
// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
|
||||
hw[0] = 0x02
|
||||
|
||||
// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
|
||||
// Since this address is locally administered, we can do whatever we want as long as
|
||||
// it doesn't conflict with other addresses.
|
||||
hw[1] = 0x42
|
||||
|
||||
// Insert the IP address into the last 32 bits of the MAC address.
|
||||
// This is a simple way to guarantee the address will be consistent and unique.
|
||||
copy(hw[2:], ip.To4())
|
||||
|
||||
return hw
|
||||
}
|
||||
|
||||
func electMacAddress(epConfig *endpointConfiguration, ip net.IP) net.HardwareAddr {
|
||||
if epConfig != nil && epConfig.MacAddress != nil {
|
||||
return epConfig.MacAddress
|
||||
}
|
||||
return generateMacAddr(ip)
|
||||
return netutils.GenerateMACFromIP(ip)
|
||||
}
|
||||
|
|
|
@ -115,17 +115,6 @@ func (eim ErrInvalidMtu) Error() string {
|
|||
// BadRequest denotes the type of this error
|
||||
func (eim ErrInvalidMtu) BadRequest() {}
|
||||
|
||||
// ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration
|
||||
// not enabled.
|
||||
type ErrIPFwdCfg struct{}
|
||||
|
||||
func (eipf *ErrIPFwdCfg) Error() string {
|
||||
return "unexpected request to enable IP Forwarding"
|
||||
}
|
||||
|
||||
// BadRequest denotes the type of this error
|
||||
func (eipf *ErrIPFwdCfg) BadRequest() {}
|
||||
|
||||
// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
|
||||
type ErrInvalidPort string
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ func linkContainers(action, parentIP, childIP string, ports []types.TransportPor
|
|||
return InvalidLinkIPAddrError(childIP)
|
||||
}
|
||||
|
||||
chain := iptables.Chain{Name: DockerChain, Bridge: bridge}
|
||||
chain := iptables.ChainInfo{Name: DockerChain}
|
||||
for _, port := range ports {
|
||||
err := chain.Link(nfAction, ip1, ip2, int(port.Port), port.Proto.String())
|
||||
err := chain.Link(nfAction, ip1, ip2, int(port.Port), port.Proto.String(), bridge)
|
||||
if !ignoreErrors && err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -74,16 +76,6 @@ func ioctlAddToBridge(iface, master *net.Interface) error {
|
|||
return ifIoctBridge(iface, master, ioctlBrAddIf)
|
||||
}
|
||||
|
||||
func randMacAddr() string {
|
||||
hw := make(net.HardwareAddr, 6)
|
||||
for i := 0; i < 6; i++ {
|
||||
hw[i] = byte(rnd.Intn(255))
|
||||
}
|
||||
hw[0] &^= 0x1 // clear multicast bit
|
||||
hw[0] |= 0x2 // set local assignment bit (IEEE802)
|
||||
return hw.String()
|
||||
}
|
||||
|
||||
func ioctlSetMacAddress(name, addr string) error {
|
||||
if len(name) >= ifNameSize {
|
||||
return fmt.Errorf("Interface name %s too long", name)
|
||||
|
@ -133,7 +125,7 @@ func ioctlCreateBridge(name string, setMacAddr bool) error {
|
|||
return err
|
||||
}
|
||||
if setMacAddr {
|
||||
return ioctlSetMacAddress(name, randMacAddr())
|
||||
return ioctlSetMacAddress(name, netutils.GenerateRandomMAC().String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -57,6 +57,11 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
|
|||
bnd.HostIP = defHostIP
|
||||
}
|
||||
|
||||
// Adjust HostPortEnd if this is not a range.
|
||||
if bnd.HostPortEnd == 0 {
|
||||
bnd.HostPortEnd = bnd.HostPort
|
||||
}
|
||||
|
||||
// Construct the container side transport address
|
||||
container, err := bnd.ContainerAddr()
|
||||
if err != nil {
|
||||
|
@ -65,12 +70,12 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
|
|||
|
||||
// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
|
||||
for i := 0; i < maxAllocatePortAttempts; i++ {
|
||||
if host, err = n.portMapper.Map(container, bnd.HostIP, int(bnd.HostPort), ulPxyEnabled); err == nil {
|
||||
if host, err = n.portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
|
||||
break
|
||||
}
|
||||
// There is no point in immediately retrying to map an explicitly chosen port.
|
||||
if bnd.HostPort != 0 {
|
||||
logrus.Warnf("Failed to allocate and map port %d: %s", bnd.HostPort, err)
|
||||
logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
|
||||
break
|
||||
}
|
||||
logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
|
||||
|
|
|
@ -3,8 +3,13 @@ package bridge
|
|||
import "github.com/docker/libnetwork/iptables"
|
||||
|
||||
func (n *bridgeNetwork) setupFirewalld(config *networkConfiguration, i *bridgeInterface) error {
|
||||
d := n.driver
|
||||
d.Lock()
|
||||
driverConfig := d.config
|
||||
d.Unlock()
|
||||
|
||||
// Sanity check.
|
||||
if config.EnableIPTables == false {
|
||||
if driverConfig.EnableIPTables == false {
|
||||
return IPTableCfgError(config.BridgeName)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,15 +10,19 @@ const (
|
|||
ipv4ForwardConfPerm = 0644
|
||||
)
|
||||
|
||||
func setupIPForwarding(config *configuration) error {
|
||||
// Sanity Check
|
||||
if config.EnableIPForwarding == false {
|
||||
return &ErrIPFwdCfg{}
|
||||
func setupIPForwarding() error {
|
||||
// Get current IPv4 forward setup
|
||||
ipv4ForwardData, err := ioutil.ReadFile(ipv4ForwardConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IP forwarding setup: %v", err)
|
||||
}
|
||||
|
||||
// Enable IPv4 forwarding
|
||||
if err := ioutil.WriteFile(ipv4ForwardConf, []byte{'1', '\n'}, ipv4ForwardConfPerm); err != nil {
|
||||
return fmt.Errorf("Setup IP forwarding failed: %v", err)
|
||||
// Enable IPv4 forwarding only if it is not already enabled
|
||||
if ipv4ForwardData[0] != '1' {
|
||||
// Enable IPv4 forwarding
|
||||
if err := ioutil.WriteFile(ipv4ForwardConf, []byte{'1', '\n'}, ipv4ForwardConfPerm); err != nil {
|
||||
return fmt.Errorf("Setup IP forwarding failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
@ -13,33 +14,77 @@ const (
|
|||
DockerChain = "DOCKER"
|
||||
)
|
||||
|
||||
func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInterface) error {
|
||||
func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, error) {
|
||||
// Sanity check.
|
||||
if config.EnableIPTables == false {
|
||||
return IPTableCfgError(config.BridgeName)
|
||||
return nil, nil, fmt.Errorf("Cannot create new chains, EnableIPTable is disabled")
|
||||
}
|
||||
|
||||
hairpinMode := !config.EnableUserlandProxy
|
||||
|
||||
natChain, err := iptables.NewChain(DockerChain, iptables.Nat, hairpinMode)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Failed to create NAT chain: %s", err.Error())
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err := iptables.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
|
||||
logrus.Warnf("Failed on removing iptables NAT chain on cleanup: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
filterChain, err := iptables.NewChain(DockerChain, iptables.Filter, hairpinMode)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Failed to create FILTER chain: %s", err.Error())
|
||||
}
|
||||
|
||||
return natChain, filterChain, nil
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInterface) error {
|
||||
d := n.driver
|
||||
d.Lock()
|
||||
driverConfig := d.config
|
||||
d.Unlock()
|
||||
|
||||
// Sanity check.
|
||||
if driverConfig.EnableIPTables == false {
|
||||
return fmt.Errorf("Cannot program chains, EnableIPTable is disabled")
|
||||
}
|
||||
|
||||
// Pickup this configuraton option from driver
|
||||
hairpinMode := !driverConfig.EnableUserlandProxy
|
||||
|
||||
addrv4, _, err := netutils.GetIfaceAddr(config.BridgeName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to setup IP tables, cannot acquire Interface address: %s", err.Error())
|
||||
}
|
||||
if err = setupIPTablesInternal(config.BridgeName, addrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
|
||||
ipnet := addrv4.(*net.IPNet)
|
||||
maskedAddrv4 := &net.IPNet{
|
||||
IP: ipnet.IP.Mask(ipnet.Mask),
|
||||
Mask: ipnet.Mask,
|
||||
}
|
||||
if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
|
||||
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
||||
}
|
||||
|
||||
_, err = iptables.NewChain(DockerChain, config.BridgeName, iptables.Nat, hairpinMode)
|
||||
natChain, filterChain, err := n.getDriverChains()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create NAT chain: %s", err.Error())
|
||||
return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
|
||||
}
|
||||
|
||||
chain, err := iptables.NewChain(DockerChain, config.BridgeName, iptables.Filter, hairpinMode)
|
||||
err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create FILTER chain: %s", err.Error())
|
||||
return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
||||
}
|
||||
|
||||
n.portMapper.SetIptablesChain(chain)
|
||||
err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
||||
}
|
||||
|
||||
n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -131,10 +131,16 @@ func setupGatewayIPv4(config *networkConfiguration, i *bridgeInterface) error {
|
|||
}
|
||||
|
||||
func setupLoopbackAdressesRouting(config *networkConfiguration, i *bridgeInterface) error {
|
||||
// Enable loopback adresses routing
|
||||
sysPath := filepath.Join("/proc/sys/net/ipv4/conf", config.BridgeName, "route_localnet")
|
||||
if err := ioutil.WriteFile(sysPath, []byte{'1', '\n'}, 0644); err != nil {
|
||||
return fmt.Errorf("Unable to enable local routing for hairpin mode: %v", err)
|
||||
ipv4LoRoutingData, err := ioutil.ReadFile(sysPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IPv4 local routing setup: %v", err)
|
||||
}
|
||||
// Enable loopback adresses routing only if it isn't already enabled
|
||||
if ipv4LoRoutingData[0] != '1' {
|
||||
if err := ioutil.WriteFile(sysPath, []byte{'1', '\n'}, 0644); err != nil {
|
||||
return fmt.Errorf("Unable to enable local routing for hairpin mode: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -12,8 +12,10 @@ import (
|
|||
var bridgeIPv6 *net.IPNet
|
||||
|
||||
const (
|
||||
bridgeIPv6Str = "fe80::1/64"
|
||||
ipv6ForwardConfPerm = 0644
|
||||
bridgeIPv6Str = "fe80::1/64"
|
||||
ipv6ForwardConfPerm = 0644
|
||||
ipv6ForwardConfDefault = "/proc/sys/net/ipv6/conf/default/forwarding"
|
||||
ipv6ForwardConfAll = "/proc/sys/net/ipv6/conf/all/forwarding"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -27,10 +29,16 @@ func init() {
|
|||
}
|
||||
|
||||
func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
|
||||
// Enable IPv6 on the bridge
|
||||
procFile := "/proc/sys/net/ipv6/conf/" + config.BridgeName + "/disable_ipv6"
|
||||
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
|
||||
ipv6BridgeData, err := ioutil.ReadFile(procFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IPv6 setup for bridge %v: %v", config.BridgeName, err)
|
||||
}
|
||||
// Enable IPv6 on the bridge only if it isn't already enabled
|
||||
if ipv6BridgeData[0] != '0' {
|
||||
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
_, addrsv6, err := i.addresses()
|
||||
|
@ -70,12 +78,29 @@ func setupGatewayIPv6(config *networkConfiguration, i *bridgeInterface) error {
|
|||
}
|
||||
|
||||
func setupIPv6Forwarding(config *networkConfiguration, i *bridgeInterface) error {
|
||||
// Enable IPv6 forwarding
|
||||
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
logrus.Warnf("Unable to enable IPv6 default forwarding: %v", err)
|
||||
// Get current IPv6 default forwarding setup
|
||||
ipv6ForwardDataDefault, err := ioutil.ReadFile(ipv6ForwardConfDefault)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IPv6 default forwarding setup: %v", err)
|
||||
}
|
||||
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
logrus.Warnf("Unable to enable IPv6 all forwarding: %v", err)
|
||||
// Enable IPv6 default forwarding only if it is not already enabled
|
||||
if ipv6ForwardDataDefault[0] != '1' {
|
||||
if err := ioutil.WriteFile(ipv6ForwardConfDefault, []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
logrus.Warnf("Unable to enable IPv6 default forwarding: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get current IPv6 all forwarding setup
|
||||
ipv6ForwardDataAll, err := ioutil.ReadFile(ipv6ForwardConfAll)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read IPv6 all forwarding setup: %v", err)
|
||||
}
|
||||
// Enable IPv6 all forwarding only if it is not already enabled
|
||||
if ipv6ForwardDataAll[0] != '1' {
|
||||
if err := ioutil.WriteFile(ipv6ForwardConfAll, []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
|
||||
logrus.Warnf("Unable to enable IPv6 all forwarding: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ type network struct {
|
|||
vxlanName string
|
||||
driver *driver
|
||||
joinCnt int
|
||||
once *sync.Once
|
||||
initEpoch int
|
||||
initErr error
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -42,6 +45,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
id: id,
|
||||
driver: d,
|
||||
endpoints: endpointTable{},
|
||||
once: &sync.Once{},
|
||||
}
|
||||
|
||||
n.gw = bridgeIP.IP
|
||||
|
@ -77,10 +81,26 @@ func (n *network) joinSandbox() error {
|
|||
n.Unlock()
|
||||
return nil
|
||||
}
|
||||
n.joinCnt++
|
||||
n.Unlock()
|
||||
|
||||
return n.initSandbox()
|
||||
// If there is a race between two go routines here only one will win
|
||||
// the other will wait.
|
||||
n.once.Do(func() {
|
||||
// save the error status of initSandbox in n.initErr so that
|
||||
// all the racing go routines are able to know the status.
|
||||
n.initErr = n.initSandbox()
|
||||
})
|
||||
|
||||
// Increment joinCnt in all the goroutines only when the one time initSandbox
|
||||
// was a success.
|
||||
n.Lock()
|
||||
if n.initErr == nil {
|
||||
n.joinCnt++
|
||||
}
|
||||
err := n.initErr
|
||||
n.Unlock()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *network) leaveSandbox() {
|
||||
|
@ -90,6 +110,11 @@ func (n *network) leaveSandbox() {
|
|||
n.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// We are about to destroy sandbox since the container is leaving the network
|
||||
// Reinitialize the once variable so that we will be able to trigger one time
|
||||
// sandbox initialization(again) when another container joins subsequently.
|
||||
n.once = &sync.Once{}
|
||||
n.Unlock()
|
||||
|
||||
n.destroySandbox()
|
||||
|
@ -111,7 +136,12 @@ func (n *network) destroySandbox() {
|
|||
}
|
||||
|
||||
func (n *network) initSandbox() error {
|
||||
sbox, err := sandbox.NewSandbox(sandbox.GenerateKey(string(n.id)), true)
|
||||
n.Lock()
|
||||
n.initEpoch++
|
||||
n.Unlock()
|
||||
|
||||
sbox, err := sandbox.NewSandbox(
|
||||
sandbox.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+string(n.id)), true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create network sandbox: %v", err)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
func validateID(nid, eid types.UUID) error {
|
||||
|
@ -54,7 +55,7 @@ func createVxlan(vni uint32) (string, error) {
|
|||
LinkAttrs: netlink.LinkAttrs{Name: name},
|
||||
VxlanId: int(vni),
|
||||
Learning: true,
|
||||
Port: vxlanPort,
|
||||
Port: int(nl.Swap16(vxlanPort)), //network endian order
|
||||
Proxy: true,
|
||||
L3miss: true,
|
||||
L2miss: true,
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
Package api represents all requests and responses suitable for conversation
|
||||
with a remote driver.
|
||||
*/
|
||||
package api
|
||||
|
||||
import "net"
|
||||
|
||||
// Response is the basic response structure used in all responses.
|
||||
type Response struct {
|
||||
Err string
|
||||
}
|
||||
|
||||
// GetError returns the error from the response, if any.
|
||||
func (r *Response) GetError() string {
|
||||
return r.Err
|
||||
}
|
||||
|
||||
// CreateNetworkRequest requests a new network.
|
||||
type CreateNetworkRequest struct {
|
||||
// A network ID that remote plugins are expected to store for future
|
||||
// reference.
|
||||
NetworkID string
|
||||
|
||||
// A free form map->object interface for communication of options.
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
// CreateNetworkResponse is the response to the CreateNetworkRequest.
|
||||
type CreateNetworkResponse struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// DeleteNetworkRequest is the request to delete an existing network.
|
||||
type DeleteNetworkRequest struct {
|
||||
// The ID of the network to delete.
|
||||
NetworkID string
|
||||
}
|
||||
|
||||
// DeleteNetworkResponse is the response to a request for deleting a network.
|
||||
type DeleteNetworkResponse struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// CreateEndpointRequest is the request to create an endpoint within a network.
|
||||
type CreateEndpointRequest struct {
|
||||
// Provided at create time, this will be the network id referenced.
|
||||
NetworkID string
|
||||
// The ID of the endpoint for later reference.
|
||||
EndpointID string
|
||||
Interfaces []*EndpointInterface
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
// EndpointInterface represents an interface endpoint.
|
||||
type EndpointInterface struct {
|
||||
ID int
|
||||
Address string
|
||||
AddressIPv6 string
|
||||
MacAddress string
|
||||
}
|
||||
|
||||
// CreateEndpointResponse is the response to the CreateEndpoint action.
|
||||
type CreateEndpointResponse struct {
|
||||
Response
|
||||
Interfaces []*EndpointInterface
|
||||
}
|
||||
|
||||
// Interface is the representation of a linux interface.
|
||||
type Interface struct {
|
||||
ID int
|
||||
Address *net.IPNet
|
||||
AddressIPv6 *net.IPNet
|
||||
MacAddress net.HardwareAddr
|
||||
}
|
||||
|
||||
// DeleteEndpointRequest describes the API for deleting an endpoint.
|
||||
type DeleteEndpointRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
// DeleteEndpointResponse is the response to the DeleteEndpoint action.
|
||||
type DeleteEndpointResponse struct {
|
||||
Response
|
||||
}
|
||||
|
||||
// EndpointInfoRequest retrieves information about the endpoint from the network driver.
|
||||
type EndpointInfoRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
// EndpointInfoResponse is the response to an EndpointInfoRequest.
|
||||
type EndpointInfoResponse struct {
|
||||
Response
|
||||
Value map[string]interface{}
|
||||
}
|
||||
|
||||
// JoinRequest describes the API for joining an endpoint to a sandbox.
|
||||
type JoinRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
SandboxKey string
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
// InterfaceName is the struct represetation of a pair of devices with source
|
||||
// and destination, for the purposes of putting an endpoint into a container.
|
||||
type InterfaceName struct {
|
||||
SrcName string
|
||||
DstName string
|
||||
DstPrefix string
|
||||
}
|
||||
|
||||
// StaticRoute is the plain JSON representation of a static route.
|
||||
type StaticRoute struct {
|
||||
Destination string
|
||||
RouteType int
|
||||
NextHop string
|
||||
InterfaceID int
|
||||
}
|
||||
|
||||
// JoinResponse is the response to a JoinRequest.
|
||||
type JoinResponse struct {
|
||||
Response
|
||||
InterfaceNames []*InterfaceName
|
||||
Gateway string
|
||||
GatewayIPv6 string
|
||||
HostsPath string
|
||||
ResolvConfPath string
|
||||
StaticRoutes []StaticRoute
|
||||
}
|
||||
|
||||
// LeaveRequest describes the API for detaching an endpoint from a sandbox.
|
||||
type LeaveRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
// LeaveResponse is the answer to LeaveRequest.
|
||||
type LeaveResponse struct {
|
||||
Response
|
||||
}
|
|
@ -7,6 +7,7 @@ import (
|
|||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/drivers/remote/api"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
|
@ -15,6 +16,10 @@ type driver struct {
|
|||
networkType string
|
||||
}
|
||||
|
||||
type maybeError interface {
|
||||
GetError() string
|
||||
}
|
||||
|
||||
func newDriver(name string, client *plugins.Client) driverapi.Driver {
|
||||
return &driver{networkType: name, endpoint: client}
|
||||
}
|
||||
|
@ -46,23 +51,23 @@ func (d *driver) call(methodName string, arg interface{}, retVal maybeError) err
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e := retVal.getError(); e != "" {
|
||||
if e := retVal.GetError(); e != "" {
|
||||
return fmt.Errorf("remote: %s", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id types.UUID, options map[string]interface{}) error {
|
||||
create := &createNetworkRequest{
|
||||
create := &api.CreateNetworkRequest{
|
||||
NetworkID: string(id),
|
||||
Options: options,
|
||||
}
|
||||
return d.call("CreateNetwork", create, &createNetworkResponse{})
|
||||
return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||
delete := &deleteNetworkRequest{NetworkID: string(nid)}
|
||||
return d.call("DeleteNetwork", delete, &deleteNetworkResponse{})
|
||||
delete := &api.DeleteNetworkRequest{NetworkID: string(nid)}
|
||||
return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
|
@ -70,29 +75,29 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
return fmt.Errorf("must not be called with nil EndpointInfo")
|
||||
}
|
||||
|
||||
reqIfaces := make([]*endpointInterface, len(epInfo.Interfaces()))
|
||||
reqIfaces := make([]*api.EndpointInterface, len(epInfo.Interfaces()))
|
||||
for i, iface := range epInfo.Interfaces() {
|
||||
addr4 := iface.Address()
|
||||
addr6 := iface.AddressIPv6()
|
||||
reqIfaces[i] = &endpointInterface{
|
||||
reqIfaces[i] = &api.EndpointInterface{
|
||||
ID: iface.ID(),
|
||||
Address: addr4.String(),
|
||||
AddressIPv6: addr6.String(),
|
||||
MacAddress: iface.MacAddress().String(),
|
||||
}
|
||||
}
|
||||
create := &createEndpointRequest{
|
||||
create := &api.CreateEndpointRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
Interfaces: reqIfaces,
|
||||
Options: epOptions,
|
||||
}
|
||||
var res createEndpointResponse
|
||||
var res api.CreateEndpointResponse
|
||||
if err := d.call("CreateEndpoint", create, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ifaces, err := res.parseInterfaces()
|
||||
ifaces, err := parseInterfaces(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -125,19 +130,19 @@ func errorWithRollback(msg string, err error) error {
|
|||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||
delete := &deleteEndpointRequest{
|
||||
delete := &api.DeleteEndpointRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
}
|
||||
return d.call("DeleteEndpoint", delete, &deleteEndpointResponse{})
|
||||
return d.call("DeleteEndpoint", delete, &api.DeleteEndpointResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
||||
info := &endpointInfoRequest{
|
||||
info := &api.EndpointInfoRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
}
|
||||
var res endpointInfoResponse
|
||||
var res api.EndpointInfoResponse
|
||||
if err := d.call("EndpointOperInfo", info, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -146,14 +151,14 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
|
|||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
join := &joinRequest{
|
||||
join := &api.JoinRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
SandboxKey: sboxKey,
|
||||
Options: options,
|
||||
}
|
||||
var (
|
||||
res joinResponse
|
||||
res api.JoinResponse
|
||||
err error
|
||||
)
|
||||
if err = d.call("Join", join, &res); err != nil {
|
||||
|
@ -194,7 +199,7 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
|
|||
}
|
||||
}
|
||||
if len(res.StaticRoutes) > 0 {
|
||||
routes, err := res.parseStaticRoutes()
|
||||
routes, err := parseStaticRoutes(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -215,13 +220,74 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
|
|||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
||||
leave := &leaveRequest{
|
||||
leave := &api.LeaveRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
}
|
||||
return d.call("Leave", leave, &leaveResponse{})
|
||||
return d.call("Leave", leave, &api.LeaveResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return d.networkType
|
||||
}
|
||||
|
||||
func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
|
||||
var routes = make([]*types.StaticRoute, len(r.StaticRoutes))
|
||||
for i, inRoute := range r.StaticRoutes {
|
||||
var err error
|
||||
outRoute := &types.StaticRoute{InterfaceID: inRoute.InterfaceID, RouteType: inRoute.RouteType}
|
||||
|
||||
if inRoute.Destination != "" {
|
||||
if outRoute.Destination, err = toAddr(inRoute.Destination); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if inRoute.NextHop != "" {
|
||||
outRoute.NextHop = net.ParseIP(inRoute.NextHop)
|
||||
if outRoute.NextHop == nil {
|
||||
return nil, fmt.Errorf("failed to parse nexthop IP %s", inRoute.NextHop)
|
||||
}
|
||||
}
|
||||
|
||||
routes[i] = outRoute
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
// parseInterfaces validates all the parameters of an Interface and returns them.
|
||||
func parseInterfaces(r api.CreateEndpointResponse) ([]*api.Interface, error) {
|
||||
var (
|
||||
Interfaces = make([]*api.Interface, len(r.Interfaces))
|
||||
)
|
||||
for i, inIf := range r.Interfaces {
|
||||
var err error
|
||||
outIf := &api.Interface{ID: inIf.ID}
|
||||
if inIf.Address != "" {
|
||||
if outIf.Address, err = toAddr(inIf.Address); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if inIf.AddressIPv6 != "" {
|
||||
if outIf.AddressIPv6, err = toAddr(inIf.AddressIPv6); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if inIf.MacAddress != "" {
|
||||
if outIf.MacAddress, err = net.ParseMAC(inIf.MacAddress); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
Interfaces[i] = outIf
|
||||
}
|
||||
return Interfaces, nil
|
||||
}
|
||||
|
||||
func toAddr(ipAddr string) (*net.IPNet, error) {
|
||||
ip, ipnet, err := net.ParseCIDR(ipAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipnet.IP = ip
|
||||
return ipnet, nil
|
||||
}
|
||||
|
|
|
@ -1,178 +0,0 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
type response struct {
|
||||
Err string
|
||||
}
|
||||
|
||||
type maybeError interface {
|
||||
getError() string
|
||||
}
|
||||
|
||||
func (r *response) getError() string {
|
||||
return r.Err
|
||||
}
|
||||
|
||||
type createNetworkRequest struct {
|
||||
NetworkID string
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
type createNetworkResponse struct {
|
||||
response
|
||||
}
|
||||
|
||||
type deleteNetworkRequest struct {
|
||||
NetworkID string
|
||||
}
|
||||
|
||||
type deleteNetworkResponse struct {
|
||||
response
|
||||
}
|
||||
|
||||
type createEndpointRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
Interfaces []*endpointInterface
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
type endpointInterface struct {
|
||||
ID int
|
||||
Address string
|
||||
AddressIPv6 string
|
||||
MacAddress string
|
||||
}
|
||||
|
||||
type staticRoute struct {
|
||||
Destination string
|
||||
RouteType int
|
||||
NextHop string
|
||||
InterfaceID int
|
||||
}
|
||||
|
||||
type createEndpointResponse struct {
|
||||
response
|
||||
Interfaces []*endpointInterface
|
||||
}
|
||||
|
||||
func toAddr(ipAddr string) (*net.IPNet, error) {
|
||||
ip, ipnet, err := net.ParseCIDR(ipAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipnet.IP = ip
|
||||
return ipnet, nil
|
||||
}
|
||||
|
||||
type iface struct {
|
||||
ID int
|
||||
Address *net.IPNet
|
||||
AddressIPv6 *net.IPNet
|
||||
MacAddress net.HardwareAddr
|
||||
}
|
||||
|
||||
func (r *createEndpointResponse) parseInterfaces() ([]*iface, error) {
|
||||
var ifaces = make([]*iface, len(r.Interfaces))
|
||||
for i, inIf := range r.Interfaces {
|
||||
var err error
|
||||
outIf := &iface{ID: inIf.ID}
|
||||
if inIf.Address != "" {
|
||||
if outIf.Address, err = toAddr(inIf.Address); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if inIf.AddressIPv6 != "" {
|
||||
if outIf.AddressIPv6, err = toAddr(inIf.AddressIPv6); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if inIf.MacAddress != "" {
|
||||
if outIf.MacAddress, err = net.ParseMAC(inIf.MacAddress); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ifaces[i] = outIf
|
||||
}
|
||||
return ifaces, nil
|
||||
}
|
||||
|
||||
func (r *joinResponse) parseStaticRoutes() ([]*types.StaticRoute, error) {
|
||||
var routes = make([]*types.StaticRoute, len(r.StaticRoutes))
|
||||
for i, inRoute := range r.StaticRoutes {
|
||||
var err error
|
||||
outRoute := &types.StaticRoute{InterfaceID: inRoute.InterfaceID, RouteType: inRoute.RouteType}
|
||||
|
||||
if inRoute.Destination != "" {
|
||||
if outRoute.Destination, err = toAddr(inRoute.Destination); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if inRoute.NextHop != "" {
|
||||
outRoute.NextHop = net.ParseIP(inRoute.NextHop)
|
||||
if outRoute.NextHop == nil {
|
||||
return nil, fmt.Errorf("failed to parse nexthop IP %s", inRoute.NextHop)
|
||||
}
|
||||
}
|
||||
|
||||
routes[i] = outRoute
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
type deleteEndpointRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
type deleteEndpointResponse struct {
|
||||
response
|
||||
}
|
||||
|
||||
type endpointInfoRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
type endpointInfoResponse struct {
|
||||
response
|
||||
Value map[string]interface{}
|
||||
}
|
||||
|
||||
type joinRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
SandboxKey string
|
||||
Options map[string]interface{}
|
||||
}
|
||||
|
||||
type ifaceName struct {
|
||||
SrcName string
|
||||
DstPrefix string
|
||||
}
|
||||
|
||||
type joinResponse struct {
|
||||
response
|
||||
InterfaceNames []*ifaceName
|
||||
Gateway string
|
||||
GatewayIPv6 string
|
||||
StaticRoutes []*staticRoute
|
||||
HostsPath string
|
||||
ResolvConfPath string
|
||||
}
|
||||
|
||||
type leaveRequest struct {
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
type leaveResponse struct {
|
||||
response
|
||||
}
|
|
@ -297,12 +297,7 @@ func (ep *endpoint) processOptions(options ...EndpointOption) {
|
|||
}
|
||||
|
||||
func createBasePath(dir string) error {
|
||||
err := os.MkdirAll(dir, 0644)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return os.MkdirAll(dir, 0644)
|
||||
}
|
||||
|
||||
func createFile(path string) error {
|
||||
|
|
|
@ -42,10 +42,9 @@ var (
|
|||
ErrIptablesNotFound = errors.New("Iptables not found")
|
||||
)
|
||||
|
||||
// Chain defines the iptables chain.
|
||||
type Chain struct {
|
||||
// ChainInfo defines the iptables chain.
|
||||
type ChainInfo struct {
|
||||
Name string
|
||||
Bridge string
|
||||
Table Table
|
||||
HairpinMode bool
|
||||
}
|
||||
|
@ -74,14 +73,12 @@ func initCheck() error {
|
|||
}
|
||||
|
||||
// NewChain adds a new chain to ip table.
|
||||
func NewChain(name, bridge string, table Table, hairpinMode bool) (*Chain, error) {
|
||||
c := &Chain{
|
||||
func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
|
||||
c := &ChainInfo{
|
||||
Name: name,
|
||||
Bridge: bridge,
|
||||
Table: table,
|
||||
HairpinMode: hairpinMode,
|
||||
}
|
||||
|
||||
if string(c.Table) == "" {
|
||||
c.Table = Filter
|
||||
}
|
||||
|
@ -94,8 +91,16 @@ func NewChain(name, bridge string, table Table, hairpinMode bool) (*Chain, error
|
|||
return nil, fmt.Errorf("Could not create %s/%s chain: %s", c.Table, c.Name, output)
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
switch table {
|
||||
// ProgramChain is used to add rules to a chain
|
||||
func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode bool) error {
|
||||
if c.Name == "" {
|
||||
return fmt.Errorf("Could not program chain, missing chain name.")
|
||||
}
|
||||
|
||||
switch c.Table {
|
||||
case Nat:
|
||||
preroute := []string{
|
||||
"-m", "addrtype",
|
||||
|
@ -103,7 +108,7 @@ func NewChain(name, bridge string, table Table, hairpinMode bool) (*Chain, error
|
|||
"-j", c.Name}
|
||||
if !Exists(Nat, "PREROUTING", preroute...) {
|
||||
if err := c.Prerouting(Append, preroute...); err != nil {
|
||||
return nil, fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err)
|
||||
return fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err)
|
||||
}
|
||||
}
|
||||
output := []string{
|
||||
|
@ -115,28 +120,32 @@ func NewChain(name, bridge string, table Table, hairpinMode bool) (*Chain, error
|
|||
}
|
||||
if !Exists(Nat, "OUTPUT", output...) {
|
||||
if err := c.Output(Append, output...); err != nil {
|
||||
return nil, fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err)
|
||||
return fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err)
|
||||
}
|
||||
}
|
||||
case Filter:
|
||||
if bridgeName == "" {
|
||||
return fmt.Errorf("Could not program chain %s/%s, missing bridge name.",
|
||||
c.Table, c.Name)
|
||||
}
|
||||
link := []string{
|
||||
"-o", c.Bridge,
|
||||
"-o", bridgeName,
|
||||
"-j", c.Name}
|
||||
if !Exists(Filter, "FORWARD", link...) {
|
||||
insert := append([]string{string(Insert), "FORWARD"}, link...)
|
||||
if output, err := Raw(insert...); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
} else if len(output) != 0 {
|
||||
return nil, fmt.Errorf("Could not create linking rule to %s/%s: %s", c.Table, c.Name, output)
|
||||
return fmt.Errorf("Could not create linking rule to %s/%s: %s", c.Table, c.Name, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveExistingChain removes existing chain from the table.
|
||||
func RemoveExistingChain(name string, table Table) error {
|
||||
c := &Chain{
|
||||
c := &ChainInfo{
|
||||
Name: name,
|
||||
Table: table,
|
||||
}
|
||||
|
@ -147,7 +156,7 @@ func RemoveExistingChain(name string, table Table) error {
|
|||
}
|
||||
|
||||
// Forward adds forwarding rule to 'filter' table and corresponding nat rule to 'nat' table.
|
||||
func (c *Chain) Forward(action Action, ip net.IP, port int, proto, destAddr string, destPort int) error {
|
||||
func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr string, destPort int, bridgeName string) error {
|
||||
daddr := ip.String()
|
||||
if ip.IsUnspecified() {
|
||||
// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
|
||||
|
@ -162,7 +171,7 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, destAddr stri
|
|||
"-j", "DNAT",
|
||||
"--to-destination", net.JoinHostPort(destAddr, strconv.Itoa(destPort))}
|
||||
if !c.HairpinMode {
|
||||
args = append(args, "!", "-i", c.Bridge)
|
||||
args = append(args, "!", "-i", bridgeName)
|
||||
}
|
||||
if output, err := Raw(args...); err != nil {
|
||||
return err
|
||||
|
@ -171,8 +180,8 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, destAddr stri
|
|||
}
|
||||
|
||||
if output, err := Raw("-t", string(Filter), string(action), c.Name,
|
||||
"!", "-i", c.Bridge,
|
||||
"-o", c.Bridge,
|
||||
"!", "-i", bridgeName,
|
||||
"-o", bridgeName,
|
||||
"-p", proto,
|
||||
"-d", destAddr,
|
||||
"--dport", strconv.Itoa(destPort),
|
||||
|
@ -198,9 +207,9 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, destAddr stri
|
|||
|
||||
// Link adds reciprocal ACCEPT rule for two supplied IP addresses.
|
||||
// Traffic is allowed from ip1 to ip2 and vice-versa
|
||||
func (c *Chain) Link(action Action, ip1, ip2 net.IP, port int, proto string) error {
|
||||
func (c *ChainInfo) Link(action Action, ip1, ip2 net.IP, port int, proto string, bridgeName string) error {
|
||||
if output, err := Raw("-t", string(Filter), string(action), c.Name,
|
||||
"-i", c.Bridge, "-o", c.Bridge,
|
||||
"-i", bridgeName, "-o", bridgeName,
|
||||
"-p", proto,
|
||||
"-s", ip1.String(),
|
||||
"-d", ip2.String(),
|
||||
|
@ -211,7 +220,7 @@ func (c *Chain) Link(action Action, ip1, ip2 net.IP, port int, proto string) err
|
|||
return fmt.Errorf("Error iptables forward: %s", output)
|
||||
}
|
||||
if output, err := Raw("-t", string(Filter), string(action), c.Name,
|
||||
"-i", c.Bridge, "-o", c.Bridge,
|
||||
"-i", bridgeName, "-o", bridgeName,
|
||||
"-p", proto,
|
||||
"-s", ip2.String(),
|
||||
"-d", ip1.String(),
|
||||
|
@ -225,7 +234,7 @@ func (c *Chain) Link(action Action, ip1, ip2 net.IP, port int, proto string) err
|
|||
}
|
||||
|
||||
// Prerouting adds linking rule to nat/PREROUTING chain.
|
||||
func (c *Chain) Prerouting(action Action, args ...string) error {
|
||||
func (c *ChainInfo) Prerouting(action Action, args ...string) error {
|
||||
a := []string{"-t", string(Nat), string(action), "PREROUTING"}
|
||||
if len(args) > 0 {
|
||||
a = append(a, args...)
|
||||
|
@ -239,7 +248,7 @@ func (c *Chain) Prerouting(action Action, args ...string) error {
|
|||
}
|
||||
|
||||
// Output adds linking rule to an OUTPUT chain.
|
||||
func (c *Chain) Output(action Action, args ...string) error {
|
||||
func (c *ChainInfo) Output(action Action, args ...string) error {
|
||||
a := []string{"-t", string(c.Table), string(action), "OUTPUT"}
|
||||
if len(args) > 0 {
|
||||
a = append(a, args...)
|
||||
|
@ -253,7 +262,7 @@ func (c *Chain) Output(action Action, args ...string) error {
|
|||
}
|
||||
|
||||
// Remove removes the chain.
|
||||
func (c *Chain) Remove() error {
|
||||
func (c *ChainInfo) Remove() error {
|
||||
// Ignore errors - This could mean the chains were never set up
|
||||
if c.Table == Nat {
|
||||
c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name)
|
||||
|
|
|
@ -122,26 +122,36 @@ func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
|
|||
return addrs4[0], addrs6, nil
|
||||
}
|
||||
|
||||
// GenerateRandomMAC returns a new 6-byte(48-bit) hardware address (MAC)
|
||||
func GenerateRandomMAC() net.HardwareAddr {
|
||||
func genMAC(ip net.IP) net.HardwareAddr {
|
||||
hw := make(net.HardwareAddr, 6)
|
||||
// The first byte of the MAC address has to comply with these rules:
|
||||
// 1. Unicast: Set the least-significant bit to 0.
|
||||
// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
|
||||
// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
|
||||
hw[0] = 0x02
|
||||
// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
|
||||
// Since this address is locally administered, we can do whatever we want as long as
|
||||
// it doesn't conflict with other addresses.
|
||||
hw[1] = 0x42
|
||||
// Randomly generate the remaining 4 bytes (2^32)
|
||||
_, err := rand.Read(hw[2:])
|
||||
if err != nil {
|
||||
return nil
|
||||
// Fill the remaining 4 bytes based on the input
|
||||
if ip == nil {
|
||||
rand.Read(hw[2:])
|
||||
} else {
|
||||
copy(hw[2:], ip.To4())
|
||||
}
|
||||
return hw
|
||||
}
|
||||
|
||||
// GenerateRandomMAC returns a new 6-byte(48-bit) hardware address (MAC)
|
||||
func GenerateRandomMAC() net.HardwareAddr {
|
||||
return genMAC(nil)
|
||||
}
|
||||
|
||||
// GenerateMACFromIP returns a locally administered MAC address where the 4 least
|
||||
// significant bytes are derived from the IPv4 address.
|
||||
func GenerateMACFromIP(ip net.IP) net.HardwareAddr {
|
||||
return genMAC(ip)
|
||||
}
|
||||
|
||||
// GenerateRandomName returns a new name joined with a prefix. This size
|
||||
// specified is used to truncate the randomly generated value
|
||||
func GenerateRandomName(prefix string, size int) (string, error) {
|
||||
|
|
|
@ -70,10 +70,15 @@ type (
|
|||
Begin int
|
||||
End int
|
||||
}
|
||||
portRange struct {
|
||||
begin int
|
||||
end int
|
||||
last int
|
||||
}
|
||||
portMap struct {
|
||||
p map[int]struct{}
|
||||
begin, end int
|
||||
last int
|
||||
p map[int]struct{}
|
||||
defaultRange string
|
||||
portRanges map[string]*portRange
|
||||
}
|
||||
protoMap map[string]*portMap
|
||||
)
|
||||
|
@ -123,8 +128,17 @@ func getDynamicPortRange() (start int, end int, err error) {
|
|||
|
||||
// RequestPort requests new port from global ports pool for specified ip and proto.
|
||||
// If port is 0 it returns first free port. Otherwise it checks port availability
|
||||
// in pool and return that port or error if port is already busy.
|
||||
// in proto's pool and returns that port or error if port is already busy.
|
||||
func (p *PortAllocator) RequestPort(ip net.IP, proto string, port int) (int, error) {
|
||||
return p.RequestPortInRange(ip, proto, port, port)
|
||||
}
|
||||
|
||||
// RequestPortInRange requests new port from global ports pool for specified ip and proto.
|
||||
// If portStart and portEnd are 0 it returns the first free port in the default ephemeral range.
|
||||
// If portStart != portEnd it returns the first free port in the requested range.
|
||||
// Otherwise (portStart == portEnd) it checks port availability in the requested proto's port-pool
|
||||
// and returns that port or error if port is already busy.
|
||||
func (p *PortAllocator) RequestPortInRange(ip net.IP, proto string, portStart, portEnd int) (int, error) {
|
||||
p.mutex.Lock()
|
||||
defer p.mutex.Unlock()
|
||||
|
||||
|
@ -146,15 +160,15 @@ func (p *PortAllocator) RequestPort(ip net.IP, proto string, port int) (int, err
|
|||
p.ipMap[ipstr] = protomap
|
||||
}
|
||||
mapping := protomap[proto]
|
||||
if port > 0 {
|
||||
if _, ok := mapping.p[port]; !ok {
|
||||
mapping.p[port] = struct{}{}
|
||||
return port, nil
|
||||
if portStart > 0 && portStart == portEnd {
|
||||
if _, ok := mapping.p[portStart]; !ok {
|
||||
mapping.p[portStart] = struct{}{}
|
||||
return portStart, nil
|
||||
}
|
||||
return 0, newErrPortAlreadyAllocated(ipstr, port)
|
||||
return 0, newErrPortAlreadyAllocated(ipstr, portStart)
|
||||
}
|
||||
|
||||
port, err := mapping.findPort()
|
||||
port, err := mapping.findPort(portStart, portEnd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -178,12 +192,15 @@ func (p *PortAllocator) ReleasePort(ip net.IP, proto string, port int) error {
|
|||
}
|
||||
|
||||
func (p *PortAllocator) newPortMap() *portMap {
|
||||
return &portMap{
|
||||
p: map[int]struct{}{},
|
||||
begin: p.Begin,
|
||||
end: p.End,
|
||||
last: p.End,
|
||||
defaultKey := getRangeKey(p.Begin, p.End)
|
||||
pm := &portMap{
|
||||
p: map[int]struct{}{},
|
||||
defaultRange: defaultKey,
|
||||
portRanges: map[string]*portRange{
|
||||
defaultKey: newPortRange(p.Begin, p.End),
|
||||
},
|
||||
}
|
||||
return pm
|
||||
}
|
||||
|
||||
// ReleaseAll releases all ports for all ips.
|
||||
|
@ -194,17 +211,58 @@ func (p *PortAllocator) ReleaseAll() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (pm *portMap) findPort() (int, error) {
|
||||
port := pm.last
|
||||
for i := 0; i <= pm.end-pm.begin; i++ {
|
||||
func getRangeKey(portStart, portEnd int) string {
|
||||
return fmt.Sprintf("%d-%d", portStart, portEnd)
|
||||
}
|
||||
|
||||
func newPortRange(portStart, portEnd int) *portRange {
|
||||
return &portRange{
|
||||
begin: portStart,
|
||||
end: portEnd,
|
||||
last: portEnd,
|
||||
}
|
||||
}
|
||||
|
||||
func (pm *portMap) getPortRange(portStart, portEnd int) (*portRange, error) {
|
||||
var key string
|
||||
if portStart == 0 && portEnd == 0 {
|
||||
key = pm.defaultRange
|
||||
} else {
|
||||
key = getRangeKey(portStart, portEnd)
|
||||
if portStart == portEnd ||
|
||||
portStart == 0 || portEnd == 0 ||
|
||||
portEnd < portStart {
|
||||
return nil, fmt.Errorf("invalid port range: %s", key)
|
||||
}
|
||||
}
|
||||
|
||||
// Return existing port range, if already known.
|
||||
if pr, exists := pm.portRanges[key]; exists {
|
||||
return pr, nil
|
||||
}
|
||||
|
||||
// Otherwise create a new port range.
|
||||
pr := newPortRange(portStart, portEnd)
|
||||
pm.portRanges[key] = pr
|
||||
return pr, nil
|
||||
}
|
||||
|
||||
func (pm *portMap) findPort(portStart, portEnd int) (int, error) {
|
||||
pr, err := pm.getPortRange(portStart, portEnd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
port := pr.last
|
||||
|
||||
for i := 0; i <= pr.end-pr.begin; i++ {
|
||||
port++
|
||||
if port > pm.end {
|
||||
port = pm.begin
|
||||
if port > pr.end {
|
||||
port = pr.begin
|
||||
}
|
||||
|
||||
if _, ok := pm.p[port]; !ok {
|
||||
pm.p[port] = struct{}{}
|
||||
pm.last = port
|
||||
pr.last = port
|
||||
return port, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ var (
|
|||
|
||||
// PortMapper manages the network address translation
|
||||
type PortMapper struct {
|
||||
chain *iptables.Chain
|
||||
chain *iptables.ChainInfo
|
||||
bridgeName string
|
||||
|
||||
// udp:ip:port
|
||||
currentMappings map[string]*mapping
|
||||
|
@ -54,12 +55,18 @@ func NewWithPortAllocator(allocator *portallocator.PortAllocator) *PortMapper {
|
|||
}
|
||||
|
||||
// SetIptablesChain sets the specified chain into portmapper
|
||||
func (pm *PortMapper) SetIptablesChain(c *iptables.Chain) {
|
||||
func (pm *PortMapper) SetIptablesChain(c *iptables.ChainInfo, bridgeName string) {
|
||||
pm.chain = c
|
||||
pm.bridgeName = bridgeName
|
||||
}
|
||||
|
||||
// Map maps the specified container transport address to the host's network address and transport port
|
||||
func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, useProxy bool) (host net.Addr, err error) {
|
||||
return pm.MapRange(container, hostIP, hostPort, hostPort, useProxy)
|
||||
}
|
||||
|
||||
// MapRange maps the specified container transport address to the host's network address and transport port range
|
||||
func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart, hostPortEnd int, useProxy bool) (host net.Addr, err error) {
|
||||
pm.lock.Lock()
|
||||
defer pm.lock.Unlock()
|
||||
|
||||
|
@ -72,7 +79,7 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
|
|||
switch container.(type) {
|
||||
case *net.TCPAddr:
|
||||
proto = "tcp"
|
||||
if allocatedHostPort, err = pm.Allocator.RequestPort(hostIP, proto, hostPort); err != nil {
|
||||
if allocatedHostPort, err = pm.Allocator.RequestPortInRange(hostIP, proto, hostPortStart, hostPortEnd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -89,7 +96,7 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
|
|||
}
|
||||
case *net.UDPAddr:
|
||||
proto = "udp"
|
||||
if allocatedHostPort, err = pm.Allocator.RequestPort(hostIP, proto, hostPort); err != nil {
|
||||
if allocatedHostPort, err = pm.Allocator.RequestPortInRange(hostIP, proto, hostPortStart, hostPortEnd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -215,5 +222,5 @@ func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net
|
|||
if pm.chain == nil {
|
||||
return nil
|
||||
}
|
||||
return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort)
|
||||
return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort, pm.bridgeName)
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ func init() {
|
|||
|
||||
func createBasePath() {
|
||||
err := os.MkdirAll(prefix, 0644)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
if err != nil {
|
||||
panic("Could not create net namespace path directory")
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,12 @@ func (t *TransportPort) GetCopy() TransportPort {
|
|||
|
||||
// PortBinding represent a port binding between the container and the host
|
||||
type PortBinding struct {
|
||||
Proto Protocol
|
||||
IP net.IP
|
||||
Port uint16
|
||||
HostIP net.IP
|
||||
HostPort uint16
|
||||
Proto Protocol
|
||||
IP net.IP
|
||||
Port uint16
|
||||
HostIP net.IP
|
||||
HostPort uint16
|
||||
HostPortEnd uint16
|
||||
}
|
||||
|
||||
// HostAddr returns the host side transport address
|
||||
|
@ -58,11 +59,12 @@ func (p PortBinding) ContainerAddr() (net.Addr, error) {
|
|||
// GetCopy returns a copy of this PortBinding structure instance
|
||||
func (p *PortBinding) GetCopy() PortBinding {
|
||||
return PortBinding{
|
||||
Proto: p.Proto,
|
||||
IP: GetIPCopy(p.IP),
|
||||
Port: p.Port,
|
||||
HostIP: GetIPCopy(p.HostIP),
|
||||
HostPort: p.HostPort,
|
||||
Proto: p.Proto,
|
||||
IP: GetIPCopy(p.IP),
|
||||
Port: p.Port,
|
||||
HostIP: GetIPCopy(p.HostIP),
|
||||
HostPort: p.HostPort,
|
||||
HostPortEnd: p.HostPortEnd,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +78,8 @@ func (p *PortBinding) Equal(o *PortBinding) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if p.Proto != o.Proto || p.Port != o.Port || p.HostPort != o.HostPort {
|
||||
if p.Proto != o.Proto || p.Port != o.Port ||
|
||||
p.HostPort != o.HostPort || p.HostPortEnd != o.HostPortEnd {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -39,8 +39,9 @@ func NativeEndian() binary.ByteOrder {
|
|||
var x uint32 = 0x01020304
|
||||
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
||||
nativeEndian = binary.BigEndian
|
||||
} else {
|
||||
nativeEndian = binary.LittleEndian
|
||||
}
|
||||
nativeEndian = binary.LittleEndian
|
||||
}
|
||||
return nativeEndian
|
||||
}
|
||||
|
|
|
@ -20,6 +20,15 @@ func NewRtMsg() *RtMsg {
|
|||
}
|
||||
}
|
||||
|
||||
func NewRtDelMsg() *RtMsg {
|
||||
return &RtMsg{
|
||||
RtMsg: syscall.RtMsg{
|
||||
Table: syscall.RT_TABLE_MAIN,
|
||||
Scope: syscall.RT_SCOPE_NOWHERE,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *RtMsg) Len() int {
|
||||
return syscall.SizeofRtMsg
|
||||
}
|
||||
|
|
|
@ -14,22 +14,21 @@ import (
|
|||
// Equivalent to: `ip route add $route`
|
||||
func RouteAdd(route *Route) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
return routeHandle(route, req)
|
||||
return routeHandle(route, req, nl.NewRtMsg())
|
||||
}
|
||||
|
||||
// RouteAdd will delete a route from the system.
|
||||
// Equivalent to: `ip route del $route`
|
||||
func RouteDel(route *Route) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
|
||||
return routeHandle(route, req)
|
||||
return routeHandle(route, req, nl.NewRtDelMsg())
|
||||
}
|
||||
|
||||
func routeHandle(route *Route, req *nl.NetlinkRequest) error {
|
||||
func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
|
||||
if (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil {
|
||||
return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil")
|
||||
}
|
||||
|
||||
msg := nl.NewRtMsg()
|
||||
msg.Scope = uint8(route.Scope)
|
||||
family := -1
|
||||
var rtAttrs []*nl.RtAttr
|
||||
|
|
Загрузка…
Ссылка в новой задаче