Vendoring libnetwork @ 9f0563ea8f430d8828553aac97161cbff4056436
Brings in:
* Support for overlay network driver in 3.10+ kernels
* Freebsd compilation fixes
* Remove .dockerinit dependency
* IPAM driver capability support
* Network internal mode support
* Misc. fixes
Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
| ... | ... |
@@ -16,7 +16,6 @@ network. Docker Engine supports multi-host networking out-of-the-box through the |
| 16 | 16 |
`overlay` network driver. Unlike `bridge` networks, overlay networks require |
| 17 | 17 |
some pre-existing conditions before you can create one. These conditions are: |
| 18 | 18 |
|
| 19 |
-* A host with a 3.16 kernel version or higher. |
|
| 20 | 19 |
* Access to a key-value store. Docker supports Consul, Etcd, and ZooKeeper (Distributed store) key-value stores. |
| 21 | 20 |
* A cluster of hosts with connectivity to the key-value store. |
| 22 | 21 |
* A properly configured Engine `daemon` on each host in the cluster. |
| ... | ... |
@@ -46,7 +45,7 @@ key-value stores. This example uses Consul. |
| 46 | 46 |
|
| 47 | 47 |
1. Log into a system prepared with the prerequisite Docker Engine, Docker Machine, and VirtualBox software. |
| 48 | 48 |
|
| 49 |
-2. Provision a VirtualBox machine called `mh-keystore`. |
|
| 49 |
+2. Provision a VirtualBox machine called `mh-keystore`. |
|
| 50 | 50 |
|
| 51 | 51 |
$ docker-machine create -d virtualbox mh-keystore |
| 52 | 52 |
|
| ... | ... |
@@ -23,7 +23,7 @@ clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://gith |
| 23 | 23 |
clone git github.com/docker/go-units v0.2.0 |
| 24 | 24 |
|
| 25 | 25 |
#get libnetwork packages |
| 26 |
-clone git github.com/docker/libnetwork bbd6e6d8ca1e7c9b42f6f53277b0bde72847ff90 |
|
| 26 |
+clone git github.com/docker/libnetwork 9f0563ea8f430d8828553aac97161cbff4056436 |
|
| 27 | 27 |
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| 28 | 28 |
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b |
| 29 | 29 |
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 |
| ... | ... |
@@ -121,7 +121,8 @@ type driverData struct {
|
| 121 | 121 |
} |
| 122 | 122 |
|
| 123 | 123 |
type ipamData struct {
|
| 124 |
- driver ipamapi.Ipam |
|
| 124 |
+ driver ipamapi.Ipam |
|
| 125 |
+ capability *ipamapi.Capability |
|
| 125 | 126 |
// default address spaces are provided by ipam driver at registration time |
| 126 | 127 |
defaultLocalAddressSpace, defaultGlobalAddressSpace string |
| 127 | 128 |
} |
| ... | ... |
@@ -306,7 +307,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, |
| 306 | 306 |
return nil |
| 307 | 307 |
} |
| 308 | 308 |
|
| 309 |
-func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
|
|
| 309 |
+func (c *controller) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
|
|
| 310 | 310 |
if !config.IsValidName(name) {
|
| 311 | 311 |
return ErrInvalidName(name) |
| 312 | 312 |
} |
| ... | ... |
@@ -322,7 +323,7 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error |
| 322 | 322 |
return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err)
|
| 323 | 323 |
} |
| 324 | 324 |
c.Lock() |
| 325 |
- c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS}
|
|
| 325 |
+ c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps}
|
|
| 326 | 326 |
c.Unlock() |
| 327 | 327 |
|
| 328 | 328 |
log.Debugf("Registering ipam driver: %q", name)
|
| ... | ... |
@@ -330,6 +331,14 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error |
| 330 | 330 |
return nil |
| 331 | 331 |
} |
| 332 | 332 |
|
| 333 |
+func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
|
|
| 334 |
+ return c.registerIpamDriver(name, driver, &ipamapi.Capability{})
|
|
| 335 |
+} |
|
| 336 |
+ |
|
| 337 |
+func (c *controller) RegisterIpamDriverWithCapabilities(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
|
|
| 338 |
+ return c.registerIpamDriver(name, driver, caps) |
|
| 339 |
+} |
|
| 340 |
+ |
|
| 333 | 341 |
// NewNetwork creates a new network of the specified network type. The options |
| 334 | 342 |
// are network specific and modeled in a generic way. |
| 335 | 343 |
func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
|
| ... | ... |
@@ -103,6 +103,9 @@ func (sb *sandbox) needDefaultGW() bool {
|
| 103 | 103 |
if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
|
| 104 | 104 |
continue |
| 105 | 105 |
} |
| 106 |
+ if ep.getNetwork().Internal() {
|
|
| 107 |
+ return false |
|
| 108 |
+ } |
|
| 106 | 109 |
if ep.joinInfo.disableGatewayService {
|
| 107 | 110 |
return false |
| 108 | 111 |
} |
| ... | ... |
@@ -490,6 +490,12 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati |
| 490 | 490 |
config.EnableIPv6 = val.(bool) |
| 491 | 491 |
} |
| 492 | 492 |
|
| 493 |
+ if val, ok := option[netlabel.Internal]; ok {
|
|
| 494 |
+ if internal, ok := val.(bool); ok && internal {
|
|
| 495 |
+ return nil, &driverapi.ErrNotImplemented{}
|
|
| 496 |
+ } |
|
| 497 |
+ } |
|
| 498 |
+ |
|
| 493 | 499 |
// Finally validate the configuration |
| 494 | 500 |
if err = config.Validate(); err != nil {
|
| 495 | 501 |
return nil, err |
| ... | ... |
@@ -62,6 +62,13 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
|
| 62 | 62 |
return nil |
| 63 | 63 |
} |
| 64 | 64 |
|
| 65 |
+ // Store and program user specified bridge network and network gateway |
|
| 66 |
+ i.bridgeIPv6 = config.AddressIPv6 |
|
| 67 |
+ i.gatewayIPv6 = config.AddressIPv6.IP |
|
| 68 |
+ if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: i.bridgeIPv6}); err != nil {
|
|
| 69 |
+ return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
|
|
| 70 |
+ } |
|
| 71 |
+ |
|
| 65 | 72 |
// Setting route to global IPv6 subnet |
| 66 | 73 |
logrus.Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
|
| 67 | 74 |
err = netlink.RouteAdd(&netlink.Route{
|
| 68 | 75 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,131 @@ |
| 0 |
+package overlay |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "sync" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/Sirupsen/logrus" |
|
| 7 |
+ "github.com/docker/libnetwork/iptables" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+const globalChain = "DOCKER-OVERLAY" |
|
| 11 |
+ |
|
| 12 |
+var filterOnce sync.Once |
|
| 13 |
+ |
|
| 14 |
+func rawIPTables(args ...string) error {
|
|
| 15 |
+ if output, err := iptables.Raw(args...); err != nil {
|
|
| 16 |
+ return fmt.Errorf("unable to add overlay filter: %v", err)
|
|
| 17 |
+ } else if len(output) != 0 {
|
|
| 18 |
+ return fmt.Errorf("unable to add overlay filter: %s", string(output))
|
|
| 19 |
+ } |
|
| 20 |
+ |
|
| 21 |
+ return nil |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+func chainExists(cname string) bool {
|
|
| 25 |
+ if _, err := iptables.Raw("-L", cname); err != nil {
|
|
| 26 |
+ return false |
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ return true |
|
| 30 |
+} |
|
| 31 |
+ |
|
| 32 |
+func setupGlobalChain() {
|
|
| 33 |
+ if err := rawIPTables("-N", globalChain); err != nil {
|
|
| 34 |
+ logrus.Debugf("could not create global overlay chain: %v", err)
|
|
| 35 |
+ } |
|
| 36 |
+ |
|
| 37 |
+ if err := rawIPTables("-A", globalChain, "-j", "RETURN"); err != nil {
|
|
| 38 |
+ logrus.Debugf("could not install default return chain in the overlay global chain: %v", err)
|
|
| 39 |
+ } |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+func setNetworkChain(cname string, remove bool) error {
|
|
| 43 |
+ // Initialize the onetime global overlay chain |
|
| 44 |
+ filterOnce.Do(setupGlobalChain) |
|
| 45 |
+ |
|
| 46 |
+ exists := chainExists(cname) |
|
| 47 |
+ |
|
| 48 |
+ opt := "-N" |
|
| 49 |
+ // In case of remove, make sure to flush the rules in the chain |
|
| 50 |
+ if remove && exists {
|
|
| 51 |
+ if err := rawIPTables("-F", cname); err != nil {
|
|
| 52 |
+ return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err)
|
|
| 53 |
+ } |
|
| 54 |
+ opt = "-X" |
|
| 55 |
+ } |
|
| 56 |
+ |
|
| 57 |
+ if (!remove && !exists) || (remove && exists) {
|
|
| 58 |
+ if err := rawIPTables(opt, cname); err != nil {
|
|
| 59 |
+ return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err)
|
|
| 60 |
+ } |
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ if !remove {
|
|
| 64 |
+ if !iptables.Exists(iptables.Filter, cname, "-j", "DROP") {
|
|
| 65 |
+ if err := rawIPTables("-A", cname, "-j", "DROP"); err != nil {
|
|
| 66 |
+ return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err)
|
|
| 67 |
+ } |
|
| 68 |
+ } |
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ return nil |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+func addNetworkChain(cname string) error {
|
|
| 75 |
+ return setNetworkChain(cname, false) |
|
| 76 |
+} |
|
| 77 |
+ |
|
| 78 |
+func removeNetworkChain(cname string) error {
|
|
| 79 |
+ return setNetworkChain(cname, true) |
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+func setFilters(cname, brName string, remove bool) error {
|
|
| 83 |
+ opt := "-I" |
|
| 84 |
+ if remove {
|
|
| 85 |
+ opt = "-D" |
|
| 86 |
+ } |
|
| 87 |
+ |
|
| 88 |
+ // 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 |
|
| 89 |
+ if !remove {
|
|
| 90 |
+ for _, chain := range []string{"OUTPUT", "FORWARD"} {
|
|
| 91 |
+ exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain) |
|
| 92 |
+ if exists {
|
|
| 93 |
+ if err := rawIPTables("-D", chain, "-j", globalChain); err != nil {
|
|
| 94 |
+ return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err)
|
|
| 95 |
+ } |
|
| 96 |
+ } |
|
| 97 |
+ |
|
| 98 |
+ if err := rawIPTables("-I", chain, "-j", globalChain); err != nil {
|
|
| 99 |
+ return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err)
|
|
| 100 |
+ } |
|
| 101 |
+ } |
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ // Insert/Delete the rule to jump to per-bridge chain |
|
| 105 |
+ exists := iptables.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname) |
|
| 106 |
+ if (!remove && !exists) || (remove && exists) {
|
|
| 107 |
+ if err := rawIPTables(opt, globalChain, "-o", brName, "-j", cname); err != nil {
|
|
| 108 |
+ return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err)
|
|
| 109 |
+ } |
|
| 110 |
+ } |
|
| 111 |
+ |
|
| 112 |
+ exists = iptables.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT") |
|
| 113 |
+ if (!remove && exists) || (remove && !exists) {
|
|
| 114 |
+ return nil |
|
| 115 |
+ } |
|
| 116 |
+ |
|
| 117 |
+ if err := rawIPTables(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil {
|
|
| 118 |
+ return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err)
|
|
| 119 |
+ } |
|
| 120 |
+ |
|
| 121 |
+ return nil |
|
| 122 |
+} |
|
| 123 |
+ |
|
| 124 |
+func addFilters(cname, brName string) error {
|
|
| 125 |
+ return setFilters(cname, brName, false) |
|
| 126 |
+} |
|
| 127 |
+ |
|
| 128 |
+func removeFilters(cname, brName string) error {
|
|
| 129 |
+ return setFilters(cname, brName, true) |
|
| 130 |
+} |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"net" |
| 7 |
+ "os" |
|
| 7 | 8 |
"sync" |
| 8 | 9 |
"syscall" |
| 9 | 10 |
|
| ... | ... |
@@ -12,11 +13,17 @@ import ( |
| 12 | 12 |
"github.com/docker/libnetwork/driverapi" |
| 13 | 13 |
"github.com/docker/libnetwork/netutils" |
| 14 | 14 |
"github.com/docker/libnetwork/osl" |
| 15 |
+ "github.com/docker/libnetwork/resolvconf" |
|
| 15 | 16 |
"github.com/docker/libnetwork/types" |
| 16 | 17 |
"github.com/vishvananda/netlink" |
| 17 | 18 |
"github.com/vishvananda/netlink/nl" |
| 18 | 19 |
) |
| 19 | 20 |
|
| 21 |
+var ( |
|
| 22 |
+ hostMode bool |
|
| 23 |
+ hostModeOnce sync.Once |
|
| 24 |
+) |
|
| 25 |
+ |
|
| 20 | 26 |
type networkTable map[string]*network |
| 21 | 27 |
|
| 22 | 28 |
type subnet struct {
|
| ... | ... |
@@ -87,22 +94,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
|
| 87 | 87 |
return nil |
| 88 | 88 |
} |
| 89 | 89 |
|
| 90 |
-/* func (d *driver) createNetworkfromStore(nid string) (*network, error) {
|
|
| 91 |
- n := &network{
|
|
| 92 |
- id: nid, |
|
| 93 |
- driver: d, |
|
| 94 |
- endpoints: endpointTable{},
|
|
| 95 |
- once: &sync.Once{},
|
|
| 96 |
- subnets: []*subnet{},
|
|
| 97 |
- } |
|
| 98 |
- |
|
| 99 |
- err := d.store.GetObject(datastore.Key(n.Key()...), n) |
|
| 100 |
- if err != nil {
|
|
| 101 |
- return nil, fmt.Errorf("unable to get network %q from data store, %v", nid, err)
|
|
| 102 |
- } |
|
| 103 |
- return n, nil |
|
| 104 |
-}*/ |
|
| 105 |
- |
|
| 106 | 90 |
func (d *driver) DeleteNetwork(nid string) error {
|
| 107 | 91 |
if nid == "" {
|
| 108 | 92 |
return fmt.Errorf("invalid network id")
|
| ... | ... |
@@ -171,24 +162,110 @@ func (n *network) destroySandbox() {
|
| 171 | 171 |
} |
| 172 | 172 |
|
| 173 | 173 |
for _, s := range n.subnets {
|
| 174 |
+ if hostMode {
|
|
| 175 |
+ if err := removeFilters(n.id[:12], s.brName); err != nil {
|
|
| 176 |
+ logrus.Warnf("Could not remove overlay filters: %v", err)
|
|
| 177 |
+ } |
|
| 178 |
+ } |
|
| 179 |
+ |
|
| 174 | 180 |
if s.vxlanName != "" {
|
| 175 |
- err := deleteVxlan(s.vxlanName) |
|
| 181 |
+ err := deleteInterface(s.vxlanName) |
|
| 176 | 182 |
if err != nil {
|
| 177 | 183 |
logrus.Warnf("could not cleanup sandbox properly: %v", err)
|
| 178 | 184 |
} |
| 179 | 185 |
} |
| 180 | 186 |
} |
| 187 |
+ |
|
| 188 |
+ if hostMode {
|
|
| 189 |
+ if err := removeNetworkChain(n.id[:12]); err != nil {
|
|
| 190 |
+ logrus.Warnf("could not remove network chain: %v", err)
|
|
| 191 |
+ } |
|
| 192 |
+ } |
|
| 193 |
+ |
|
| 181 | 194 |
sbox.Destroy() |
| 182 | 195 |
n.setSandbox(nil) |
| 183 | 196 |
} |
| 184 | 197 |
} |
| 185 | 198 |
|
| 186 |
-func (n *network) initSubnetSandbox(s *subnet) error {
|
|
| 187 |
- // create a bridge and vxlan device for this subnet and move it to the sandbox |
|
| 188 |
- brName, err := netutils.GenerateIfaceName("bridge", 7)
|
|
| 199 |
+func setHostMode() {
|
|
| 200 |
+ if os.Getenv("_OVERLAY_HOST_MODE") != "" {
|
|
| 201 |
+ hostMode = true |
|
| 202 |
+ return |
|
| 203 |
+ } |
|
| 204 |
+ |
|
| 205 |
+ err := createVxlan("testvxlan", 1)
|
|
| 189 | 206 |
if err != nil {
|
| 190 |
- return err |
|
| 207 |
+ logrus.Errorf("Failed to create testvxlan interface: %v", err)
|
|
| 208 |
+ return |
|
| 209 |
+ } |
|
| 210 |
+ |
|
| 211 |
+ defer deleteInterface("testvxlan")
|
|
| 212 |
+ |
|
| 213 |
+ path := "/proc/self/ns/net" |
|
| 214 |
+ f, err := os.OpenFile(path, os.O_RDONLY, 0) |
|
| 215 |
+ if err != nil {
|
|
| 216 |
+ logrus.Errorf("Failed to open path %s for network namespace for setting host mode: %v", path, err)
|
|
| 217 |
+ return |
|
| 218 |
+ } |
|
| 219 |
+ defer f.Close() |
|
| 220 |
+ |
|
| 221 |
+ nsFD := f.Fd() |
|
| 222 |
+ |
|
| 223 |
+ iface, err := netlink.LinkByName("testvxlan")
|
|
| 224 |
+ if err != nil {
|
|
| 225 |
+ logrus.Errorf("Failed to get link testvxlan: %v", err)
|
|
| 226 |
+ return |
|
| 227 |
+ } |
|
| 228 |
+ |
|
| 229 |
+ // If we are not able to move the vxlan interface to a namespace |
|
| 230 |
+ // then fallback to host mode |
|
| 231 |
+ if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil {
|
|
| 232 |
+ hostMode = true |
|
| 233 |
+ } |
|
| 234 |
+} |
|
| 235 |
+ |
|
| 236 |
+func (n *network) generateVxlanName(s *subnet) string {
|
|
| 237 |
+ return "vx-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5]
|
|
| 238 |
+} |
|
| 239 |
+ |
|
| 240 |
+func (n *network) generateBridgeName(s *subnet) string {
|
|
| 241 |
+ return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5]
|
|
| 242 |
+} |
|
| 243 |
+ |
|
| 244 |
+func isOverlap(nw *net.IPNet) bool {
|
|
| 245 |
+ var nameservers []string |
|
| 246 |
+ |
|
| 247 |
+ if rc, err := resolvconf.Get(); err == nil {
|
|
| 248 |
+ nameservers = resolvconf.GetNameserversAsCIDR(rc.Content) |
|
| 249 |
+ } |
|
| 250 |
+ |
|
| 251 |
+ if err := netutils.CheckNameserverOverlaps(nameservers, nw); err != nil {
|
|
| 252 |
+ return true |
|
| 253 |
+ } |
|
| 254 |
+ |
|
| 255 |
+ if err := netutils.CheckRouteOverlaps(nw); err != nil {
|
|
| 256 |
+ return true |
|
| 257 |
+ } |
|
| 258 |
+ |
|
| 259 |
+ return false |
|
| 260 |
+} |
|
| 261 |
+ |
|
| 262 |
+func (n *network) initSubnetSandbox(s *subnet) error {
|
|
| 263 |
+ brName := n.generateBridgeName(s) |
|
| 264 |
+ vxlanName := n.generateVxlanName(s) |
|
| 265 |
+ |
|
| 266 |
+ if hostMode {
|
|
| 267 |
+ // Try to delete stale bridge interface if it exists |
|
| 268 |
+ deleteInterface(brName) |
|
| 269 |
+ // Try to delete the vxlan interface by vni if already present |
|
| 270 |
+ deleteVxlanByVNI(n.vxlanID(s)) |
|
| 271 |
+ |
|
| 272 |
+ if isOverlap(s.subnetIP) {
|
|
| 273 |
+ return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String())
|
|
| 274 |
+ } |
|
| 191 | 275 |
} |
| 276 |
+ |
|
| 277 |
+ // create a bridge and vxlan device for this subnet and move it to the sandbox |
|
| 192 | 278 |
sbox := n.sandbox() |
| 193 | 279 |
|
| 194 | 280 |
if err := sbox.AddInterface(brName, "br", |
| ... | ... |
@@ -197,7 +274,7 @@ func (n *network) initSubnetSandbox(s *subnet) error {
|
| 197 | 197 |
return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.String(), err)
|
| 198 | 198 |
} |
| 199 | 199 |
|
| 200 |
- vxlanName, err := createVxlan(n.vxlanID(s)) |
|
| 200 |
+ err := createVxlan(vxlanName, n.vxlanID(s)) |
|
| 201 | 201 |
if err != nil {
|
| 202 | 202 |
return err |
| 203 | 203 |
} |
| ... | ... |
@@ -207,6 +284,12 @@ func (n *network) initSubnetSandbox(s *subnet) error {
|
| 207 | 207 |
return fmt.Errorf("vxlan interface creation failed for subnet %q: %v", s.subnetIP.String(), err)
|
| 208 | 208 |
} |
| 209 | 209 |
|
| 210 |
+ if hostMode {
|
|
| 211 |
+ if err := addFilters(n.id[:12], brName); err != nil {
|
|
| 212 |
+ return err |
|
| 213 |
+ } |
|
| 214 |
+ } |
|
| 215 |
+ |
|
| 210 | 216 |
n.Lock() |
| 211 | 217 |
s.vxlanName = vxlanName |
| 212 | 218 |
s.brName = brName |
| ... | ... |
@@ -220,8 +303,16 @@ func (n *network) initSandbox() error {
|
| 220 | 220 |
n.initEpoch++ |
| 221 | 221 |
n.Unlock() |
| 222 | 222 |
|
| 223 |
+ hostModeOnce.Do(setHostMode) |
|
| 224 |
+ |
|
| 225 |
+ if hostMode {
|
|
| 226 |
+ if err := addNetworkChain(n.id[:12]); err != nil {
|
|
| 227 |
+ return err |
|
| 228 |
+ } |
|
| 229 |
+ } |
|
| 230 |
+ |
|
| 223 | 231 |
sbox, err := osl.NewSandbox( |
| 224 |
- osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), true)
|
|
| 232 |
+ osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), !hostMode)
|
|
| 225 | 233 |
if err != nil {
|
| 226 | 234 |
return fmt.Errorf("could not create network sandbox: %v", err)
|
| 227 | 235 |
} |
| ... | ... |
@@ -47,14 +47,9 @@ func createVethPair() (string, string, error) {
|
| 47 | 47 |
return name1, name2, nil |
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 |
-func createVxlan(vni uint32) (string, error) {
|
|
| 50 |
+func createVxlan(name string, vni uint32) error {
|
|
| 51 | 51 |
defer osl.InitOSContext()() |
| 52 | 52 |
|
| 53 |
- name, err := netutils.GenerateIfaceName("vxlan", 7)
|
|
| 54 |
- if err != nil {
|
|
| 55 |
- return "", fmt.Errorf("error generating vxlan name: %v", err)
|
|
| 56 |
- } |
|
| 57 |
- |
|
| 58 | 53 |
vxlan := &netlink.Vxlan{
|
| 59 | 54 |
LinkAttrs: netlink.LinkAttrs{Name: name},
|
| 60 | 55 |
VxlanId: int(vni), |
| ... | ... |
@@ -66,23 +61,45 @@ func createVxlan(vni uint32) (string, error) {
|
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 | 68 |
if err := netlink.LinkAdd(vxlan); err != nil {
|
| 69 |
- return "", fmt.Errorf("error creating vxlan interface: %v", err)
|
|
| 69 |
+ return fmt.Errorf("error creating vxlan interface: %v", err)
|
|
| 70 | 70 |
} |
| 71 | 71 |
|
| 72 |
- return name, nil |
|
| 72 |
+ return nil |
|
| 73 | 73 |
} |
| 74 | 74 |
|
| 75 |
-func deleteVxlan(name string) error {
|
|
| 75 |
+func deleteInterface(name string) error {
|
|
| 76 | 76 |
defer osl.InitOSContext()() |
| 77 | 77 |
|
| 78 | 78 |
link, err := netlink.LinkByName(name) |
| 79 | 79 |
if err != nil {
|
| 80 |
- return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err)
|
|
| 80 |
+ return fmt.Errorf("failed to find interface with name %s: %v", name, err)
|
|
| 81 | 81 |
} |
| 82 | 82 |
|
| 83 | 83 |
if err := netlink.LinkDel(link); err != nil {
|
| 84 |
- return fmt.Errorf("error deleting vxlan interface: %v", err)
|
|
| 84 |
+ return fmt.Errorf("error deleting interface with name %s: %v", name, err)
|
|
| 85 | 85 |
} |
| 86 | 86 |
|
| 87 | 87 |
return nil |
| 88 | 88 |
} |
| 89 |
+ |
|
| 90 |
+func deleteVxlanByVNI(vni uint32) error {
|
|
| 91 |
+ defer osl.InitOSContext()() |
|
| 92 |
+ |
|
| 93 |
+ links, err := netlink.LinkList() |
|
| 94 |
+ if err != nil {
|
|
| 95 |
+ return fmt.Errorf("failed to list interfaces while deleting vxlan interface by vni: %v", err)
|
|
| 96 |
+ } |
|
| 97 |
+ |
|
| 98 |
+ for _, l := range links {
|
|
| 99 |
+ if l.Type() == "vxlan" && l.(*netlink.Vxlan).VxlanId == int(vni) {
|
|
| 100 |
+ err = netlink.LinkDel(l) |
|
| 101 |
+ if err != nil {
|
|
| 102 |
+ return fmt.Errorf("error deleting vxlan interface with id %d: %v", vni, err)
|
|
| 103 |
+ } |
|
| 104 |
+ |
|
| 105 |
+ return nil |
|
| 106 |
+ } |
|
| 107 |
+ } |
|
| 108 |
+ |
|
| 109 |
+ return fmt.Errorf("could not find a vxlan interface to delete with id %d", vni)
|
|
| 110 |
+} |
| ... | ... |
@@ -26,7 +26,7 @@ type peerMap struct {
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 | 28 |
type peerNetworkMap struct {
|
| 29 |
- mp map[string]peerMap |
|
| 29 |
+ mp map[string]*peerMap |
|
| 30 | 30 |
sync.Mutex |
| 31 | 31 |
} |
| 32 | 32 |
|
| ... | ... |
@@ -138,7 +138,7 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask |
| 138 | 138 |
d.peerDb.Lock() |
| 139 | 139 |
pMap, ok := d.peerDb.mp[nid] |
| 140 | 140 |
if !ok {
|
| 141 |
- d.peerDb.mp[nid] = peerMap{
|
|
| 141 |
+ d.peerDb.mp[nid] = &peerMap{
|
|
| 142 | 142 |
mp: make(map[string]peerEntry), |
| 143 | 143 |
} |
| 144 | 144 |
|
| ... | ... |
@@ -748,11 +748,8 @@ func (ep *endpoint) DataScope() string {
|
| 748 | 748 |
return ep.getNetwork().DataScope() |
| 749 | 749 |
} |
| 750 | 750 |
|
| 751 |
-func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error {
|
|
| 752 |
- var ( |
|
| 753 |
- ipam ipamapi.Ipam |
|
| 754 |
- err error |
|
| 755 |
- ) |
|
| 751 |
+func (ep *endpoint) assignAddress(ipam ipamapi.Ipam, assignIPv4, assignIPv6 bool) error {
|
|
| 752 |
+ var err error |
|
| 756 | 753 |
|
| 757 | 754 |
n := ep.getNetwork() |
| 758 | 755 |
if n.Type() == "host" || n.Type() == "null" {
|
| ... | ... |
@@ -761,11 +758,6 @@ func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error {
|
| 761 | 761 |
|
| 762 | 762 |
log.Debugf("Assigning addresses for endpoint %s's interface on network %s", ep.Name(), n.Name())
|
| 763 | 763 |
|
| 764 |
- ipam, err = n.getController().getIpamDriver(n.ipamType) |
|
| 765 |
- if err != nil {
|
|
| 766 |
- return err |
|
| 767 |
- } |
|
| 768 |
- |
|
| 769 | 764 |
if assignIPv4 {
|
| 770 | 765 |
if err = ep.assignAddressVersion(4, ipam); err != nil {
|
| 771 | 766 |
return err |
| ... | ... |
@@ -486,21 +486,28 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres |
| 486 | 486 |
// DumpDatabase dumps the internal info |
| 487 | 487 |
func (a *Allocator) DumpDatabase() string {
|
| 488 | 488 |
a.Lock() |
| 489 |
- defer a.Unlock() |
|
| 489 |
+ aspaces := make(map[string]*addrSpace, len(a.addrSpaces)) |
|
| 490 |
+ for as, aSpace := range a.addrSpaces {
|
|
| 491 |
+ aspaces[as] = aSpace |
|
| 492 |
+ } |
|
| 493 |
+ a.Unlock() |
|
| 490 | 494 |
|
| 491 | 495 |
var s string |
| 492 |
- for as, aSpace := range a.addrSpaces {
|
|
| 496 |
+ for as, aSpace := range aspaces {
|
|
| 493 | 497 |
s = fmt.Sprintf("\n\n%s Config", as)
|
| 494 | 498 |
aSpace.Lock() |
| 495 | 499 |
for k, config := range aSpace.subnets {
|
| 496 | 500 |
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
|
| 501 |
+ if config.Range == nil {
|
|
| 502 |
+ a.retrieveBitmask(k, config.Pool) |
|
| 503 |
+ } |
|
| 497 | 504 |
} |
| 498 | 505 |
aSpace.Unlock() |
| 499 | 506 |
} |
| 500 | 507 |
|
| 501 | 508 |
s = fmt.Sprintf("%s\n\nBitmasks", s)
|
| 502 | 509 |
for k, bm := range a.addresses {
|
| 503 |
- s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected()))
|
|
| 510 |
+ s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%s: %s", k, bm))
|
|
| 504 | 511 |
} |
| 505 | 512 |
|
| 506 | 513 |
return s |
| ... | ... |
@@ -22,8 +22,10 @@ const ( |
| 22 | 22 |
|
| 23 | 23 |
// Callback provides a Callback interface for registering an IPAM instance into LibNetwork |
| 24 | 24 |
type Callback interface {
|
| 25 |
- // RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a ipam instance |
|
| 25 |
+ // RegisterIpamDriver provides a way for Remote drivers to dynamically register with libnetwork |
|
| 26 | 26 |
RegisterIpamDriver(name string, driver Ipam) error |
| 27 |
+ // RegisterIpamDriverWithCapabilities provides a way for Remote drivers to dynamically register with libnetwork and specify cpaabilities |
|
| 28 |
+ RegisterIpamDriverWithCapabilities(name string, driver Ipam, capability *Capability) error |
|
| 27 | 29 |
} |
| 28 | 30 |
|
| 29 | 31 |
/************** |
| ... | ... |
@@ -70,3 +72,8 @@ type Ipam interface {
|
| 70 | 70 |
// Release the address from the specified pool ID |
| 71 | 71 |
ReleaseAddress(string, net.IP) error |
| 72 | 72 |
} |
| 73 |
+ |
|
| 74 |
+// Capability represents the requirements and capabilities of the IPAM driver |
|
| 75 |
+type Capability struct {
|
|
| 76 |
+ RequiresMACAddress bool |
|
| 77 |
+} |
| ... | ... |
@@ -2,6 +2,8 @@ |
| 2 | 2 |
// messages between libnetwork and the remote ipam plugin |
| 3 | 3 |
package api |
| 4 | 4 |
|
| 5 |
+import "github.com/docker/libnetwork/ipamapi" |
|
| 6 |
+ |
|
| 5 | 7 |
// Response is the basic response structure used in all responses |
| 6 | 8 |
type Response struct {
|
| 7 | 9 |
Error string |
| ... | ... |
@@ -17,6 +19,17 @@ func (r *Response) GetError() string {
|
| 17 | 17 |
return r.Error |
| 18 | 18 |
} |
| 19 | 19 |
|
| 20 |
+// GetCapabilityResponse is the response of GetCapability request |
|
| 21 |
+type GetCapabilityResponse struct {
|
|
| 22 |
+ Response |
|
| 23 |
+ RequiresMACAddress bool |
|
| 24 |
+} |
|
| 25 |
+ |
|
| 26 |
+// ToCapability converts the capability response into the internal ipam driver capaility structure |
|
| 27 |
+func (capRes GetCapabilityResponse) ToCapability() *ipamapi.Capability {
|
|
| 28 |
+ return &ipamapi.Capability{RequiresMACAddress: capRes.RequiresMACAddress}
|
|
| 29 |
+} |
|
| 30 |
+ |
|
| 20 | 31 |
// GetAddressSpacesResponse is the response to the ``get default address spaces`` request message |
| 21 | 32 |
type GetAddressSpacesResponse struct {
|
| 22 | 33 |
Response |
| ... | ... |
@@ -30,8 +30,17 @@ func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
|
| 30 | 30 |
// Init registers a remote ipam when its plugin is activated |
| 31 | 31 |
func Init(cb ipamapi.Callback, l, g interface{}) error {
|
| 32 | 32 |
plugins.Handle(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) {
|
| 33 |
- if err := cb.RegisterIpamDriver(name, newAllocator(name, client)); err != nil {
|
|
| 34 |
- log.Errorf("error registering remote ipam %s due to %v", name, err)
|
|
| 33 |
+ a := newAllocator(name, client) |
|
| 34 |
+ if cps, err := a.(*allocator).getCapabilities(); err == nil {
|
|
| 35 |
+ if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil {
|
|
| 36 |
+ log.Errorf("error registering remote ipam driver %s due to %v", name, err)
|
|
| 37 |
+ } |
|
| 38 |
+ } else {
|
|
| 39 |
+ log.Infof("remote ipam driver %s does not support capabilities", name)
|
|
| 40 |
+ log.Debug(err) |
|
| 41 |
+ if err := cb.RegisterIpamDriver(name, a); err != nil {
|
|
| 42 |
+ log.Errorf("error registering remote ipam driver %s due to %v", name, err)
|
|
| 43 |
+ } |
|
| 35 | 44 |
} |
| 36 | 45 |
}) |
| 37 | 46 |
return nil |
| ... | ... |
@@ -49,6 +58,14 @@ func (a *allocator) call(methodName string, arg interface{}, retVal PluginRespon
|
| 49 | 49 |
return nil |
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
+func (a *allocator) getCapabilities() (*ipamapi.Capability, error) {
|
|
| 53 |
+ var res api.GetCapabilityResponse |
|
| 54 |
+ if err := a.call("GetCapabilities", nil, &res); err != nil {
|
|
| 55 |
+ return nil, err |
|
| 56 |
+ } |
|
| 57 |
+ return res.ToCapability(), nil |
|
| 58 |
+} |
|
| 59 |
+ |
|
| 52 | 60 |
// GetDefaultAddressSpaces returns the local and global default address spaces |
| 53 | 61 |
func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
|
| 54 | 62 |
res := &api.GetAddressSpacesResponse{}
|
| 55 | 63 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,22 @@ |
| 0 |
+// Package ipamutils provides utililty functions for ipam management |
|
| 1 |
+package ipamutils |
|
| 2 |
+ |
|
| 3 |
+import ( |
|
| 4 |
+ "net" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/docker/libnetwork/types" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// ElectInterfaceAddresses looks for an interface on the OS with the specified name |
|
| 10 |
+// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist, |
|
| 11 |
+// it chooses from a predifined list the first IPv4 address which does not conflict |
|
| 12 |
+// with other interfaces on the system. |
|
| 13 |
+func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
|
|
| 14 |
+ return nil, nil, types.NotImplementedErrorf("not supported on freebsd")
|
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+// FindAvailableNetwork returns a network from the passed list which does not |
|
| 18 |
+// overlap with existing interfaces in the system |
|
| 19 |
+func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
|
|
| 20 |
+ return nil, types.NotImplementedErrorf("not supported on freebsd")
|
|
| 21 |
+} |
| ... | ... |
@@ -41,6 +41,9 @@ const ( |
| 41 | 41 |
|
| 42 | 42 |
// Gateway represents the gateway for the network |
| 43 | 43 |
Gateway = Prefix + ".gateway" |
| 44 |
+ |
|
| 45 |
+ // Internal constant represents that the network is internal which disables default gateway service |
|
| 46 |
+ Internal = Prefix + ".internal" |
|
| 44 | 47 |
) |
| 45 | 48 |
|
| 46 | 49 |
var ( |
| ... | ... |
@@ -16,6 +16,7 @@ import ( |
| 16 | 16 |
"github.com/docker/libnetwork/etchosts" |
| 17 | 17 |
"github.com/docker/libnetwork/ipamapi" |
| 18 | 18 |
"github.com/docker/libnetwork/netlabel" |
| 19 |
+ "github.com/docker/libnetwork/netutils" |
|
| 19 | 20 |
"github.com/docker/libnetwork/options" |
| 20 | 21 |
"github.com/docker/libnetwork/types" |
| 21 | 22 |
) |
| ... | ... |
@@ -58,6 +59,7 @@ type Network interface {
|
| 58 | 58 |
// NetworkInfo returns some configuration and operational information about the network |
| 59 | 59 |
type NetworkInfo interface {
|
| 60 | 60 |
IpamConfig() (string, []*IpamConf, []*IpamConf) |
| 61 |
+ IpamInfo() ([]*IpamInfo, []*IpamInfo) |
|
| 61 | 62 |
DriverOptions() map[string]string |
| 62 | 63 |
Scope() string |
| 63 | 64 |
} |
| ... | ... |
@@ -161,6 +163,7 @@ type network struct {
|
| 161 | 161 |
persist bool |
| 162 | 162 |
stopWatchCh chan struct{}
|
| 163 | 163 |
drvOnce *sync.Once |
| 164 |
+ internal bool |
|
| 164 | 165 |
sync.Mutex |
| 165 | 166 |
} |
| 166 | 167 |
|
| ... | ... |
@@ -303,6 +306,7 @@ func (n *network) CopyTo(o datastore.KVObject) error {
|
| 303 | 303 |
dstN.dbIndex = n.dbIndex |
| 304 | 304 |
dstN.dbExists = n.dbExists |
| 305 | 305 |
dstN.drvOnce = n.drvOnce |
| 306 |
+ dstN.internal = n.internal |
|
| 306 | 307 |
|
| 307 | 308 |
for _, v4conf := range n.ipamV4Config {
|
| 308 | 309 |
dstV4Conf := &IpamConf{}
|
| ... | ... |
@@ -389,6 +393,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
|
| 389 | 389 |
} |
| 390 | 390 |
netMap["ipamV6Info"] = string(iis) |
| 391 | 391 |
} |
| 392 |
+ netMap["internal"] = n.internal |
|
| 392 | 393 |
return json.Marshal(netMap) |
| 393 | 394 |
} |
| 394 | 395 |
|
| ... | ... |
@@ -452,6 +457,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
| 452 | 452 |
return err |
| 453 | 453 |
} |
| 454 | 454 |
} |
| 455 |
+ if v, ok := netMap["internal"]; ok {
|
|
| 456 |
+ n.internal = v.(bool) |
|
| 457 |
+ } |
|
| 455 | 458 |
return nil |
| 456 | 459 |
} |
| 457 | 460 |
|
| ... | ... |
@@ -478,6 +486,18 @@ func NetworkOptionPersist(persist bool) NetworkOption {
|
| 478 | 478 |
} |
| 479 | 479 |
} |
| 480 | 480 |
|
| 481 |
+// NetworkOptionInternalNetwork returns an option setter to config the network |
|
| 482 |
+// to be internal which disables default gateway service |
|
| 483 |
+func NetworkOptionInternalNetwork() NetworkOption {
|
|
| 484 |
+ return func(n *network) {
|
|
| 485 |
+ n.internal = true |
|
| 486 |
+ if n.generic == nil {
|
|
| 487 |
+ n.generic = make(map[string]interface{})
|
|
| 488 |
+ } |
|
| 489 |
+ n.generic[netlabel.Internal] = true |
|
| 490 |
+ } |
|
| 491 |
+} |
|
| 492 |
+ |
|
| 481 | 493 |
// NetworkOptionIpam function returns an option setter for the ipam configuration for this network |
| 482 | 494 |
func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf) NetworkOption {
|
| 483 | 495 |
return func(n *network) {
|
| ... | ... |
@@ -678,7 +698,22 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi |
| 678 | 678 |
} |
| 679 | 679 |
} |
| 680 | 680 |
|
| 681 |
- if err = ep.assignAddress(true, !n.postIPv6); err != nil {
|
|
| 681 |
+ ipam, err := n.getController().getIPAM(n.ipamType) |
|
| 682 |
+ if err != nil {
|
|
| 683 |
+ return nil, err |
|
| 684 |
+ } |
|
| 685 |
+ |
|
| 686 |
+ if ipam.capability.RequiresMACAddress {
|
|
| 687 |
+ if ep.iface.mac == nil {
|
|
| 688 |
+ ep.iface.mac = netutils.GenerateRandomMAC() |
|
| 689 |
+ } |
|
| 690 |
+ if ep.ipamOptions == nil {
|
|
| 691 |
+ ep.ipamOptions = make(map[string]string) |
|
| 692 |
+ } |
|
| 693 |
+ ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String() |
|
| 694 |
+ } |
|
| 695 |
+ |
|
| 696 |
+ if err = ep.assignAddress(ipam.driver, true, !n.postIPv6); err != nil {
|
|
| 682 | 697 |
return nil, err |
| 683 | 698 |
} |
| 684 | 699 |
defer func() {
|
| ... | ... |
@@ -698,7 +733,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi |
| 698 | 698 |
} |
| 699 | 699 |
}() |
| 700 | 700 |
|
| 701 |
- if err = ep.assignAddress(false, n.postIPv6); err != nil {
|
|
| 701 |
+ if err = ep.assignAddress(ipam.driver, false, n.postIPv6); err != nil {
|
|
| 702 | 702 |
return nil, err |
| 703 | 703 |
} |
| 704 | 704 |
|
| ... | ... |
@@ -1148,3 +1183,32 @@ func (n *network) IpamConfig() (string, []*IpamConf, []*IpamConf) {
|
| 1148 | 1148 |
|
| 1149 | 1149 |
return n.ipamType, v4L, v6L |
| 1150 | 1150 |
} |
| 1151 |
+ |
|
| 1152 |
+func (n *network) IpamInfo() ([]*IpamInfo, []*IpamInfo) {
|
|
| 1153 |
+ n.Lock() |
|
| 1154 |
+ defer n.Unlock() |
|
| 1155 |
+ |
|
| 1156 |
+ v4Info := make([]*IpamInfo, len(n.ipamV4Info)) |
|
| 1157 |
+ v6Info := make([]*IpamInfo, len(n.ipamV6Info)) |
|
| 1158 |
+ |
|
| 1159 |
+ for i, info := range n.ipamV4Info {
|
|
| 1160 |
+ ic := &IpamInfo{}
|
|
| 1161 |
+ info.CopyTo(ic) |
|
| 1162 |
+ v4Info[i] = ic |
|
| 1163 |
+ } |
|
| 1164 |
+ |
|
| 1165 |
+ for i, info := range n.ipamV6Info {
|
|
| 1166 |
+ ic := &IpamInfo{}
|
|
| 1167 |
+ info.CopyTo(ic) |
|
| 1168 |
+ v6Info[i] = ic |
|
| 1169 |
+ } |
|
| 1170 |
+ |
|
| 1171 |
+ return v4Info, v6Info |
|
| 1172 |
+} |
|
| 1173 |
+ |
|
| 1174 |
+func (n *network) Internal() bool {
|
|
| 1175 |
+ n.Lock() |
|
| 1176 |
+ defer n.Unlock() |
|
| 1177 |
+ |
|
| 1178 |
+ return n.internal |
|
| 1179 |
+} |
| ... | ... |
@@ -109,6 +109,7 @@ func (i *nwIface) Remove() error {
|
| 109 | 109 |
|
| 110 | 110 |
n.Lock() |
| 111 | 111 |
path := n.path |
| 112 |
+ isDefault := n.isDefault |
|
| 112 | 113 |
n.Unlock() |
| 113 | 114 |
|
| 114 | 115 |
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
|
| ... | ... |
@@ -134,7 +135,7 @@ func (i *nwIface) Remove() error {
|
| 134 | 134 |
if err := netlink.LinkDel(iface); err != nil {
|
| 135 | 135 |
return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
|
| 136 | 136 |
} |
| 137 |
- } else {
|
|
| 137 |
+ } else if !isDefault {
|
|
| 138 | 138 |
// Move the network interface to caller namespace. |
| 139 | 139 |
if err := netlink.LinkSetNsFd(iface, callerFD); err != nil {
|
| 140 | 140 |
fmt.Println("LinkSetNsPid failed: ", err)
|
| ... | ... |
@@ -213,9 +214,15 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If |
| 213 | 213 |
} |
| 214 | 214 |
|
| 215 | 215 |
n.Lock() |
| 216 |
- i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
|
|
| 217 |
- n.nextIfIndex++ |
|
| 216 |
+ if n.isDefault {
|
|
| 217 |
+ i.dstName = i.srcName |
|
| 218 |
+ } else {
|
|
| 219 |
+ i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
|
|
| 220 |
+ n.nextIfIndex++ |
|
| 221 |
+ } |
|
| 222 |
+ |
|
| 218 | 223 |
path := n.path |
| 224 |
+ isDefault := n.isDefault |
|
| 219 | 225 |
n.Unlock() |
| 220 | 226 |
|
| 221 | 227 |
return nsInvoke(path, func(nsFD int) error {
|
| ... | ... |
@@ -231,9 +238,13 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If |
| 231 | 231 |
return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
|
| 232 | 232 |
} |
| 233 | 233 |
|
| 234 |
- // Move the network interface to the destination namespace. |
|
| 235 |
- if err := netlink.LinkSetNsFd(iface, nsFD); err != nil {
|
|
| 236 |
- return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
|
|
| 234 |
+ // Move the network interface to the destination |
|
| 235 |
+ // namespace only if the namespace is not a default |
|
| 236 |
+ // type |
|
| 237 |
+ if !isDefault {
|
|
| 238 |
+ if err := netlink.LinkSetNsFd(iface, nsFD); err != nil {
|
|
| 239 |
+ return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
|
|
| 240 |
+ } |
|
| 237 | 241 |
} |
| 238 | 242 |
|
| 239 | 243 |
return nil |
| ... | ... |
@@ -41,6 +41,7 @@ type networkNamespace struct {
|
| 41 | 41 |
staticRoutes []*types.StaticRoute |
| 42 | 42 |
neighbors []*neigh |
| 43 | 43 |
nextIfIndex int |
| 44 |
+ isDefault bool |
|
| 44 | 45 |
sync.Mutex |
| 45 | 46 |
} |
| 46 | 47 |
|
| ... | ... |
@@ -146,7 +147,7 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
| 146 | 146 |
return nil, err |
| 147 | 147 |
} |
| 148 | 148 |
|
| 149 |
- return &networkNamespace{path: key}, nil
|
|
| 149 |
+ return &networkNamespace{path: key, isDefault: !osCreate}, nil
|
|
| 150 | 150 |
} |
| 151 | 151 |
|
| 152 | 152 |
func (n *networkNamespace) InterfaceOptions() IfaceOptionSetter {
|
| ... | ... |
@@ -19,6 +19,11 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
| 19 | 19 |
return nil, nil |
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 |
+// GetSandboxForExternalKey returns sandbox object for the supplied path |
|
| 23 |
+func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
|
|
| 24 |
+ return nil, nil |
|
| 25 |
+} |
|
| 26 |
+ |
|
| 22 | 27 |
// GC triggers garbage collection of namespace path right away |
| 23 | 28 |
// and waits for it. |
| 24 | 29 |
func GC() {
|