Daemon to support network restore
| ... | ... |
@@ -121,14 +121,6 @@ func New(config Config) (*Cluster, error) {
|
| 121 | 121 |
return c, nil |
| 122 | 122 |
} |
| 123 | 123 |
|
| 124 |
-func (c *Cluster) checkCompatibility() error {
|
|
| 125 |
- info, _ := c.config.Backend.SystemInfo() |
|
| 126 |
- if info != nil && (info.ClusterStore != "" || info.ClusterAdvertise != "") {
|
|
| 127 |
- return fmt.Errorf("swarm mode is incompatible with `--cluster-store` and `--cluster-advertise daemon configuration")
|
|
| 128 |
- } |
|
| 129 |
- return nil |
|
| 130 |
-} |
|
| 131 |
- |
|
| 132 | 124 |
func (c *Cluster) saveState() error {
|
| 133 | 125 |
dt, err := json.Marshal(state{ListenAddr: c.listenAddr})
|
| 134 | 126 |
if err != nil {
|
| ... | ... |
@@ -173,7 +165,7 @@ func (c *Cluster) reconnectOnFailure(ctx context.Context) {
|
| 173 | 173 |
} |
| 174 | 174 |
|
| 175 | 175 |
func (c *Cluster) startNewNode(forceNewCluster bool, listenAddr, joinAddr, secret, cahash string, ismanager bool) (*swarmagent.Node, context.Context, error) {
|
| 176 |
- if err := c.checkCompatibility(); err != nil {
|
|
| 176 |
+ if err := c.config.Backend.IsSwarmCompatible(); err != nil {
|
|
| 177 | 177 |
return nil, nil, err |
| 178 | 178 |
} |
| 179 | 179 |
c.node = nil |
| ... | ... |
@@ -3,6 +3,7 @@ |
| 3 | 3 |
package daemon |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "fmt" |
|
| 6 | 7 |
"net" |
| 7 | 8 |
|
| 8 | 9 |
"github.com/docker/docker/opts" |
| ... | ... |
@@ -120,3 +121,13 @@ func (config *Config) GetAllRuntimes() map[string]types.Runtime {
|
| 120 | 120 |
config.reloadLock.Unlock() |
| 121 | 121 |
return rts |
| 122 | 122 |
} |
| 123 |
+ |
|
| 124 |
+func (config *Config) isSwarmCompatible() error {
|
|
| 125 |
+ if config.IsValueSet("cluster-store") || config.IsValueSet("cluster-advertise") {
|
|
| 126 |
+ return fmt.Errorf("--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode")
|
|
| 127 |
+ } |
|
| 128 |
+ if config.LiveRestore {
|
|
| 129 |
+ return fmt.Errorf("--live-restore daemon configuration is incompatible with swarm mode")
|
|
| 130 |
+ } |
|
| 131 |
+ return nil |
|
| 132 |
+} |
| ... | ... |
@@ -30,7 +30,7 @@ var ( |
| 30 | 30 |
getPortMapInfo = container.GetSandboxPortMapInfo |
| 31 | 31 |
) |
| 32 | 32 |
|
| 33 |
-func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libnetwork.Network) ([]libnetwork.SandboxOption, error) {
|
|
| 33 |
+func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]libnetwork.SandboxOption, error) {
|
|
| 34 | 34 |
var ( |
| 35 | 35 |
sboxOptions []libnetwork.SandboxOption |
| 36 | 36 |
err error |
| ... | ... |
@@ -176,16 +176,19 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libn |
| 176 | 176 |
|
| 177 | 177 |
// Legacy Link feature is supported only for the default bridge network. |
| 178 | 178 |
// return if this call to build join options is not for default bridge network |
| 179 |
- if n.Name() != defaultNetName {
|
|
| 179 |
+ // Legacy Link is only supported by docker run --link |
|
| 180 |
+ if _, ok := container.NetworkSettings.Networks[defaultNetName]; !container.HostConfig.NetworkMode.IsDefault() || !ok {
|
|
| 180 | 181 |
return sboxOptions, nil |
| 181 | 182 |
} |
| 182 | 183 |
|
| 183 |
- ep, _ := container.GetEndpointInNetwork(n) |
|
| 184 |
- if ep == nil {
|
|
| 184 |
+ if container.NetworkSettings.Networks[defaultNetName].EndpointID == "" {
|
|
| 185 | 185 |
return sboxOptions, nil |
| 186 | 186 |
} |
| 187 | 187 |
|
| 188 |
- var childEndpoints, parentEndpoints []string |
|
| 188 |
+ var ( |
|
| 189 |
+ childEndpoints, parentEndpoints []string |
|
| 190 |
+ cEndpointID string |
|
| 191 |
+ ) |
|
| 189 | 192 |
|
| 190 | 193 |
children := daemon.children(container) |
| 191 | 194 |
for linkAlias, child := range children {
|
| ... | ... |
@@ -200,9 +203,9 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libn |
| 200 | 200 |
aliasList = aliasList + " " + child.Name[1:] |
| 201 | 201 |
} |
| 202 | 202 |
sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress)) |
| 203 |
- cEndpoint, _ := child.GetEndpointInNetwork(n) |
|
| 204 |
- if cEndpoint != nil && cEndpoint.ID() != "" {
|
|
| 205 |
- childEndpoints = append(childEndpoints, cEndpoint.ID()) |
|
| 203 |
+ cEndpointID = child.NetworkSettings.Networks[defaultNetName].EndpointID |
|
| 204 |
+ if cEndpointID != "" {
|
|
| 205 |
+ childEndpoints = append(childEndpoints, cEndpointID) |
|
| 206 | 206 |
} |
| 207 | 207 |
} |
| 208 | 208 |
|
| ... | ... |
@@ -219,8 +222,8 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libn |
| 219 | 219 |
alias, |
| 220 | 220 |
bridgeSettings.IPAddress, |
| 221 | 221 |
)) |
| 222 |
- if ep.ID() != "" {
|
|
| 223 |
- parentEndpoints = append(parentEndpoints, ep.ID()) |
|
| 222 |
+ if cEndpointID != "" {
|
|
| 223 |
+ parentEndpoints = append(parentEndpoints, cEndpointID) |
|
| 224 | 224 |
} |
| 225 | 225 |
} |
| 226 | 226 |
|
| ... | ... |
@@ -312,7 +315,7 @@ func (daemon *Daemon) updateNetwork(container *container.Container) error {
|
| 312 | 312 |
return nil |
| 313 | 313 |
} |
| 314 | 314 |
|
| 315 |
- options, err := daemon.buildSandboxOptions(container, n) |
|
| 315 |
+ options, err := daemon.buildSandboxOptions(container) |
|
| 316 | 316 |
if err != nil {
|
| 317 | 317 |
return fmt.Errorf("Update network failed: %v", err)
|
| 318 | 318 |
} |
| ... | ... |
@@ -570,7 +573,7 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName |
| 570 | 570 |
} |
| 571 | 571 |
|
| 572 | 572 |
if sb == nil {
|
| 573 |
- options, err := daemon.buildSandboxOptions(container, n) |
|
| 573 |
+ options, err := daemon.buildSandboxOptions(container) |
|
| 574 | 574 |
if err != nil {
|
| 575 | 575 |
return err |
| 576 | 576 |
} |
| ... | ... |
@@ -709,6 +712,9 @@ func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID st |
| 709 | 709 |
} |
| 710 | 710 |
|
| 711 | 711 |
func (daemon *Daemon) releaseNetwork(container *container.Container) {
|
| 712 |
+ if daemon.netController == nil {
|
|
| 713 |
+ return |
|
| 714 |
+ } |
|
| 712 | 715 |
if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
|
| 713 | 716 |
return |
| 714 | 717 |
} |
| ... | ... |
@@ -146,6 +146,7 @@ func (daemon *Daemon) restore() error {
|
| 146 | 146 |
|
| 147 | 147 |
var migrateLegacyLinks bool |
| 148 | 148 |
restartContainers := make(map[*container.Container]chan struct{})
|
| 149 |
+ activeSandboxes := make(map[string]interface{})
|
|
| 149 | 150 |
for _, c := range containers {
|
| 150 | 151 |
if err := daemon.registerName(c); err != nil {
|
| 151 | 152 |
logrus.Errorf("Failed to register container %s: %s", c.ID, err)
|
| ... | ... |
@@ -178,6 +179,16 @@ func (daemon *Daemon) restore() error {
|
| 178 | 178 |
logrus.Errorf("Failed to restore with containerd: %q", err)
|
| 179 | 179 |
return |
| 180 | 180 |
} |
| 181 |
+ if !c.HostConfig.NetworkMode.IsContainer() {
|
|
| 182 |
+ options, err := daemon.buildSandboxOptions(c) |
|
| 183 |
+ if err != nil {
|
|
| 184 |
+ logrus.Warnf("Failed build sandbox option to restore container %s: %v", c.ID, err)
|
|
| 185 |
+ } |
|
| 186 |
+ mapLock.Lock() |
|
| 187 |
+ activeSandboxes[c.NetworkSettings.SandboxID] = options |
|
| 188 |
+ mapLock.Unlock() |
|
| 189 |
+ } |
|
| 190 |
+ |
|
| 181 | 191 |
} |
| 182 | 192 |
// fixme: only if not running |
| 183 | 193 |
// get list of containers we need to restart |
| ... | ... |
@@ -209,6 +220,10 @@ func (daemon *Daemon) restore() error {
|
| 209 | 209 |
}(c) |
| 210 | 210 |
} |
| 211 | 211 |
wg.Wait() |
| 212 |
+ daemon.netController, err = daemon.initNetworkController(daemon.configStore, activeSandboxes) |
|
| 213 |
+ if err != nil {
|
|
| 214 |
+ return fmt.Errorf("Error initializing network controller: %v", err)
|
|
| 215 |
+ } |
|
| 212 | 216 |
|
| 213 | 217 |
// migrate any legacy links from sqlite |
| 214 | 218 |
linkdbFile := filepath.Join(daemon.root, "linkgraph.db") |
| ... | ... |
@@ -356,6 +371,15 @@ func (daemon *Daemon) SetClusterProvider(clusterProvider cluster.Provider) {
|
| 356 | 356 |
daemon.netController.SetClusterProvider(clusterProvider) |
| 357 | 357 |
} |
| 358 | 358 |
|
| 359 |
+// IsSwarmCompatible verifies if the current daemon |
|
| 360 |
+// configuration is compatible with the swarm mode |
|
| 361 |
+func (daemon *Daemon) IsSwarmCompatible() error {
|
|
| 362 |
+ if daemon.configStore == nil {
|
|
| 363 |
+ return nil |
|
| 364 |
+ } |
|
| 365 |
+ return daemon.configStore.isSwarmCompatible() |
|
| 366 |
+} |
|
| 367 |
+ |
|
| 359 | 368 |
// NewDaemon sets up everything for the daemon to be able to service |
| 360 | 369 |
// requests from the webserver. |
| 361 | 370 |
func NewDaemon(config *Config, registryService registry.Service, containerdRemote libcontainerd.Remote) (daemon *Daemon, err error) {
|
| ... | ... |
@@ -530,11 +554,6 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot |
| 530 | 530 |
return nil, err |
| 531 | 531 |
} |
| 532 | 532 |
|
| 533 |
- d.netController, err = d.initNetworkController(config) |
|
| 534 |
- if err != nil {
|
|
| 535 |
- return nil, fmt.Errorf("Error initializing network controller: %v", err)
|
|
| 536 |
- } |
|
| 537 |
- |
|
| 538 | 533 |
sysInfo := sysinfo.New(false) |
| 539 | 534 |
// Check if Devices cgroup is mounted, it is hard requirement for container security, |
| 540 | 535 |
// on Linux. |
| ... | ... |
@@ -912,15 +931,17 @@ func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
|
| 912 | 912 |
} |
| 913 | 913 |
} |
| 914 | 914 |
|
| 915 |
+ if daemon.clusterProvider != nil {
|
|
| 916 |
+ if err := config.isSwarmCompatible(); err != nil {
|
|
| 917 |
+ return err |
|
| 918 |
+ } |
|
| 919 |
+ } |
|
| 920 |
+ |
|
| 915 | 921 |
// check discovery modifications |
| 916 | 922 |
if !modifiedDiscoverySettings(daemon.configStore, newAdvertise, newClusterStore, config.ClusterOpts) {
|
| 917 | 923 |
return nil |
| 918 | 924 |
} |
| 919 | 925 |
|
| 920 |
- if daemon.clusterProvider != nil {
|
|
| 921 |
- return fmt.Errorf("--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode")
|
|
| 922 |
- } |
|
| 923 |
- |
|
| 924 | 926 |
// enable discovery for the first time if it was not previously enabled |
| 925 | 927 |
if daemon.discoveryWatcher == nil {
|
| 926 | 928 |
discoveryWatcher, err := initDiscovery(newClusterStore, newAdvertise, config.ClusterOpts) |
| ... | ... |
@@ -947,7 +968,7 @@ func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
|
| 947 | 947 |
if daemon.netController == nil {
|
| 948 | 948 |
return nil |
| 949 | 949 |
} |
| 950 |
- netOptions, err := daemon.networkOptions(daemon.configStore) |
|
| 950 |
+ netOptions, err := daemon.networkOptions(daemon.configStore, nil) |
|
| 951 | 951 |
if err != nil {
|
| 952 | 952 |
logrus.Warnf("Failed to reload configuration with network controller: %v", err)
|
| 953 | 953 |
return nil |
| ... | ... |
@@ -964,7 +985,7 @@ func isBridgeNetworkDisabled(config *Config) bool {
|
| 964 | 964 |
return config.bridgeConfig.Iface == disableNetworkBridge |
| 965 | 965 |
} |
| 966 | 966 |
|
| 967 |
-func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
|
|
| 967 |
+func (daemon *Daemon) networkOptions(dconfig *Config, activeSandboxes map[string]interface{}) ([]nwconfig.Option, error) {
|
|
| 968 | 968 |
options := []nwconfig.Option{}
|
| 969 | 969 |
if dconfig == nil {
|
| 970 | 970 |
return options, nil |
| ... | ... |
@@ -999,6 +1020,11 @@ func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) |
| 999 | 999 |
|
| 1000 | 1000 |
options = append(options, nwconfig.OptionLabels(dconfig.Labels)) |
| 1001 | 1001 |
options = append(options, driverOptions(dconfig)...) |
| 1002 |
+ |
|
| 1003 |
+ if daemon.configStore != nil && daemon.configStore.LiveRestore && len(activeSandboxes) != 0 {
|
|
| 1004 |
+ options = append(options, nwconfig.OptionActiveSandboxes(activeSandboxes)) |
|
| 1005 |
+ } |
|
| 1006 |
+ |
|
| 1002 | 1007 |
return options, nil |
| 1003 | 1008 |
} |
| 1004 | 1009 |
|
| ... | ... |
@@ -113,7 +113,7 @@ func configureKernelSecuritySupport(config *Config, driverName string) error {
|
| 113 | 113 |
return nil |
| 114 | 114 |
} |
| 115 | 115 |
|
| 116 |
-func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
|
|
| 116 |
+func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
|
|
| 117 | 117 |
return nil, nil |
| 118 | 118 |
} |
| 119 | 119 |
|
| ... | ... |
@@ -627,8 +627,8 @@ func configureKernelSecuritySupport(config *Config, driverName string) error {
|
| 627 | 627 |
return nil |
| 628 | 628 |
} |
| 629 | 629 |
|
| 630 |
-func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
|
|
| 631 |
- netOptions, err := daemon.networkOptions(config) |
|
| 630 |
+func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
|
|
| 631 |
+ netOptions, err := daemon.networkOptions(config, activeSandboxes) |
|
| 632 | 632 |
if err != nil {
|
| 633 | 633 |
return nil, err |
| 634 | 634 |
} |
| ... | ... |
@@ -638,16 +638,24 @@ func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkC |
| 638 | 638 |
return nil, fmt.Errorf("error obtaining controller instance: %v", err)
|
| 639 | 639 |
} |
| 640 | 640 |
|
| 641 |
+ if len(activeSandboxes) > 0 {
|
|
| 642 |
+ logrus.Infof("There are old running containers, the network config will not take affect")
|
|
| 643 |
+ return controller, nil |
|
| 644 |
+ } |
|
| 645 |
+ |
|
| 641 | 646 |
// Initialize default network on "null" |
| 642 |
- if _, err := controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false)); err != nil {
|
|
| 643 |
- return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
|
|
| 647 |
+ if n, _ := controller.NetworkByName("none"); n == nil {
|
|
| 648 |
+ if _, err := controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(true)); err != nil {
|
|
| 649 |
+ return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
|
|
| 650 |
+ } |
|
| 644 | 651 |
} |
| 645 | 652 |
|
| 646 | 653 |
// Initialize default network on "host" |
| 647 |
- if _, err := controller.NewNetwork("host", "host", "", libnetwork.NetworkOptionPersist(false)); err != nil {
|
|
| 648 |
- return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
|
|
| 654 |
+ if n, _ := controller.NetworkByName("host"); n == nil {
|
|
| 655 |
+ if _, err := controller.NewNetwork("host", "host", "", libnetwork.NetworkOptionPersist(true)); err != nil {
|
|
| 656 |
+ return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
|
|
| 657 |
+ } |
|
| 649 | 658 |
} |
| 650 |
- |
|
| 651 | 659 |
if !config.DisableBridge {
|
| 652 | 660 |
// Initialize default driver "bridge" |
| 653 | 661 |
if err := initBridgeDriver(controller, config); err != nil {
|
| ... | ... |
@@ -183,7 +183,7 @@ func TestNetworkOptions(t *testing.T) {
|
| 183 | 183 |
}, |
| 184 | 184 |
} |
| 185 | 185 |
|
| 186 |
- if _, err := daemon.networkOptions(dconfigCorrect); err != nil {
|
|
| 186 |
+ if _, err := daemon.networkOptions(dconfigCorrect, nil); err != nil {
|
|
| 187 | 187 |
t.Fatalf("Expect networkOptions success, got error: %v", err)
|
| 188 | 188 |
} |
| 189 | 189 |
|
| ... | ... |
@@ -193,7 +193,7 @@ func TestNetworkOptions(t *testing.T) {
|
| 193 | 193 |
}, |
| 194 | 194 |
} |
| 195 | 195 |
|
| 196 |
- if _, err := daemon.networkOptions(dconfigWrong); err == nil {
|
|
| 196 |
+ if _, err := daemon.networkOptions(dconfigWrong, nil); err == nil {
|
|
| 197 | 197 |
t.Fatalf("Expected networkOptions error, got nil")
|
| 198 | 198 |
} |
| 199 | 199 |
} |
| ... | ... |
@@ -189,8 +189,8 @@ func configureMaxThreads(config *Config) error {
|
| 189 | 189 |
return nil |
| 190 | 190 |
} |
| 191 | 191 |
|
| 192 |
-func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
|
|
| 193 |
- netOptions, err := daemon.networkOptions(config) |
|
| 192 |
+func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
|
|
| 193 |
+ netOptions, err := daemon.networkOptions(config, nil) |
|
| 194 | 194 |
if err != nil {
|
| 195 | 195 |
return nil, err |
| 196 | 196 |
} |
| ... | ... |
@@ -59,6 +59,9 @@ func (daemon *Daemon) GetNetworkByID(partialID string) (libnetwork.Network, erro |
| 59 | 59 |
// GetNetworkByName function returns a network for a given network name. |
| 60 | 60 |
func (daemon *Daemon) GetNetworkByName(name string) (libnetwork.Network, error) {
|
| 61 | 61 |
c := daemon.netController |
| 62 |
+ if c == nil {
|
|
| 63 |
+ return nil, libnetwork.ErrNoSuchNetwork(name) |
|
| 64 |
+ } |
|
| 62 | 65 |
if name == "" {
|
| 63 | 66 |
name = c.Config().Daemon.DefaultNetwork |
| 64 | 67 |
} |
| ... | ... |
@@ -68,6 +71,9 @@ func (daemon *Daemon) GetNetworkByName(name string) (libnetwork.Network, error) |
| 68 | 68 |
// GetNetworksByID returns a list of networks whose ID partially matches zero or more networks |
| 69 | 69 |
func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network {
|
| 70 | 70 |
c := daemon.netController |
| 71 |
+ if c == nil {
|
|
| 72 |
+ return nil |
|
| 73 |
+ } |
|
| 71 | 74 |
list := []libnetwork.Network{}
|
| 72 | 75 |
l := func(nw libnetwork.Network) bool {
|
| 73 | 76 |
if strings.HasPrefix(nw.ID(), partialID) {
|
| ... | ... |
@@ -65,7 +65,7 @@ clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837 |
| 65 | 65 |
clone git github.com/imdario/mergo 0.2.1 |
| 66 | 66 |
|
| 67 | 67 |
#get libnetwork packages |
| 68 |
-clone git github.com/docker/libnetwork e8da32ce5693f0ed6823d59c8415baf76c0809ea |
|
| 68 |
+clone git github.com/docker/libnetwork 452dff166e0abd9455b07c835613197f078a34de |
|
| 69 | 69 |
clone git github.com/docker/go-events 39718a26497694185f8fb58a7d6f31947f3dc42d |
| 70 | 70 |
clone git github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 |
| 71 | 71 |
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| ... | ... |
@@ -1586,3 +1586,67 @@ func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *c |
| 1586 | 1586 |
dockerCmd(c, "network", "rm", "kiwl$%^") |
| 1587 | 1587 |
assertNwNotAvailable(c, "kiwl$%^") |
| 1588 | 1588 |
} |
| 1589 |
+ |
|
| 1590 |
+func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) {
|
|
| 1591 |
+ testRequires(t, DaemonIsLinux) |
|
| 1592 |
+ if err := s.d.StartWithBusybox("--live-restore"); err != nil {
|
|
| 1593 |
+ t.Fatal(err) |
|
| 1594 |
+ } |
|
| 1595 |
+ defer s.d.Stop() |
|
| 1596 |
+ oldCon := "old" |
|
| 1597 |
+ |
|
| 1598 |
+ _, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top")
|
|
| 1599 |
+ if err != nil {
|
|
| 1600 |
+ t.Fatal(err) |
|
| 1601 |
+ } |
|
| 1602 |
+ oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon)
|
|
| 1603 |
+ if err != nil {
|
|
| 1604 |
+ t.Fatal(err) |
|
| 1605 |
+ } |
|
| 1606 |
+ // Kill the daemon |
|
| 1607 |
+ if err := s.d.Kill(); err != nil {
|
|
| 1608 |
+ t.Fatal(err) |
|
| 1609 |
+ } |
|
| 1610 |
+ |
|
| 1611 |
+ // restart the daemon |
|
| 1612 |
+ if err := s.d.Start("--live-restore"); err != nil {
|
|
| 1613 |
+ t.Fatal(err) |
|
| 1614 |
+ } |
|
| 1615 |
+ |
|
| 1616 |
+ // start a new container, the new container's ip should not be the same with |
|
| 1617 |
+ // old running container. |
|
| 1618 |
+ newCon := "new" |
|
| 1619 |
+ _, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top")
|
|
| 1620 |
+ if err != nil {
|
|
| 1621 |
+ t.Fatal(err) |
|
| 1622 |
+ } |
|
| 1623 |
+ newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon)
|
|
| 1624 |
+ if err != nil {
|
|
| 1625 |
+ t.Fatal(err) |
|
| 1626 |
+ } |
|
| 1627 |
+ if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 {
|
|
| 1628 |
+ t.Fatalf("new container ip should not equal to old running container ip")
|
|
| 1629 |
+ } |
|
| 1630 |
+ |
|
| 1631 |
+ // start a new container, the new container should ping old running container |
|
| 1632 |
+ _, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP)
|
|
| 1633 |
+ if err != nil {
|
|
| 1634 |
+ t.Fatal(err) |
|
| 1635 |
+ } |
|
| 1636 |
+ |
|
| 1637 |
+ // start a new container try to publist port 80:80 will failed |
|
| 1638 |
+ out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
|
|
| 1639 |
+ if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") {
|
|
| 1640 |
+ t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container")
|
|
| 1641 |
+ } |
|
| 1642 |
+ |
|
| 1643 |
+ // kill old running container and try to allocate again |
|
| 1644 |
+ _, err = s.d.Cmd("kill", oldCon)
|
|
| 1645 |
+ if err != nil {
|
|
| 1646 |
+ t.Fatal(err) |
|
| 1647 |
+ } |
|
| 1648 |
+ _, err = s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
|
|
| 1649 |
+ if err != nil {
|
|
| 1650 |
+ t.Fatal(err) |
|
| 1651 |
+ } |
|
| 1652 |
+} |
| ... | ... |
@@ -15,9 +15,10 @@ import ( |
| 15 | 15 |
|
| 16 | 16 |
// Config encapsulates configurations of various Libnetwork components |
| 17 | 17 |
type Config struct {
|
| 18 |
- Daemon DaemonCfg |
|
| 19 |
- Cluster ClusterCfg |
|
| 20 |
- Scopes map[string]*datastore.ScopeCfg |
|
| 18 |
+ Daemon DaemonCfg |
|
| 19 |
+ Cluster ClusterCfg |
|
| 20 |
+ Scopes map[string]*datastore.ScopeCfg |
|
| 21 |
+ ActiveSandboxes map[string]interface{}
|
|
| 21 | 22 |
} |
| 22 | 23 |
|
| 23 | 24 |
// DaemonCfg represents libnetwork core configuration |
| ... | ... |
@@ -245,3 +246,11 @@ func OptionLocalKVProviderConfig(config *store.Config) Option {
|
| 245 | 245 |
c.Scopes[datastore.LocalScope].Client.Config = config |
| 246 | 246 |
} |
| 247 | 247 |
} |
| 248 |
+ |
|
| 249 |
+// OptionActiveSandboxes function returns an option setter for passing the sandboxes |
|
| 250 |
+// which were active during previous daemon life |
|
| 251 |
+func OptionActiveSandboxes(sandboxes map[string]interface{}) Option {
|
|
| 252 |
+ return func(c *Config) {
|
|
| 253 |
+ c.ActiveSandboxes = sandboxes |
|
| 254 |
+ } |
|
| 255 |
+} |
| ... | ... |
@@ -203,15 +203,13 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
|
| 203 | 203 |
} |
| 204 | 204 |
} |
| 205 | 205 |
|
| 206 |
- // Reserve pools first before doing cleanup. This is because |
|
| 207 |
- // if the pools are not populated properly, the cleanups of |
|
| 208 |
- // endpoint/network and sandbox below will not be able to |
|
| 209 |
- // release ip subnets and addresses properly into the pool |
|
| 210 |
- // because the pools won't exist. |
|
| 206 |
+ // Reserve pools first before doing cleanup. Otherwise the |
|
| 207 |
+ // cleanups of endpoint/network and sandbox below will |
|
| 208 |
+ // generate many unnecessary warnings |
|
| 211 | 209 |
c.reservePools() |
| 212 | 210 |
|
| 213 | 211 |
// Cleanup resources |
| 214 |
- c.sandboxCleanup() |
|
| 212 |
+ c.sandboxCleanup(c.cfg.ActiveSandboxes) |
|
| 215 | 213 |
c.cleanupLocalEndpoints() |
| 216 | 214 |
c.networkCleanup() |
| 217 | 215 |
|
| ... | ... |
@@ -671,9 +669,27 @@ func (c *controller) reservePools() {
|
| 671 | 671 |
c.Gateway = n.ipamV6Info[i].Gateway.IP.String() |
| 672 | 672 |
} |
| 673 | 673 |
} |
| 674 |
+ // Reserve pools |
|
| 674 | 675 |
if err := n.ipamAllocate(); err != nil {
|
| 675 | 676 |
log.Warnf("Failed to allocate ipam pool(s) for network %q (%s): %v", n.Name(), n.ID(), err)
|
| 676 | 677 |
} |
| 678 |
+ // Reserve existing endpoints' addresses |
|
| 679 |
+ ipam, _, err := n.getController().getIPAMDriver(n.ipamType) |
|
| 680 |
+ if err != nil {
|
|
| 681 |
+ log.Warnf("Failed to retrieve ipam driver for network %q (%s) during address reservation", n.Name(), n.ID())
|
|
| 682 |
+ continue |
|
| 683 |
+ } |
|
| 684 |
+ epl, err := n.getEndpointsFromStore() |
|
| 685 |
+ if err != nil {
|
|
| 686 |
+ log.Warnf("Failed to retrieve list of current endpoints on network %q (%s)", n.Name(), n.ID())
|
|
| 687 |
+ continue |
|
| 688 |
+ } |
|
| 689 |
+ for _, ep := range epl {
|
|
| 690 |
+ if err := ep.assignAddress(ipam, true, ep.Iface().AddressIPv6() != nil); err != nil {
|
|
| 691 |
+ log.Warnf("Failed to reserve current adress for endpoint %q (%s) on network %q (%s)",
|
|
| 692 |
+ ep.Name(), ep.ID(), n.Name(), n.ID()) |
|
| 693 |
+ } |
|
| 694 |
+ } |
|
| 677 | 695 |
} |
| 678 | 696 |
} |
| 679 | 697 |
|
| ... | ... |
@@ -832,7 +848,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s |
| 832 | 832 |
|
| 833 | 833 |
if sb.config.useDefaultSandBox {
|
| 834 | 834 |
c.sboxOnce.Do(func() {
|
| 835 |
- c.defOsSbox, err = osl.NewSandbox(sb.Key(), false) |
|
| 835 |
+ c.defOsSbox, err = osl.NewSandbox(sb.Key(), false, false) |
|
| 836 | 836 |
}) |
| 837 | 837 |
|
| 838 | 838 |
if err != nil {
|
| ... | ... |
@@ -844,7 +860,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s |
| 844 | 844 |
} |
| 845 | 845 |
|
| 846 | 846 |
if sb.osSbox == nil && !sb.config.useExternalKey {
|
| 847 |
- if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil {
|
|
| 847 |
+ if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox, false); err != nil {
|
|
| 848 | 848 |
return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
|
| 849 | 849 |
} |
| 850 | 850 |
} |
| ... | ... |
@@ -86,25 +86,52 @@ out: |
| 86 | 86 |
return kmap, nil |
| 87 | 87 |
} |
| 88 | 88 |
|
| 89 |
-func (c *cache) add(kvObject KVObject) error {
|
|
| 89 |
+func (c *cache) add(kvObject KVObject, atomic bool) error {
|
|
| 90 | 90 |
kmap, err := c.kmap(kvObject) |
| 91 | 91 |
if err != nil {
|
| 92 | 92 |
return err |
| 93 | 93 |
} |
| 94 | 94 |
|
| 95 | 95 |
c.Lock() |
| 96 |
+ // If atomic is true, cache needs to maintain its own index |
|
| 97 |
+ // for atomicity and the add needs to be atomic. |
|
| 98 |
+ if atomic {
|
|
| 99 |
+ if prev, ok := kmap[Key(kvObject.Key()...)]; ok {
|
|
| 100 |
+ if prev.Index() != kvObject.Index() {
|
|
| 101 |
+ c.Unlock() |
|
| 102 |
+ return ErrKeyModified |
|
| 103 |
+ } |
|
| 104 |
+ } |
|
| 105 |
+ |
|
| 106 |
+ // Increment index |
|
| 107 |
+ index := kvObject.Index() |
|
| 108 |
+ index++ |
|
| 109 |
+ kvObject.SetIndex(index) |
|
| 110 |
+ } |
|
| 111 |
+ |
|
| 96 | 112 |
kmap[Key(kvObject.Key()...)] = kvObject |
| 97 | 113 |
c.Unlock() |
| 98 | 114 |
return nil |
| 99 | 115 |
} |
| 100 | 116 |
|
| 101 |
-func (c *cache) del(kvObject KVObject) error {
|
|
| 117 |
+func (c *cache) del(kvObject KVObject, atomic bool) error {
|
|
| 102 | 118 |
kmap, err := c.kmap(kvObject) |
| 103 | 119 |
if err != nil {
|
| 104 | 120 |
return err |
| 105 | 121 |
} |
| 106 | 122 |
|
| 107 | 123 |
c.Lock() |
| 124 |
+ // If atomic is true, cache needs to maintain its own index |
|
| 125 |
+ // for atomicity and del needs to be atomic. |
|
| 126 |
+ if atomic {
|
|
| 127 |
+ if prev, ok := kmap[Key(kvObject.Key()...)]; ok {
|
|
| 128 |
+ if prev.Index() != kvObject.Index() {
|
|
| 129 |
+ c.Unlock() |
|
| 130 |
+ return ErrKeyModified |
|
| 131 |
+ } |
|
| 132 |
+ } |
|
| 133 |
+ } |
|
| 134 |
+ |
|
| 108 | 135 |
delete(kmap, Key(kvObject.Key()...)) |
| 109 | 136 |
c.Unlock() |
| 110 | 137 |
return nil |
| ... | ... |
@@ -410,7 +410,9 @@ func (ds *datastore) PutObjectAtomic(kvObject KVObject) error {
|
| 410 | 410 |
|
| 411 | 411 |
add_cache: |
| 412 | 412 |
if ds.cache != nil {
|
| 413 |
- return ds.cache.add(kvObject) |
|
| 413 |
+ // If persistent store is skipped, sequencing needs to |
|
| 414 |
+ // happen in cache. |
|
| 415 |
+ return ds.cache.add(kvObject, kvObject.Skip()) |
|
| 414 | 416 |
} |
| 415 | 417 |
|
| 416 | 418 |
return nil |
| ... | ... |
@@ -435,7 +437,9 @@ func (ds *datastore) PutObject(kvObject KVObject) error {
|
| 435 | 435 |
|
| 436 | 436 |
add_cache: |
| 437 | 437 |
if ds.cache != nil {
|
| 438 |
- return ds.cache.add(kvObject) |
|
| 438 |
+ // If persistent store is skipped, sequencing needs to |
|
| 439 |
+ // happen in cache. |
|
| 440 |
+ return ds.cache.add(kvObject, kvObject.Skip()) |
|
| 439 | 441 |
} |
| 440 | 442 |
|
| 441 | 443 |
return nil |
| ... | ... |
@@ -537,7 +541,9 @@ func (ds *datastore) DeleteObject(kvObject KVObject) error {
|
| 537 | 537 |
|
| 538 | 538 |
// cleaup the cache first |
| 539 | 539 |
if ds.cache != nil {
|
| 540 |
- ds.cache.del(kvObject) |
|
| 540 |
+ // If persistent store is skipped, sequencing needs to |
|
| 541 |
+ // happen in cache. |
|
| 542 |
+ ds.cache.del(kvObject, kvObject.Skip()) |
|
| 541 | 543 |
} |
| 542 | 544 |
|
| 543 | 545 |
if kvObject.Skip() {
|
| ... | ... |
@@ -572,7 +578,9 @@ func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
|
| 572 | 572 |
del_cache: |
| 573 | 573 |
// cleanup the cache only if AtomicDelete went through successfully |
| 574 | 574 |
if ds.cache != nil {
|
| 575 |
- return ds.cache.del(kvObject) |
|
| 575 |
+ // If persistent store is skipped, sequencing needs to |
|
| 576 |
+ // happen in cache. |
|
| 577 |
+ return ds.cache.del(kvObject, kvObject.Skip()) |
|
| 576 | 578 |
} |
| 577 | 579 |
|
| 578 | 580 |
return nil |
| ... | ... |
@@ -585,7 +593,9 @@ func (ds *datastore) DeleteTree(kvObject KVObject) error {
|
| 585 | 585 |
|
| 586 | 586 |
// cleaup the cache first |
| 587 | 587 |
if ds.cache != nil {
|
| 588 |
- ds.cache.del(kvObject) |
|
| 588 |
+ // If persistent store is skipped, sequencing needs to |
|
| 589 |
+ // happen in cache. |
|
| 590 |
+ ds.cache.del(kvObject, kvObject.Skip()) |
|
| 589 | 591 |
} |
| 590 | 592 |
|
| 591 | 593 |
if kvObject.Skip() {
|
| ... | ... |
@@ -91,6 +91,7 @@ type connectivityConfiguration struct {
|
| 91 | 91 |
|
| 92 | 92 |
type bridgeEndpoint struct {
|
| 93 | 93 |
id string |
| 94 |
+ nid string |
|
| 94 | 95 |
srcName string |
| 95 | 96 |
addr *net.IPNet |
| 96 | 97 |
addrv6 *net.IPNet |
| ... | ... |
@@ -99,6 +100,8 @@ type bridgeEndpoint struct {
|
| 99 | 99 |
containerConfig *containerConfiguration |
| 100 | 100 |
extConnConfig *connectivityConfiguration |
| 101 | 101 |
portMapping []types.PortBinding // Operation port bindings |
| 102 |
+ dbIndex uint64 |
|
| 103 |
+ dbExists bool |
|
| 102 | 104 |
} |
| 103 | 105 |
|
| 104 | 106 |
type bridgeNetwork struct {
|
| ... | ... |
@@ -882,7 +885,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 882 | 882 |
|
| 883 | 883 |
// Create and add the endpoint |
| 884 | 884 |
n.Lock() |
| 885 |
- endpoint := &bridgeEndpoint{id: eid, config: epConfig}
|
|
| 885 |
+ endpoint := &bridgeEndpoint{id: eid, nid: nid, config: epConfig}
|
|
| 886 | 886 |
n.endpoints[eid] = endpoint |
| 887 | 887 |
n.Unlock() |
| 888 | 888 |
|
| ... | ... |
@@ -1009,6 +1012,10 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 1009 | 1009 |
} |
| 1010 | 1010 |
} |
| 1011 | 1011 |
|
| 1012 |
+ if err = d.storeUpdate(endpoint); err != nil {
|
|
| 1013 |
+ return fmt.Errorf("failed to save bridge endpoint %s to store: %v", ep.id[0:7], err)
|
|
| 1014 |
+ } |
|
| 1015 |
+ |
|
| 1012 | 1016 |
return nil |
| 1013 | 1017 |
} |
| 1014 | 1018 |
|
| ... | ... |
@@ -1069,6 +1076,10 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
|
| 1069 | 1069 |
d.nlh.LinkDel(link) |
| 1070 | 1070 |
} |
| 1071 | 1071 |
|
| 1072 |
+ if err := d.storeDelete(ep); err != nil {
|
|
| 1073 |
+ logrus.Warnf("Failed to remove bridge endpoint %s from store: %v", ep.id[0:7], err)
|
|
| 1074 |
+ } |
|
| 1075 |
+ |
|
| 1072 | 1076 |
return nil |
| 1073 | 1077 |
} |
| 1074 | 1078 |
|
| ... | ... |
@@ -1225,6 +1236,11 @@ func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string |
| 1225 | 1225 |
return err |
| 1226 | 1226 |
} |
| 1227 | 1227 |
|
| 1228 |
+ if err = d.storeUpdate(endpoint); err != nil {
|
|
| 1229 |
+ endpoint.portMapping = nil |
|
| 1230 |
+ return fmt.Errorf("failed to update bridge endpoint %s to store: %v", endpoint.id[0:7], err)
|
|
| 1231 |
+ } |
|
| 1232 |
+ |
|
| 1228 | 1233 |
if !network.config.EnableICC {
|
| 1229 | 1234 |
return d.link(network, endpoint, true) |
| 1230 | 1235 |
} |
| ... | ... |
@@ -12,7 +12,13 @@ import ( |
| 12 | 12 |
"github.com/docker/libnetwork/types" |
| 13 | 13 |
) |
| 14 | 14 |
|
| 15 |
-const bridgePrefix = "bridge" |
|
| 15 |
+const ( |
|
| 16 |
+ // network config prefix was not specific enough. |
|
| 17 |
+ // To be backward compatible, need custom endpoint |
|
| 18 |
+ // prefix with different root |
|
| 19 |
+ bridgePrefix = "bridge" |
|
| 20 |
+ bridgeEndpointPrefix = "bridge-endpoint" |
|
| 21 |
+) |
|
| 16 | 22 |
|
| 17 | 23 |
func (d *driver) initStore(option map[string]interface{}) error {
|
| 18 | 24 |
if data, ok := option[netlabel.LocalKVClient]; ok {
|
| ... | ... |
@@ -26,7 +32,15 @@ func (d *driver) initStore(option map[string]interface{}) error {
|
| 26 | 26 |
return types.InternalErrorf("bridge driver failed to initialize data store: %v", err)
|
| 27 | 27 |
} |
| 28 | 28 |
|
| 29 |
- return d.populateNetworks() |
|
| 29 |
+ err = d.populateNetworks() |
|
| 30 |
+ if err != nil {
|
|
| 31 |
+ return err |
|
| 32 |
+ } |
|
| 33 |
+ |
|
| 34 |
+ err = d.populateEndpoints() |
|
| 35 |
+ if err != nil {
|
|
| 36 |
+ return err |
|
| 37 |
+ } |
|
| 30 | 38 |
} |
| 31 | 39 |
|
| 32 | 40 |
return nil |
| ... | ... |
@@ -48,6 +62,36 @@ func (d *driver) populateNetworks() error {
|
| 48 | 48 |
if err = d.createNetwork(ncfg); err != nil {
|
| 49 | 49 |
logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state: %v", ncfg.ID, ncfg.BridgeName, err)
|
| 50 | 50 |
} |
| 51 |
+ logrus.Debugf("Network (%s) restored", ncfg.ID[0:7])
|
|
| 52 |
+ } |
|
| 53 |
+ |
|
| 54 |
+ return nil |
|
| 55 |
+} |
|
| 56 |
+ |
|
| 57 |
+func (d *driver) populateEndpoints() error {
|
|
| 58 |
+ kvol, err := d.store.List(datastore.Key(bridgeEndpointPrefix), &bridgeEndpoint{})
|
|
| 59 |
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
| 60 |
+ return fmt.Errorf("failed to get bridge endpoints from store: %v", err)
|
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ if err == datastore.ErrKeyNotFound {
|
|
| 64 |
+ return nil |
|
| 65 |
+ } |
|
| 66 |
+ |
|
| 67 |
+ for _, kvo := range kvol {
|
|
| 68 |
+ ep := kvo.(*bridgeEndpoint) |
|
| 69 |
+ n, ok := d.networks[ep.nid] |
|
| 70 |
+ if !ok {
|
|
| 71 |
+ logrus.Debugf("Network (%s) not found for restored bridge endpoint (%s)", ep.nid[0:7], ep.id[0:7])
|
|
| 72 |
+ logrus.Debugf("Deleting stale bridge endpoint (%s) from store", ep.nid[0:7])
|
|
| 73 |
+ if err := d.storeDelete(ep); err != nil {
|
|
| 74 |
+ logrus.Debugf("Failed to delete stale bridge endpoint (%s) from store", ep.nid[0:7])
|
|
| 75 |
+ } |
|
| 76 |
+ continue |
|
| 77 |
+ } |
|
| 78 |
+ n.endpoints[ep.id] = ep |
|
| 79 |
+ n.restorePortAllocations(ep) |
|
| 80 |
+ logrus.Debugf("Endpoint (%s) restored to network (%s)", ep.id[0:7], ep.nid[0:7])
|
|
| 51 | 81 |
} |
| 52 | 82 |
|
| 53 | 83 |
return nil |
| ... | ... |
@@ -184,7 +228,7 @@ func (ncfg *networkConfiguration) Exists() bool {
|
| 184 | 184 |
} |
| 185 | 185 |
|
| 186 | 186 |
func (ncfg *networkConfiguration) Skip() bool {
|
| 187 |
- return ncfg.DefaultBridge |
|
| 187 |
+ return false |
|
| 188 | 188 |
} |
| 189 | 189 |
|
| 190 | 190 |
func (ncfg *networkConfiguration) New() datastore.KVObject {
|
| ... | ... |
@@ -200,3 +244,135 @@ func (ncfg *networkConfiguration) CopyTo(o datastore.KVObject) error {
|
| 200 | 200 |
func (ncfg *networkConfiguration) DataScope() string {
|
| 201 | 201 |
return datastore.LocalScope |
| 202 | 202 |
} |
| 203 |
+ |
|
| 204 |
+func (ep *bridgeEndpoint) MarshalJSON() ([]byte, error) {
|
|
| 205 |
+ epMap := make(map[string]interface{})
|
|
| 206 |
+ epMap["id"] = ep.id |
|
| 207 |
+ epMap["nid"] = ep.nid |
|
| 208 |
+ epMap["SrcName"] = ep.srcName |
|
| 209 |
+ epMap["MacAddress"] = ep.macAddress.String() |
|
| 210 |
+ epMap["Addr"] = ep.addr.String() |
|
| 211 |
+ if ep.addrv6 != nil {
|
|
| 212 |
+ epMap["Addrv6"] = ep.addrv6.String() |
|
| 213 |
+ } |
|
| 214 |
+ epMap["Config"] = ep.config |
|
| 215 |
+ epMap["ContainerConfig"] = ep.containerConfig |
|
| 216 |
+ epMap["ExternalConnConfig"] = ep.extConnConfig |
|
| 217 |
+ epMap["PortMapping"] = ep.portMapping |
|
| 218 |
+ |
|
| 219 |
+ return json.Marshal(epMap) |
|
| 220 |
+} |
|
| 221 |
+ |
|
| 222 |
+func (ep *bridgeEndpoint) UnmarshalJSON(b []byte) error {
|
|
| 223 |
+ var ( |
|
| 224 |
+ err error |
|
| 225 |
+ epMap map[string]interface{}
|
|
| 226 |
+ ) |
|
| 227 |
+ |
|
| 228 |
+ if err = json.Unmarshal(b, &epMap); err != nil {
|
|
| 229 |
+ return fmt.Errorf("Failed to unmarshal to bridge endpoint: %v", err)
|
|
| 230 |
+ } |
|
| 231 |
+ |
|
| 232 |
+ if v, ok := epMap["MacAddress"]; ok {
|
|
| 233 |
+ if ep.macAddress, err = net.ParseMAC(v.(string)); err != nil {
|
|
| 234 |
+ return types.InternalErrorf("failed to decode bridge endpoint MAC address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 235 |
+ } |
|
| 236 |
+ } |
|
| 237 |
+ if v, ok := epMap["Addr"]; ok {
|
|
| 238 |
+ if ep.addr, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 239 |
+ return types.InternalErrorf("failed to decode bridge endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 240 |
+ } |
|
| 241 |
+ } |
|
| 242 |
+ if v, ok := epMap["Addrv6"]; ok {
|
|
| 243 |
+ if ep.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 244 |
+ return types.InternalErrorf("failed to decode bridge endpoint IPv6 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 245 |
+ } |
|
| 246 |
+ } |
|
| 247 |
+ ep.id = epMap["id"].(string) |
|
| 248 |
+ ep.nid = epMap["nid"].(string) |
|
| 249 |
+ ep.srcName = epMap["SrcName"].(string) |
|
| 250 |
+ d, _ := json.Marshal(epMap["Config"]) |
|
| 251 |
+ if err := json.Unmarshal(d, &ep.config); err != nil {
|
|
| 252 |
+ logrus.Warnf("Failed to decode endpoint config %v", err)
|
|
| 253 |
+ } |
|
| 254 |
+ d, _ = json.Marshal(epMap["ContainerConfig"]) |
|
| 255 |
+ if err := json.Unmarshal(d, &ep.containerConfig); err != nil {
|
|
| 256 |
+ logrus.Warnf("Failed to decode endpoint container config %v", err)
|
|
| 257 |
+ } |
|
| 258 |
+ d, _ = json.Marshal(epMap["ExternalConnConfig"]) |
|
| 259 |
+ if err := json.Unmarshal(d, &ep.extConnConfig); err != nil {
|
|
| 260 |
+ logrus.Warnf("Failed to decode endpoint external connectivity configuration %v", err)
|
|
| 261 |
+ } |
|
| 262 |
+ d, _ = json.Marshal(epMap["PortMapping"]) |
|
| 263 |
+ if err := json.Unmarshal(d, &ep.portMapping); err != nil {
|
|
| 264 |
+ logrus.Warnf("Failed to decode endpoint port mapping %v", err)
|
|
| 265 |
+ } |
|
| 266 |
+ |
|
| 267 |
+ return nil |
|
| 268 |
+} |
|
| 269 |
+ |
|
| 270 |
+func (ep *bridgeEndpoint) Key() []string {
|
|
| 271 |
+ return []string{bridgeEndpointPrefix, ep.id}
|
|
| 272 |
+} |
|
| 273 |
+ |
|
| 274 |
+func (ep *bridgeEndpoint) KeyPrefix() []string {
|
|
| 275 |
+ return []string{bridgeEndpointPrefix}
|
|
| 276 |
+} |
|
| 277 |
+ |
|
| 278 |
+func (ep *bridgeEndpoint) Value() []byte {
|
|
| 279 |
+ b, err := json.Marshal(ep) |
|
| 280 |
+ if err != nil {
|
|
| 281 |
+ return nil |
|
| 282 |
+ } |
|
| 283 |
+ return b |
|
| 284 |
+} |
|
| 285 |
+ |
|
| 286 |
+func (ep *bridgeEndpoint) SetValue(value []byte) error {
|
|
| 287 |
+ return json.Unmarshal(value, ep) |
|
| 288 |
+} |
|
| 289 |
+ |
|
| 290 |
+func (ep *bridgeEndpoint) Index() uint64 {
|
|
| 291 |
+ return ep.dbIndex |
|
| 292 |
+} |
|
| 293 |
+ |
|
| 294 |
+func (ep *bridgeEndpoint) SetIndex(index uint64) {
|
|
| 295 |
+ ep.dbIndex = index |
|
| 296 |
+ ep.dbExists = true |
|
| 297 |
+} |
|
| 298 |
+ |
|
| 299 |
+func (ep *bridgeEndpoint) Exists() bool {
|
|
| 300 |
+ return ep.dbExists |
|
| 301 |
+} |
|
| 302 |
+ |
|
| 303 |
+func (ep *bridgeEndpoint) Skip() bool {
|
|
| 304 |
+ return false |
|
| 305 |
+} |
|
| 306 |
+ |
|
| 307 |
+func (ep *bridgeEndpoint) New() datastore.KVObject {
|
|
| 308 |
+ return &bridgeEndpoint{}
|
|
| 309 |
+} |
|
| 310 |
+ |
|
| 311 |
+func (ep *bridgeEndpoint) CopyTo(o datastore.KVObject) error {
|
|
| 312 |
+ dstEp := o.(*bridgeEndpoint) |
|
| 313 |
+ *dstEp = *ep |
|
| 314 |
+ return nil |
|
| 315 |
+} |
|
| 316 |
+ |
|
| 317 |
+func (ep *bridgeEndpoint) DataScope() string {
|
|
| 318 |
+ return datastore.LocalScope |
|
| 319 |
+} |
|
| 320 |
+ |
|
| 321 |
+func (n *bridgeNetwork) restorePortAllocations(ep *bridgeEndpoint) {
|
|
| 322 |
+ if ep.extConnConfig == nil || |
|
| 323 |
+ ep.extConnConfig.ExposedPorts == nil || |
|
| 324 |
+ ep.extConnConfig.PortBindings == nil {
|
|
| 325 |
+ return |
|
| 326 |
+ } |
|
| 327 |
+ tmp := ep.extConnConfig.PortBindings |
|
| 328 |
+ ep.extConnConfig.PortBindings = ep.portMapping |
|
| 329 |
+ _, err := n.allocatePorts(ep, n.config.DefaultBindingIP, n.driver.config.EnableUserlandProxy) |
|
| 330 |
+ if err != nil {
|
|
| 331 |
+ logrus.Warnf("Failed to reserve existing port mapping for endpoint %s:%v", ep.id[0:7], err)
|
|
| 332 |
+ } |
|
| 333 |
+ ep.extConnConfig.PortBindings = tmp |
|
| 334 |
+} |
| ... | ... |
@@ -36,11 +36,14 @@ type driver struct {
|
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 | 38 |
type endpoint struct {
|
| 39 |
- id string |
|
| 40 |
- mac net.HardwareAddr |
|
| 41 |
- addr *net.IPNet |
|
| 42 |
- addrv6 *net.IPNet |
|
| 43 |
- srcName string |
|
| 39 |
+ id string |
|
| 40 |
+ nid string |
|
| 41 |
+ mac net.HardwareAddr |
|
| 42 |
+ addr *net.IPNet |
|
| 43 |
+ addrv6 *net.IPNet |
|
| 44 |
+ srcName string |
|
| 45 |
+ dbIndex uint64 |
|
| 46 |
+ dbExists bool |
|
| 44 | 47 |
} |
| 45 | 48 |
|
| 46 | 49 |
type network struct {
|
| ... | ... |
@@ -28,9 +28,9 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 28 | 28 |
} |
| 29 | 29 |
ep := &endpoint{
|
| 30 | 30 |
id: eid, |
| 31 |
+ nid: nid, |
|
| 31 | 32 |
addr: ifInfo.Address(), |
| 32 | 33 |
addrv6: ifInfo.AddressIPv6(), |
| 33 |
- mac: ifInfo.MacAddress(), |
|
| 34 | 34 |
} |
| 35 | 35 |
if ep.addr == nil {
|
| 36 | 36 |
return fmt.Errorf("create endpoint was not passed an IP address")
|
| ... | ... |
@@ -51,6 +51,11 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 51 | 51 |
} |
| 52 | 52 |
} |
| 53 | 53 |
} |
| 54 |
+ |
|
| 55 |
+ if err := d.storeUpdate(ep); err != nil {
|
|
| 56 |
+ return fmt.Errorf("failed to save ipvlan endpoint %s to store: %v", ep.id[0:7], err)
|
|
| 57 |
+ } |
|
| 58 |
+ |
|
| 54 | 59 |
n.addEndpoint(ep) |
| 55 | 60 |
|
| 56 | 61 |
return nil |
| ... | ... |
@@ -74,5 +79,9 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
|
| 74 | 74 |
ns.NlHandle().LinkDel(link) |
| 75 | 75 |
} |
| 76 | 76 |
|
| 77 |
+ if err := d.storeDelete(ep); err != nil {
|
|
| 78 |
+ logrus.Warnf("Failed to remove ipvlan endpoint %s from store: %v", ep.id[0:7], err)
|
|
| 79 |
+ } |
|
| 80 |
+ |
|
| 77 | 81 |
return nil |
| 78 | 82 |
} |
| ... | ... |
@@ -116,6 +116,9 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, |
| 116 | 116 |
if err != nil {
|
| 117 | 117 |
return err |
| 118 | 118 |
} |
| 119 |
+ if err = d.storeUpdate(ep); err != nil {
|
|
| 120 |
+ return fmt.Errorf("failed to save ipvlan endpoint %s to store: %v", ep.id[0:7], err)
|
|
| 121 |
+ } |
|
| 119 | 122 |
|
| 120 | 123 |
return nil |
| 121 | 124 |
} |
| ... | ... |
@@ -3,6 +3,7 @@ package ipvlan |
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"fmt" |
| 6 |
+ "net" |
|
| 6 | 7 |
|
| 7 | 8 |
"github.com/Sirupsen/logrus" |
| 8 | 9 |
"github.com/docker/libnetwork/datastore" |
| ... | ... |
@@ -11,7 +12,11 @@ import ( |
| 11 | 11 |
"github.com/docker/libnetwork/types" |
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 |
-const ipvlanPrefix = "ipvlan" // prefix used for persistent driver storage |
|
| 14 |
+const ( |
|
| 15 |
+ ipvlanPrefix = "ipvlan" |
|
| 16 |
+ ipvlanNetworkPrefix = ipvlanPrefix + "/network" |
|
| 17 |
+ ipvlanEndpointPrefix = ipvlanPrefix + "/endpoint" |
|
| 18 |
+) |
|
| 15 | 19 |
|
| 16 | 20 |
// networkConfiguration for this driver's network specific configuration |
| 17 | 21 |
type configuration struct {
|
| ... | ... |
@@ -58,7 +63,7 @@ func (d *driver) initStore(option map[string]interface{}) error {
|
| 58 | 58 |
|
| 59 | 59 |
// populateNetworks is invoked at driver init to recreate persistently stored networks |
| 60 | 60 |
func (d *driver) populateNetworks() error {
|
| 61 |
- kvol, err := d.store.List(datastore.Key(ipvlanPrefix), &configuration{})
|
|
| 61 |
+ kvol, err := d.store.List(datastore.Key(ipvlanNetworkPrefix), &configuration{})
|
|
| 62 | 62 |
if err != nil && err != datastore.ErrKeyNotFound {
|
| 63 | 63 |
return fmt.Errorf("failed to get ipvlan network configurations from store: %v", err)
|
| 64 | 64 |
} |
| ... | ... |
@@ -76,6 +81,34 @@ func (d *driver) populateNetworks() error {
|
| 76 | 76 |
return nil |
| 77 | 77 |
} |
| 78 | 78 |
|
| 79 |
+func (d *driver) populateEndpoints() error {
|
|
| 80 |
+ kvol, err := d.store.List(datastore.Key(ipvlanEndpointPrefix), &endpoint{})
|
|
| 81 |
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
| 82 |
+ return fmt.Errorf("failed to get ipvlan endpoints from store: %v", err)
|
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 85 |
+ if err == datastore.ErrKeyNotFound {
|
|
| 86 |
+ return nil |
|
| 87 |
+ } |
|
| 88 |
+ |
|
| 89 |
+ for _, kvo := range kvol {
|
|
| 90 |
+ ep := kvo.(*endpoint) |
|
| 91 |
+ n, ok := d.networks[ep.nid] |
|
| 92 |
+ if !ok {
|
|
| 93 |
+ logrus.Debugf("Network (%s) not found for restored ipvlan endpoint (%s)", ep.nid[0:7], ep.id[0:7])
|
|
| 94 |
+ logrus.Debugf("Deleting stale ipvlan endpoint (%s) from store", ep.nid[0:7])
|
|
| 95 |
+ if err := d.storeDelete(ep); err != nil {
|
|
| 96 |
+ logrus.Debugf("Failed to delete stale ipvlan endpoint (%s) from store", ep.nid[0:7])
|
|
| 97 |
+ } |
|
| 98 |
+ continue |
|
| 99 |
+ } |
|
| 100 |
+ n.endpoints[ep.id] = ep |
|
| 101 |
+ logrus.Debugf("Endpoint (%s) restored to network (%s)", ep.id[0:7], ep.nid[0:7])
|
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ return nil |
|
| 105 |
+} |
|
| 106 |
+ |
|
| 79 | 107 |
// storeUpdate used to update persistent ipvlan network records as they are created |
| 80 | 108 |
func (d *driver) storeUpdate(kvObject datastore.KVObject) error {
|
| 81 | 109 |
if d.store == nil {
|
| ... | ... |
@@ -165,11 +198,11 @@ func (config *configuration) UnmarshalJSON(b []byte) error {
|
| 165 | 165 |
} |
| 166 | 166 |
|
| 167 | 167 |
func (config *configuration) Key() []string {
|
| 168 |
- return []string{ipvlanPrefix, config.ID}
|
|
| 168 |
+ return []string{ipvlanNetworkPrefix, config.ID}
|
|
| 169 | 169 |
} |
| 170 | 170 |
|
| 171 | 171 |
func (config *configuration) KeyPrefix() []string {
|
| 172 |
- return []string{ipvlanPrefix}
|
|
| 172 |
+ return []string{ipvlanNetworkPrefix}
|
|
| 173 | 173 |
} |
| 174 | 174 |
|
| 175 | 175 |
func (config *configuration) Value() []byte {
|
| ... | ... |
@@ -214,3 +247,103 @@ func (config *configuration) CopyTo(o datastore.KVObject) error {
|
| 214 | 214 |
func (config *configuration) DataScope() string {
|
| 215 | 215 |
return datastore.LocalScope |
| 216 | 216 |
} |
| 217 |
+ |
|
| 218 |
+func (ep *endpoint) MarshalJSON() ([]byte, error) {
|
|
| 219 |
+ epMap := make(map[string]interface{})
|
|
| 220 |
+ epMap["id"] = ep.id |
|
| 221 |
+ epMap["nid"] = ep.nid |
|
| 222 |
+ epMap["SrcName"] = ep.srcName |
|
| 223 |
+ if len(ep.mac) != 0 {
|
|
| 224 |
+ epMap["MacAddress"] = ep.mac.String() |
|
| 225 |
+ } |
|
| 226 |
+ if ep.addr != nil {
|
|
| 227 |
+ epMap["Addr"] = ep.addr.String() |
|
| 228 |
+ } |
|
| 229 |
+ if ep.addrv6 != nil {
|
|
| 230 |
+ epMap["Addrv6"] = ep.addrv6.String() |
|
| 231 |
+ } |
|
| 232 |
+ return json.Marshal(epMap) |
|
| 233 |
+} |
|
| 234 |
+ |
|
| 235 |
+func (ep *endpoint) UnmarshalJSON(b []byte) error {
|
|
| 236 |
+ var ( |
|
| 237 |
+ err error |
|
| 238 |
+ epMap map[string]interface{}
|
|
| 239 |
+ ) |
|
| 240 |
+ |
|
| 241 |
+ if err = json.Unmarshal(b, &epMap); err != nil {
|
|
| 242 |
+ return fmt.Errorf("Failed to unmarshal to ipvlan endpoint: %v", err)
|
|
| 243 |
+ } |
|
| 244 |
+ |
|
| 245 |
+ if v, ok := epMap["MacAddress"]; ok {
|
|
| 246 |
+ if ep.mac, err = net.ParseMAC(v.(string)); err != nil {
|
|
| 247 |
+ return types.InternalErrorf("failed to decode ipvlan endpoint MAC address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 248 |
+ } |
|
| 249 |
+ } |
|
| 250 |
+ if v, ok := epMap["Addr"]; ok {
|
|
| 251 |
+ if ep.addr, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 252 |
+ return types.InternalErrorf("failed to decode ipvlan endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 253 |
+ } |
|
| 254 |
+ } |
|
| 255 |
+ if v, ok := epMap["Addrv6"]; ok {
|
|
| 256 |
+ if ep.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 257 |
+ return types.InternalErrorf("failed to decode ipvlan endpoint IPv6 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 258 |
+ } |
|
| 259 |
+ } |
|
| 260 |
+ ep.id = epMap["id"].(string) |
|
| 261 |
+ ep.nid = epMap["nid"].(string) |
|
| 262 |
+ ep.srcName = epMap["SrcName"].(string) |
|
| 263 |
+ |
|
| 264 |
+ return nil |
|
| 265 |
+} |
|
| 266 |
+ |
|
| 267 |
+func (ep *endpoint) Key() []string {
|
|
| 268 |
+ return []string{ipvlanEndpointPrefix, ep.id}
|
|
| 269 |
+} |
|
| 270 |
+ |
|
| 271 |
+func (ep *endpoint) KeyPrefix() []string {
|
|
| 272 |
+ return []string{ipvlanEndpointPrefix}
|
|
| 273 |
+} |
|
| 274 |
+ |
|
| 275 |
+func (ep *endpoint) Value() []byte {
|
|
| 276 |
+ b, err := json.Marshal(ep) |
|
| 277 |
+ if err != nil {
|
|
| 278 |
+ return nil |
|
| 279 |
+ } |
|
| 280 |
+ return b |
|
| 281 |
+} |
|
| 282 |
+ |
|
| 283 |
+func (ep *endpoint) SetValue(value []byte) error {
|
|
| 284 |
+ return json.Unmarshal(value, ep) |
|
| 285 |
+} |
|
| 286 |
+ |
|
| 287 |
+func (ep *endpoint) Index() uint64 {
|
|
| 288 |
+ return ep.dbIndex |
|
| 289 |
+} |
|
| 290 |
+ |
|
| 291 |
+func (ep *endpoint) SetIndex(index uint64) {
|
|
| 292 |
+ ep.dbIndex = index |
|
| 293 |
+ ep.dbExists = true |
|
| 294 |
+} |
|
| 295 |
+ |
|
| 296 |
+func (ep *endpoint) Exists() bool {
|
|
| 297 |
+ return ep.dbExists |
|
| 298 |
+} |
|
| 299 |
+ |
|
| 300 |
+func (ep *endpoint) Skip() bool {
|
|
| 301 |
+ return false |
|
| 302 |
+} |
|
| 303 |
+ |
|
| 304 |
+func (ep *endpoint) New() datastore.KVObject {
|
|
| 305 |
+ return &endpoint{}
|
|
| 306 |
+} |
|
| 307 |
+ |
|
| 308 |
+func (ep *endpoint) CopyTo(o datastore.KVObject) error {
|
|
| 309 |
+ dstEp := o.(*endpoint) |
|
| 310 |
+ *dstEp = *ep |
|
| 311 |
+ return nil |
|
| 312 |
+} |
|
| 313 |
+ |
|
| 314 |
+func (ep *endpoint) DataScope() string {
|
|
| 315 |
+ return datastore.LocalScope |
|
| 316 |
+} |
| ... | ... |
@@ -38,11 +38,14 @@ type driver struct {
|
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 | 40 |
type endpoint struct {
|
| 41 |
- id string |
|
| 42 |
- mac net.HardwareAddr |
|
| 43 |
- addr *net.IPNet |
|
| 44 |
- addrv6 *net.IPNet |
|
| 45 |
- srcName string |
|
| 41 |
+ id string |
|
| 42 |
+ nid string |
|
| 43 |
+ mac net.HardwareAddr |
|
| 44 |
+ addr *net.IPNet |
|
| 45 |
+ addrv6 *net.IPNet |
|
| 46 |
+ srcName string |
|
| 47 |
+ dbIndex uint64 |
|
| 48 |
+ dbExists bool |
|
| 46 | 49 |
} |
| 47 | 50 |
|
| 48 | 51 |
type network struct {
|
| ... | ... |
@@ -26,6 +26,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 26 | 26 |
} |
| 27 | 27 |
ep := &endpoint{
|
| 28 | 28 |
id: eid, |
| 29 |
+ nid: nid, |
|
| 29 | 30 |
addr: ifInfo.Address(), |
| 30 | 31 |
addrv6: ifInfo.AddressIPv6(), |
| 31 | 32 |
mac: ifInfo.MacAddress(), |
| ... | ... |
@@ -55,6 +56,11 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 55 | 55 |
} |
| 56 | 56 |
} |
| 57 | 57 |
} |
| 58 |
+ |
|
| 59 |
+ if err := d.storeUpdate(ep); err != nil {
|
|
| 60 |
+ return fmt.Errorf("failed to save macvlan endpoint %s to store: %v", ep.id[0:7], err)
|
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 58 | 63 |
n.addEndpoint(ep) |
| 59 | 64 |
|
| 60 | 65 |
return nil |
| ... | ... |
@@ -77,6 +83,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
|
| 77 | 77 |
if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil {
|
| 78 | 78 |
ns.NlHandle().LinkDel(link) |
| 79 | 79 |
} |
| 80 |
- |
|
| 80 |
+ if err := d.storeDelete(ep); err != nil {
|
|
| 81 |
+ logrus.Warnf("Failed to remove macvlan endpoint %s from store: %v", ep.id[0:7], err)
|
|
| 82 |
+ } |
|
| 81 | 83 |
return nil |
| 82 | 84 |
} |
| ... | ... |
@@ -77,7 +77,9 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, |
| 77 | 77 |
if err != nil {
|
| 78 | 78 |
return err |
| 79 | 79 |
} |
| 80 |
- |
|
| 80 |
+ if err := d.storeUpdate(ep); err != nil {
|
|
| 81 |
+ return fmt.Errorf("failed to save macvlan endpoint %s to store: %v", ep.id[0:7], err)
|
|
| 82 |
+ } |
|
| 81 | 83 |
return nil |
| 82 | 84 |
} |
| 83 | 85 |
|
| ... | ... |
@@ -3,6 +3,7 @@ package macvlan |
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"fmt" |
| 6 |
+ "net" |
|
| 6 | 7 |
|
| 7 | 8 |
"github.com/Sirupsen/logrus" |
| 8 | 9 |
"github.com/docker/libnetwork/datastore" |
| ... | ... |
@@ -11,7 +12,11 @@ import ( |
| 11 | 11 |
"github.com/docker/libnetwork/types" |
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 |
-const macvlanPrefix = "macvlan" // prefix used for persistent driver storage |
|
| 14 |
+const ( |
|
| 15 |
+ macvlanPrefix = "macvlan" |
|
| 16 |
+ macvlanNetworkPrefix = macvlanPrefix + "/network" |
|
| 17 |
+ macvlanEndpointPrefix = macvlanPrefix + "/endpoint" |
|
| 18 |
+) |
|
| 15 | 19 |
|
| 16 | 20 |
// networkConfiguration for this driver's network specific configuration |
| 17 | 21 |
type configuration struct {
|
| ... | ... |
@@ -76,6 +81,34 @@ func (d *driver) populateNetworks() error {
|
| 76 | 76 |
return nil |
| 77 | 77 |
} |
| 78 | 78 |
|
| 79 |
+func (d *driver) populateEndpoints() error {
|
|
| 80 |
+ kvol, err := d.store.List(datastore.Key(macvlanEndpointPrefix), &endpoint{})
|
|
| 81 |
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
| 82 |
+ return fmt.Errorf("failed to get macvlan endpoints from store: %v", err)
|
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 85 |
+ if err == datastore.ErrKeyNotFound {
|
|
| 86 |
+ return nil |
|
| 87 |
+ } |
|
| 88 |
+ |
|
| 89 |
+ for _, kvo := range kvol {
|
|
| 90 |
+ ep := kvo.(*endpoint) |
|
| 91 |
+ n, ok := d.networks[ep.nid] |
|
| 92 |
+ if !ok {
|
|
| 93 |
+ logrus.Debugf("Network (%s) not found for restored macvlan endpoint (%s)", ep.nid[0:7], ep.id[0:7])
|
|
| 94 |
+ logrus.Debugf("Deleting stale macvlan endpoint (%s) from store", ep.nid[0:7])
|
|
| 95 |
+ if err := d.storeDelete(ep); err != nil {
|
|
| 96 |
+ logrus.Debugf("Failed to delete stale macvlan endpoint (%s) from store", ep.nid[0:7])
|
|
| 97 |
+ } |
|
| 98 |
+ continue |
|
| 99 |
+ } |
|
| 100 |
+ n.endpoints[ep.id] = ep |
|
| 101 |
+ logrus.Debugf("Endpoint (%s) restored to network (%s)", ep.id[0:7], ep.nid[0:7])
|
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ return nil |
|
| 105 |
+} |
|
| 106 |
+ |
|
| 79 | 107 |
// storeUpdate used to update persistent macvlan network records as they are created |
| 80 | 108 |
func (d *driver) storeUpdate(kvObject datastore.KVObject) error {
|
| 81 | 109 |
if d.store == nil {
|
| ... | ... |
@@ -165,11 +198,11 @@ func (config *configuration) UnmarshalJSON(b []byte) error {
|
| 165 | 165 |
} |
| 166 | 166 |
|
| 167 | 167 |
func (config *configuration) Key() []string {
|
| 168 |
- return []string{macvlanPrefix, config.ID}
|
|
| 168 |
+ return []string{macvlanNetworkPrefix, config.ID}
|
|
| 169 | 169 |
} |
| 170 | 170 |
|
| 171 | 171 |
func (config *configuration) KeyPrefix() []string {
|
| 172 |
- return []string{macvlanPrefix}
|
|
| 172 |
+ return []string{macvlanNetworkPrefix}
|
|
| 173 | 173 |
} |
| 174 | 174 |
|
| 175 | 175 |
func (config *configuration) Value() []byte {
|
| ... | ... |
@@ -216,3 +249,103 @@ func (config *configuration) CopyTo(o datastore.KVObject) error {
|
| 216 | 216 |
func (config *configuration) DataScope() string {
|
| 217 | 217 |
return datastore.LocalScope |
| 218 | 218 |
} |
| 219 |
+ |
|
| 220 |
+func (ep *endpoint) MarshalJSON() ([]byte, error) {
|
|
| 221 |
+ epMap := make(map[string]interface{})
|
|
| 222 |
+ epMap["id"] = ep.id |
|
| 223 |
+ epMap["nid"] = ep.nid |
|
| 224 |
+ epMap["SrcName"] = ep.srcName |
|
| 225 |
+ if len(ep.mac) != 0 {
|
|
| 226 |
+ epMap["MacAddress"] = ep.mac.String() |
|
| 227 |
+ } |
|
| 228 |
+ if ep.addr != nil {
|
|
| 229 |
+ epMap["Addr"] = ep.addr.String() |
|
| 230 |
+ } |
|
| 231 |
+ if ep.addrv6 != nil {
|
|
| 232 |
+ epMap["Addrv6"] = ep.addrv6.String() |
|
| 233 |
+ } |
|
| 234 |
+ return json.Marshal(epMap) |
|
| 235 |
+} |
|
| 236 |
+ |
|
| 237 |
+func (ep *endpoint) UnmarshalJSON(b []byte) error {
|
|
| 238 |
+ var ( |
|
| 239 |
+ err error |
|
| 240 |
+ epMap map[string]interface{}
|
|
| 241 |
+ ) |
|
| 242 |
+ |
|
| 243 |
+ if err = json.Unmarshal(b, &epMap); err != nil {
|
|
| 244 |
+ return fmt.Errorf("Failed to unmarshal to macvlan endpoint: %v", err)
|
|
| 245 |
+ } |
|
| 246 |
+ |
|
| 247 |
+ if v, ok := epMap["MacAddress"]; ok {
|
|
| 248 |
+ if ep.mac, err = net.ParseMAC(v.(string)); err != nil {
|
|
| 249 |
+ return types.InternalErrorf("failed to decode macvlan endpoint MAC address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 250 |
+ } |
|
| 251 |
+ } |
|
| 252 |
+ if v, ok := epMap["Addr"]; ok {
|
|
| 253 |
+ if ep.addr, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 254 |
+ return types.InternalErrorf("failed to decode macvlan endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 255 |
+ } |
|
| 256 |
+ } |
|
| 257 |
+ if v, ok := epMap["Addrv6"]; ok {
|
|
| 258 |
+ if ep.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 259 |
+ return types.InternalErrorf("failed to decode macvlan endpoint IPv6 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 260 |
+ } |
|
| 261 |
+ } |
|
| 262 |
+ ep.id = epMap["id"].(string) |
|
| 263 |
+ ep.nid = epMap["nid"].(string) |
|
| 264 |
+ ep.srcName = epMap["SrcName"].(string) |
|
| 265 |
+ |
|
| 266 |
+ return nil |
|
| 267 |
+} |
|
| 268 |
+ |
|
| 269 |
+func (ep *endpoint) Key() []string {
|
|
| 270 |
+ return []string{macvlanEndpointPrefix, ep.id}
|
|
| 271 |
+} |
|
| 272 |
+ |
|
| 273 |
+func (ep *endpoint) KeyPrefix() []string {
|
|
| 274 |
+ return []string{macvlanEndpointPrefix}
|
|
| 275 |
+} |
|
| 276 |
+ |
|
| 277 |
+func (ep *endpoint) Value() []byte {
|
|
| 278 |
+ b, err := json.Marshal(ep) |
|
| 279 |
+ if err != nil {
|
|
| 280 |
+ return nil |
|
| 281 |
+ } |
|
| 282 |
+ return b |
|
| 283 |
+} |
|
| 284 |
+ |
|
| 285 |
+func (ep *endpoint) SetValue(value []byte) error {
|
|
| 286 |
+ return json.Unmarshal(value, ep) |
|
| 287 |
+} |
|
| 288 |
+ |
|
| 289 |
+func (ep *endpoint) Index() uint64 {
|
|
| 290 |
+ return ep.dbIndex |
|
| 291 |
+} |
|
| 292 |
+ |
|
| 293 |
+func (ep *endpoint) SetIndex(index uint64) {
|
|
| 294 |
+ ep.dbIndex = index |
|
| 295 |
+ ep.dbExists = true |
|
| 296 |
+} |
|
| 297 |
+ |
|
| 298 |
+func (ep *endpoint) Exists() bool {
|
|
| 299 |
+ return ep.dbExists |
|
| 300 |
+} |
|
| 301 |
+ |
|
| 302 |
+func (ep *endpoint) Skip() bool {
|
|
| 303 |
+ return false |
|
| 304 |
+} |
|
| 305 |
+ |
|
| 306 |
+func (ep *endpoint) New() datastore.KVObject {
|
|
| 307 |
+ return &endpoint{}
|
|
| 308 |
+} |
|
| 309 |
+ |
|
| 310 |
+func (ep *endpoint) CopyTo(o datastore.KVObject) error {
|
|
| 311 |
+ dstEp := o.(*endpoint) |
|
| 312 |
+ *dstEp = *ep |
|
| 313 |
+ return nil |
|
| 314 |
+} |
|
| 315 |
+ |
|
| 316 |
+func (ep *endpoint) DataScope() string {
|
|
| 317 |
+ return datastore.LocalScope |
|
| 318 |
+} |
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
|
| 11 | 11 |
log "github.com/Sirupsen/logrus" |
| 12 | 12 |
"github.com/docker/libnetwork/iptables" |
| 13 |
+ "github.com/docker/libnetwork/ns" |
|
| 13 | 14 |
"github.com/docker/libnetwork/types" |
| 14 | 15 |
"github.com/vishvananda/netlink" |
| 15 | 16 |
"strconv" |
| ... | ... |
@@ -214,12 +215,12 @@ func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (f |
| 214 | 214 |
var ( |
| 215 | 215 |
crypt *netlink.XfrmStateAlgo |
| 216 | 216 |
action = "Removing" |
| 217 |
- xfrmProgram = netlink.XfrmStateDel |
|
| 217 |
+ xfrmProgram = ns.NlHandle().XfrmStateDel |
|
| 218 | 218 |
) |
| 219 | 219 |
|
| 220 | 220 |
if add {
|
| 221 | 221 |
action = "Adding" |
| 222 |
- xfrmProgram = netlink.XfrmStateAdd |
|
| 222 |
+ xfrmProgram = ns.NlHandle().XfrmStateAdd |
|
| 223 | 223 |
crypt = &netlink.XfrmStateAlgo{Name: "cbc(aes)", Key: k.value}
|
| 224 | 224 |
} |
| 225 | 225 |
|
| ... | ... |
@@ -278,10 +279,10 @@ func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (f |
| 278 | 278 |
|
| 279 | 279 |
func programSP(fSA *netlink.XfrmState, rSA *netlink.XfrmState, add bool) error {
|
| 280 | 280 |
action := "Removing" |
| 281 |
- xfrmProgram := netlink.XfrmPolicyDel |
|
| 281 |
+ xfrmProgram := ns.NlHandle().XfrmPolicyDel |
|
| 282 | 282 |
if add {
|
| 283 | 283 |
action = "Adding" |
| 284 |
- xfrmProgram = netlink.XfrmPolicyAdd |
|
| 284 |
+ xfrmProgram = ns.NlHandle().XfrmPolicyAdd |
|
| 285 | 285 |
} |
| 286 | 286 |
|
| 287 | 287 |
fullMask := net.CIDRMask(8*len(fSA.Src), 8*len(fSA.Src)) |
| ... | ... |
@@ -322,7 +323,7 @@ func programSP(fSA *netlink.XfrmState, rSA *netlink.XfrmState, add bool) error {
|
| 322 | 322 |
} |
| 323 | 323 |
|
| 324 | 324 |
func saExists(sa *netlink.XfrmState) (bool, error) {
|
| 325 |
- _, err := netlink.XfrmStateGet(sa) |
|
| 325 |
+ _, err := ns.NlHandle().XfrmStateGet(sa) |
|
| 326 | 326 |
switch err {
|
| 327 | 327 |
case nil: |
| 328 | 328 |
return true, nil |
| ... | ... |
@@ -336,7 +337,7 @@ func saExists(sa *netlink.XfrmState) (bool, error) {
|
| 336 | 336 |
} |
| 337 | 337 |
|
| 338 | 338 |
func spExists(sp *netlink.XfrmPolicy) (bool, error) {
|
| 339 |
- _, err := netlink.XfrmPolicyGet(sp) |
|
| 339 |
+ _, err := ns.NlHandle().XfrmPolicyGet(sp) |
|
| 340 | 340 |
switch err {
|
| 341 | 341 |
case nil: |
| 342 | 342 |
return true, nil |
| ... | ... |
@@ -482,7 +483,7 @@ func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, |
| 482 | 482 |
Limits: netlink.XfrmStateLimits{TimeSoft: timeout},
|
| 483 | 483 |
} |
| 484 | 484 |
log.Infof("Updating rSA0{%s}", rSA0)
|
| 485 |
- if err := netlink.XfrmStateUpdate(rSA0); err != nil {
|
|
| 485 |
+ if err := ns.NlHandle().XfrmStateUpdate(rSA0); err != nil {
|
|
| 486 | 486 |
log.Warnf("Failed to update rSA0{%s}: %v", rSA0, err)
|
| 487 | 487 |
} |
| 488 | 488 |
} |
| ... | ... |
@@ -518,7 +519,7 @@ func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, |
| 518 | 518 |
}, |
| 519 | 519 |
} |
| 520 | 520 |
log.Infof("Updating fSP{%s}", fSP1)
|
| 521 |
- if err := netlink.XfrmPolicyUpdate(fSP1); err != nil {
|
|
| 521 |
+ if err := ns.NlHandle().XfrmPolicyUpdate(fSP1); err != nil {
|
|
| 522 | 522 |
log.Warnf("Failed to update fSP{%s}: %v", fSP1, err)
|
| 523 | 523 |
} |
| 524 | 524 |
|
| ... | ... |
@@ -533,7 +534,7 @@ func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, |
| 533 | 533 |
Limits: netlink.XfrmStateLimits{TimeHard: timeout},
|
| 534 | 534 |
} |
| 535 | 535 |
log.Infof("Removing fSA0{%s}", fSA0)
|
| 536 |
- if err := netlink.XfrmStateUpdate(fSA0); err != nil {
|
|
| 536 |
+ if err := ns.NlHandle().XfrmStateUpdate(fSA0); err != nil {
|
|
| 537 | 537 |
log.Warnf("Failed to remove fSA0{%s}: %v", fSA0, err)
|
| 538 | 538 |
} |
| 539 | 539 |
} |
| ... | ... |
@@ -40,11 +40,11 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, |
| 40 | 40 |
return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
|
| 41 | 41 |
} |
| 42 | 42 |
|
| 43 |
- if err := n.joinSandbox(); err != nil {
|
|
| 43 |
+ if err := n.joinSandbox(false); err != nil {
|
|
| 44 | 44 |
return fmt.Errorf("network sandbox join failed: %v", err)
|
| 45 | 45 |
} |
| 46 | 46 |
|
| 47 |
- if err := n.joinSubnetSandbox(s); err != nil {
|
|
| 47 |
+ if err := n.joinSubnetSandbox(s, false); err != nil {
|
|
| 48 | 48 |
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
|
| 49 | 49 |
} |
| 50 | 50 |
|
| ... | ... |
@@ -61,6 +61,10 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, |
| 61 | 61 |
|
| 62 | 62 |
ep.ifName = containerIfName |
| 63 | 63 |
|
| 64 |
+ if err := d.writeEndpointToStore(ep); err != nil {
|
|
| 65 |
+ return fmt.Errorf("failed to update overlay endpoint %s to local data store: %v", ep.id[0:7], err)
|
|
| 66 |
+ } |
|
| 67 |
+ |
|
| 64 | 68 |
nlh := ns.NlHandle() |
| 65 | 69 |
|
| 66 | 70 |
// Set the container interface and its peer MTU to 1450 to allow |
| ... | ... |
@@ -1,22 +1,30 @@ |
| 1 | 1 |
package overlay |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "encoding/json" |
|
| 4 | 5 |
"fmt" |
| 5 | 6 |
"net" |
| 6 | 7 |
|
| 7 | 8 |
log "github.com/Sirupsen/logrus" |
| 9 |
+ "github.com/docker/libnetwork/datastore" |
|
| 8 | 10 |
"github.com/docker/libnetwork/driverapi" |
| 9 | 11 |
"github.com/docker/libnetwork/netutils" |
| 10 | 12 |
"github.com/docker/libnetwork/ns" |
| 13 |
+ "github.com/docker/libnetwork/types" |
|
| 11 | 14 |
) |
| 12 | 15 |
|
| 13 | 16 |
type endpointTable map[string]*endpoint |
| 14 | 17 |
|
| 18 |
+const overlayEndpointPrefix = "overlay/endpoint" |
|
| 19 |
+ |
|
| 15 | 20 |
type endpoint struct {
|
| 16 |
- id string |
|
| 17 |
- ifName string |
|
| 18 |
- mac net.HardwareAddr |
|
| 19 |
- addr *net.IPNet |
|
| 21 |
+ id string |
|
| 22 |
+ nid string |
|
| 23 |
+ ifName string |
|
| 24 |
+ mac net.HardwareAddr |
|
| 25 |
+ addr *net.IPNet |
|
| 26 |
+ dbExists bool |
|
| 27 |
+ dbIndex uint64 |
|
| 20 | 28 |
} |
| 21 | 29 |
|
| 22 | 30 |
func (n *network) endpoint(eid string) *endpoint {
|
| ... | ... |
@@ -60,6 +68,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 60 | 60 |
|
| 61 | 61 |
ep := &endpoint{
|
| 62 | 62 |
id: eid, |
| 63 |
+ nid: n.id, |
|
| 63 | 64 |
addr: ifInfo.Address(), |
| 64 | 65 |
mac: ifInfo.MacAddress(), |
| 65 | 66 |
} |
| ... | ... |
@@ -80,6 +89,10 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 80 | 80 |
|
| 81 | 81 |
n.addEndpoint(ep) |
| 82 | 82 |
|
| 83 |
+ if err := d.writeEndpointToStore(ep); err != nil {
|
|
| 84 |
+ return fmt.Errorf("failed to update overlay endpoint %s to local store: %v", ep.id[0:7], err)
|
|
| 85 |
+ } |
|
| 86 |
+ |
|
| 83 | 87 |
return nil |
| 84 | 88 |
} |
| 85 | 89 |
|
| ... | ... |
@@ -102,6 +115,10 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
|
| 102 | 102 |
|
| 103 | 103 |
n.deleteEndpoint(eid) |
| 104 | 104 |
|
| 105 |
+ if err := d.deleteEndpointFromStore(ep); err != nil {
|
|
| 106 |
+ log.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err)
|
|
| 107 |
+ } |
|
| 108 |
+ |
|
| 105 | 109 |
if ep.ifName == "" {
|
| 106 | 110 |
return nil |
| 107 | 111 |
} |
| ... | ... |
@@ -121,3 +138,122 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
|
| 121 | 121 |
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
| 122 | 122 |
return make(map[string]interface{}, 0), nil
|
| 123 | 123 |
} |
| 124 |
+ |
|
| 125 |
+func (d *driver) deleteEndpointFromStore(e *endpoint) error {
|
|
| 126 |
+ if d.localStore == nil {
|
|
| 127 |
+ return fmt.Errorf("overlay local store not initialized, ep not deleted")
|
|
| 128 |
+ } |
|
| 129 |
+ |
|
| 130 |
+ if err := d.localStore.DeleteObjectAtomic(e); err != nil {
|
|
| 131 |
+ return err |
|
| 132 |
+ } |
|
| 133 |
+ |
|
| 134 |
+ return nil |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+func (d *driver) writeEndpointToStore(e *endpoint) error {
|
|
| 138 |
+ if d.localStore == nil {
|
|
| 139 |
+ return fmt.Errorf("overlay local store not initialized, ep not added")
|
|
| 140 |
+ } |
|
| 141 |
+ |
|
| 142 |
+ if err := d.localStore.PutObjectAtomic(e); err != nil {
|
|
| 143 |
+ return err |
|
| 144 |
+ } |
|
| 145 |
+ return nil |
|
| 146 |
+} |
|
| 147 |
+ |
|
| 148 |
+func (ep *endpoint) DataScope() string {
|
|
| 149 |
+ return datastore.LocalScope |
|
| 150 |
+} |
|
| 151 |
+ |
|
| 152 |
+func (ep *endpoint) New() datastore.KVObject {
|
|
| 153 |
+ return &endpoint{}
|
|
| 154 |
+} |
|
| 155 |
+ |
|
| 156 |
+func (ep *endpoint) CopyTo(o datastore.KVObject) error {
|
|
| 157 |
+ dstep := o.(*endpoint) |
|
| 158 |
+ *dstep = *ep |
|
| 159 |
+ return nil |
|
| 160 |
+} |
|
| 161 |
+ |
|
| 162 |
+func (ep *endpoint) Key() []string {
|
|
| 163 |
+ return []string{overlayEndpointPrefix, ep.id}
|
|
| 164 |
+} |
|
| 165 |
+ |
|
| 166 |
+func (ep *endpoint) KeyPrefix() []string {
|
|
| 167 |
+ return []string{overlayEndpointPrefix}
|
|
| 168 |
+} |
|
| 169 |
+ |
|
| 170 |
+func (ep *endpoint) Index() uint64 {
|
|
| 171 |
+ return ep.dbIndex |
|
| 172 |
+} |
|
| 173 |
+ |
|
| 174 |
+func (ep *endpoint) SetIndex(index uint64) {
|
|
| 175 |
+ ep.dbIndex = index |
|
| 176 |
+ ep.dbExists = true |
|
| 177 |
+} |
|
| 178 |
+ |
|
| 179 |
+func (ep *endpoint) Exists() bool {
|
|
| 180 |
+ return ep.dbExists |
|
| 181 |
+} |
|
| 182 |
+ |
|
| 183 |
+func (ep *endpoint) Skip() bool {
|
|
| 184 |
+ return false |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 187 |
+func (ep *endpoint) Value() []byte {
|
|
| 188 |
+ b, err := json.Marshal(ep) |
|
| 189 |
+ if err != nil {
|
|
| 190 |
+ return nil |
|
| 191 |
+ } |
|
| 192 |
+ return b |
|
| 193 |
+} |
|
| 194 |
+ |
|
| 195 |
+func (ep *endpoint) SetValue(value []byte) error {
|
|
| 196 |
+ return json.Unmarshal(value, ep) |
|
| 197 |
+} |
|
| 198 |
+ |
|
| 199 |
+func (ep *endpoint) MarshalJSON() ([]byte, error) {
|
|
| 200 |
+ epMap := make(map[string]interface{})
|
|
| 201 |
+ |
|
| 202 |
+ epMap["id"] = ep.id |
|
| 203 |
+ epMap["nid"] = ep.nid |
|
| 204 |
+ if ep.ifName != "" {
|
|
| 205 |
+ epMap["ifName"] = ep.ifName |
|
| 206 |
+ } |
|
| 207 |
+ if ep.addr != nil {
|
|
| 208 |
+ epMap["addr"] = ep.addr.String() |
|
| 209 |
+ } |
|
| 210 |
+ if len(ep.mac) != 0 {
|
|
| 211 |
+ epMap["mac"] = ep.mac.String() |
|
| 212 |
+ } |
|
| 213 |
+ |
|
| 214 |
+ return json.Marshal(epMap) |
|
| 215 |
+} |
|
| 216 |
+ |
|
| 217 |
+func (ep *endpoint) UnmarshalJSON(value []byte) error {
|
|
| 218 |
+ var ( |
|
| 219 |
+ err error |
|
| 220 |
+ epMap map[string]interface{}
|
|
| 221 |
+ ) |
|
| 222 |
+ |
|
| 223 |
+ json.Unmarshal(value, &epMap) |
|
| 224 |
+ |
|
| 225 |
+ ep.id = epMap["id"].(string) |
|
| 226 |
+ ep.nid = epMap["nid"].(string) |
|
| 227 |
+ if v, ok := epMap["mac"]; ok {
|
|
| 228 |
+ if ep.mac, err = net.ParseMAC(v.(string)); err != nil {
|
|
| 229 |
+ return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string))
|
|
| 230 |
+ } |
|
| 231 |
+ } |
|
| 232 |
+ if v, ok := epMap["addr"]; ok {
|
|
| 233 |
+ if ep.addr, err = types.ParseCIDR(v.(string)); err != nil {
|
|
| 234 |
+ return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err)
|
|
| 235 |
+ } |
|
| 236 |
+ } |
|
| 237 |
+ if v, ok := epMap["ifName"]; ok {
|
|
| 238 |
+ ep.ifName = v.(string) |
|
| 239 |
+ } |
|
| 240 |
+ |
|
| 241 |
+ return nil |
|
| 242 |
+} |
| ... | ... |
@@ -195,21 +195,21 @@ func (n *network) incEndpointCount() {
|
| 195 | 195 |
n.joinCnt++ |
| 196 | 196 |
} |
| 197 | 197 |
|
| 198 |
-func (n *network) joinSandbox() error {
|
|
| 198 |
+func (n *network) joinSandbox(restore bool) error {
|
|
| 199 | 199 |
// If there is a race between two go routines here only one will win |
| 200 | 200 |
// the other will wait. |
| 201 | 201 |
n.once.Do(func() {
|
| 202 | 202 |
// save the error status of initSandbox in n.initErr so that |
| 203 | 203 |
// all the racing go routines are able to know the status. |
| 204 |
- n.initErr = n.initSandbox() |
|
| 204 |
+ n.initErr = n.initSandbox(restore) |
|
| 205 | 205 |
}) |
| 206 | 206 |
|
| 207 | 207 |
return n.initErr |
| 208 | 208 |
} |
| 209 | 209 |
|
| 210 |
-func (n *network) joinSubnetSandbox(s *subnet) error {
|
|
| 210 |
+func (n *network) joinSubnetSandbox(s *subnet, restore bool) error {
|
|
| 211 | 211 |
s.once.Do(func() {
|
| 212 |
- s.initErr = n.initSubnetSandbox(s) |
|
| 212 |
+ s.initErr = n.initSubnetSandbox(s, restore) |
|
| 213 | 213 |
}) |
| 214 | 214 |
return s.initErr |
| 215 | 215 |
} |
| ... | ... |
@@ -386,9 +386,33 @@ func isOverlap(nw *net.IPNet) bool {
|
| 386 | 386 |
return false |
| 387 | 387 |
} |
| 388 | 388 |
|
| 389 |
-func (n *network) initSubnetSandbox(s *subnet) error {
|
|
| 390 |
- brName := n.generateBridgeName(s) |
|
| 391 |
- vxlanName := n.generateVxlanName(s) |
|
| 389 |
+func (n *network) restoreSubnetSandbox(s *subnet, brName, vxlanName string) error {
|
|
| 390 |
+ sbox := n.sandbox() |
|
| 391 |
+ |
|
| 392 |
+ // restore overlay osl sandbox |
|
| 393 |
+ Ifaces := make(map[string][]osl.IfaceOption) |
|
| 394 |
+ brIfaceOption := make([]osl.IfaceOption, 2) |
|
| 395 |
+ brIfaceOption = append(brIfaceOption, sbox.InterfaceOptions().Address(s.gwIP)) |
|
| 396 |
+ brIfaceOption = append(brIfaceOption, sbox.InterfaceOptions().Bridge(true)) |
|
| 397 |
+ Ifaces[fmt.Sprintf("%s+%s", brName, "br")] = brIfaceOption
|
|
| 398 |
+ |
|
| 399 |
+ err := sbox.Restore(Ifaces, nil, nil, nil) |
|
| 400 |
+ if err != nil {
|
|
| 401 |
+ return err |
|
| 402 |
+ } |
|
| 403 |
+ |
|
| 404 |
+ Ifaces = make(map[string][]osl.IfaceOption) |
|
| 405 |
+ vxlanIfaceOption := make([]osl.IfaceOption, 1) |
|
| 406 |
+ vxlanIfaceOption = append(vxlanIfaceOption, sbox.InterfaceOptions().Master(brName)) |
|
| 407 |
+ Ifaces[fmt.Sprintf("%s+%s", vxlanName, "vxlan")] = vxlanIfaceOption
|
|
| 408 |
+ err = sbox.Restore(Ifaces, nil, nil, nil) |
|
| 409 |
+ if err != nil {
|
|
| 410 |
+ return err |
|
| 411 |
+ } |
|
| 412 |
+ return nil |
|
| 413 |
+} |
|
| 414 |
+ |
|
| 415 |
+func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error {
|
|
| 392 | 416 |
|
| 393 | 417 |
if hostMode {
|
| 394 | 418 |
// Try to delete stale bridge interface if it exists |
| ... | ... |
@@ -451,6 +475,19 @@ func (n *network) initSubnetSandbox(s *subnet) error {
|
| 451 | 451 |
} |
| 452 | 452 |
} |
| 453 | 453 |
|
| 454 |
+ return nil |
|
| 455 |
+} |
|
| 456 |
+ |
|
| 457 |
+func (n *network) initSubnetSandbox(s *subnet, restore bool) error {
|
|
| 458 |
+ brName := n.generateBridgeName(s) |
|
| 459 |
+ vxlanName := n.generateVxlanName(s) |
|
| 460 |
+ |
|
| 461 |
+ if restore {
|
|
| 462 |
+ n.restoreSubnetSandbox(s, brName, vxlanName) |
|
| 463 |
+ } else {
|
|
| 464 |
+ n.setupSubnetSandbox(s, brName, vxlanName) |
|
| 465 |
+ } |
|
| 466 |
+ |
|
| 454 | 467 |
n.Lock() |
| 455 | 468 |
s.vxlanName = vxlanName |
| 456 | 469 |
s.brName = brName |
| ... | ... |
@@ -494,32 +531,45 @@ func (n *network) cleanupStaleSandboxes() {
|
| 494 | 494 |
}) |
| 495 | 495 |
} |
| 496 | 496 |
|
| 497 |
-func (n *network) initSandbox() error {
|
|
| 497 |
+func (n *network) initSandbox(restore bool) error {
|
|
| 498 | 498 |
n.Lock() |
| 499 | 499 |
n.initEpoch++ |
| 500 | 500 |
n.Unlock() |
| 501 | 501 |
|
| 502 | 502 |
networkOnce.Do(networkOnceInit) |
| 503 | 503 |
|
| 504 |
- if hostMode {
|
|
| 505 |
- if err := addNetworkChain(n.id[:12]); err != nil {
|
|
| 506 |
- return err |
|
| 504 |
+ if !restore {
|
|
| 505 |
+ if hostMode {
|
|
| 506 |
+ if err := addNetworkChain(n.id[:12]); err != nil {
|
|
| 507 |
+ return err |
|
| 508 |
+ } |
|
| 507 | 509 |
} |
| 510 |
+ |
|
| 511 |
+ // If there are any stale sandboxes related to this network |
|
| 512 |
+ // from previous daemon life clean it up here |
|
| 513 |
+ n.cleanupStaleSandboxes() |
|
| 508 | 514 |
} |
| 509 | 515 |
|
| 510 |
- // If there are any stale sandboxes related to this network |
|
| 511 |
- // from previous daemon life clean it up here |
|
| 512 |
- n.cleanupStaleSandboxes() |
|
| 516 |
+ // In the restore case network sandbox already exist; but we don't know |
|
| 517 |
+ // what epoch number it was created with. It has to be retrieved by |
|
| 518 |
+ // searching the net namespaces. |
|
| 519 |
+ key := "" |
|
| 520 |
+ if restore {
|
|
| 521 |
+ key = osl.GenerateKey("-" + n.id)
|
|
| 522 |
+ } else {
|
|
| 523 |
+ key = osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch) + n.id)
|
|
| 524 |
+ } |
|
| 513 | 525 |
|
| 514 |
- sbox, err := osl.NewSandbox( |
|
| 515 |
- osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), !hostMode)
|
|
| 526 |
+ sbox, err := osl.NewSandbox(key, !hostMode, restore) |
|
| 516 | 527 |
if err != nil {
|
| 517 |
- return fmt.Errorf("could not create network sandbox: %v", err)
|
|
| 528 |
+ return fmt.Errorf("could not get network sandbox (oper %t): %v", restore, err)
|
|
| 518 | 529 |
} |
| 519 | 530 |
|
| 520 | 531 |
n.setSandbox(sbox) |
| 521 | 532 |
|
| 522 |
- n.driver.peerDbUpdateSandbox(n.id) |
|
| 533 |
+ if !restore {
|
|
| 534 |
+ n.driver.peerDbUpdateSandbox(n.id) |
|
| 535 |
+ } |
|
| 523 | 536 |
|
| 524 | 537 |
var nlSock *nl.NetlinkSocket |
| 525 | 538 |
sbox.InvokeFunc(func() {
|
| ... | ... |
@@ -13,6 +13,7 @@ import ( |
| 13 | 13 |
"github.com/docker/libnetwork/driverapi" |
| 14 | 14 |
"github.com/docker/libnetwork/idm" |
| 15 | 15 |
"github.com/docker/libnetwork/netlabel" |
| 16 |
+ "github.com/docker/libnetwork/osl" |
|
| 16 | 17 |
"github.com/docker/libnetwork/types" |
| 17 | 18 |
"github.com/hashicorp/serf/serf" |
| 18 | 19 |
) |
| ... | ... |
@@ -41,6 +42,7 @@ type driver struct {
|
| 41 | 41 |
serfInstance *serf.Serf |
| 42 | 42 |
networks networkTable |
| 43 | 43 |
store datastore.DataStore |
| 44 |
+ localStore datastore.DataStore |
|
| 44 | 45 |
vxlanIdm *idm.Idm |
| 45 | 46 |
once sync.Once |
| 46 | 47 |
joinOnce sync.Once |
| ... | ... |
@@ -74,9 +76,75 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
| 74 | 74 |
} |
| 75 | 75 |
} |
| 76 | 76 |
|
| 77 |
+ if data, ok := config[netlabel.LocalKVClient]; ok {
|
|
| 78 |
+ var err error |
|
| 79 |
+ dsc, ok := data.(discoverapi.DatastoreConfigData) |
|
| 80 |
+ if !ok {
|
|
| 81 |
+ return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
|
|
| 82 |
+ } |
|
| 83 |
+ d.localStore, err = datastore.NewDataStoreFromConfig(dsc) |
|
| 84 |
+ if err != nil {
|
|
| 85 |
+ return types.InternalErrorf("failed to initialize local data store: %v", err)
|
|
| 86 |
+ } |
|
| 87 |
+ } |
|
| 88 |
+ |
|
| 89 |
+ d.restoreEndpoints() |
|
| 90 |
+ |
|
| 77 | 91 |
return dc.RegisterDriver(networkType, d, c) |
| 78 | 92 |
} |
| 79 | 93 |
|
| 94 |
+// Endpoints are stored in the local store. Restore them and reconstruct the overlay sandbox |
|
| 95 |
+func (d *driver) restoreEndpoints() error {
|
|
| 96 |
+ if d.localStore == nil {
|
|
| 97 |
+ logrus.Warnf("Cannot restore overlay endpoints because local datastore is missing")
|
|
| 98 |
+ return nil |
|
| 99 |
+ } |
|
| 100 |
+ kvol, err := d.localStore.List(datastore.Key(overlayEndpointPrefix), &endpoint{})
|
|
| 101 |
+ if err != nil && err != datastore.ErrKeyNotFound {
|
|
| 102 |
+ return fmt.Errorf("failed to read overlay endpoint from store: %v", err)
|
|
| 103 |
+ } |
|
| 104 |
+ |
|
| 105 |
+ if err == datastore.ErrKeyNotFound {
|
|
| 106 |
+ return nil |
|
| 107 |
+ } |
|
| 108 |
+ for _, kvo := range kvol {
|
|
| 109 |
+ ep := kvo.(*endpoint) |
|
| 110 |
+ n := d.network(ep.nid) |
|
| 111 |
+ if n == nil {
|
|
| 112 |
+ logrus.Debugf("Network (%s) not found for restored endpoint (%s)", ep.nid, ep.id)
|
|
| 113 |
+ continue |
|
| 114 |
+ } |
|
| 115 |
+ n.addEndpoint(ep) |
|
| 116 |
+ |
|
| 117 |
+ s := n.getSubnetforIP(ep.addr) |
|
| 118 |
+ if s == nil {
|
|
| 119 |
+ return fmt.Errorf("could not find subnet for endpoint %s", ep.id)
|
|
| 120 |
+ } |
|
| 121 |
+ |
|
| 122 |
+ if err := n.joinSandbox(true); err != nil {
|
|
| 123 |
+ return fmt.Errorf("restore network sandbox failed: %v", err)
|
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+ if err := n.joinSubnetSandbox(s, true); err != nil {
|
|
| 127 |
+ return fmt.Errorf("restore subnet sandbox failed for %q: %v", s.subnetIP.String(), err)
|
|
| 128 |
+ } |
|
| 129 |
+ |
|
| 130 |
+ Ifaces := make(map[string][]osl.IfaceOption) |
|
| 131 |
+ vethIfaceOption := make([]osl.IfaceOption, 1) |
|
| 132 |
+ vethIfaceOption = append(vethIfaceOption, n.sbox.InterfaceOptions().Master(s.brName)) |
|
| 133 |
+ Ifaces[fmt.Sprintf("%s+%s", "veth", "veth")] = vethIfaceOption
|
|
| 134 |
+ |
|
| 135 |
+ err := n.sbox.Restore(Ifaces, nil, nil, nil) |
|
| 136 |
+ if err != nil {
|
|
| 137 |
+ return fmt.Errorf("failed to restore overlay sandbox: %v", err)
|
|
| 138 |
+ } |
|
| 139 |
+ |
|
| 140 |
+ n.incEndpointCount() |
|
| 141 |
+ d.peerDbAdd(ep.nid, ep.id, ep.addr.IP, ep.addr.Mask, ep.mac, net.ParseIP(d.bindAddress), true) |
|
| 142 |
+ } |
|
| 143 |
+ return nil |
|
| 144 |
+} |
|
| 145 |
+ |
|
| 80 | 146 |
// Fini cleans up the driver resources |
| 81 | 147 |
func Fini(drv driverapi.Driver) {
|
| 82 | 148 |
d := drv.(*driver) |
| ... | ... |
@@ -271,7 +271,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask, |
| 271 | 271 |
return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
|
| 272 | 272 |
} |
| 273 | 273 |
|
| 274 |
- if err := n.joinSubnetSandbox(s); err != nil {
|
|
| 274 |
+ if err := n.joinSubnetSandbox(s, false); err != nil {
|
|
| 275 | 275 |
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
|
| 276 | 276 |
} |
| 277 | 277 |
|
| ... | ... |
@@ -2,14 +2,10 @@ |
| 2 | 2 |
|
| 3 | 3 |
package libnetwork |
| 4 | 4 |
|
| 5 |
-import ( |
|
| 6 |
- "github.com/docker/libnetwork/drivers/ipvlan" |
|
| 7 |
- "github.com/docker/libnetwork/drivers/macvlan" |
|
| 8 |
-) |
|
| 5 |
+import "github.com/docker/libnetwork/drivers/ipvlan" |
|
| 9 | 6 |
|
| 10 | 7 |
func additionalDrivers() []initializer {
|
| 11 | 8 |
return []initializer{
|
| 12 |
- {macvlan.Init, "macvlan"},
|
|
| 13 | 9 |
{ipvlan.Init, "ipvlan"},
|
| 14 | 10 |
} |
| 15 | 11 |
} |
| ... | ... |
@@ -3,6 +3,7 @@ package libnetwork |
| 3 | 3 |
import ( |
| 4 | 4 |
"github.com/docker/libnetwork/drivers/bridge" |
| 5 | 5 |
"github.com/docker/libnetwork/drivers/host" |
| 6 |
+ "github.com/docker/libnetwork/drivers/macvlan" |
|
| 6 | 7 |
"github.com/docker/libnetwork/drivers/null" |
| 7 | 8 |
"github.com/docker/libnetwork/drivers/overlay" |
| 8 | 9 |
"github.com/docker/libnetwork/drivers/remote" |
| ... | ... |
@@ -12,6 +13,7 @@ func getInitializers() []initializer {
|
| 12 | 12 |
in := []initializer{
|
| 13 | 13 |
{bridge.Init, "bridge"},
|
| 14 | 14 |
{host.Init, "host"},
|
| 15 |
+ {macvlan.Init, "macvlan"},
|
|
| 15 | 16 |
{null.Init, "null"},
|
| 16 | 17 |
{remote.Init, "remote"},
|
| 17 | 18 |
{overlay.Init, "overlay"},
|
| ... | ... |
@@ -84,6 +84,7 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
|
| 84 | 84 |
epMap["name"] = ep.name |
| 85 | 85 |
epMap["id"] = ep.id |
| 86 | 86 |
epMap["ep_iface"] = ep.iface |
| 87 |
+ epMap["joinInfo"] = ep.joinInfo |
|
| 87 | 88 |
epMap["exposed_ports"] = ep.exposedPorts |
| 88 | 89 |
if ep.generic != nil {
|
| 89 | 90 |
epMap["generic"] = ep.generic |
| ... | ... |
@@ -115,6 +116,9 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
|
| 115 | 115 |
ib, _ := json.Marshal(epMap["ep_iface"]) |
| 116 | 116 |
json.Unmarshal(ib, &ep.iface) |
| 117 | 117 |
|
| 118 |
+ jb, _ := json.Marshal(epMap["joinInfo"]) |
|
| 119 |
+ json.Unmarshal(jb, &ep.joinInfo) |
|
| 120 |
+ |
|
| 118 | 121 |
tb, _ := json.Marshal(epMap["exposed_ports"]) |
| 119 | 122 |
var tPorts []types.TransportPort |
| 120 | 123 |
json.Unmarshal(tb, &tPorts) |
| ... | ... |
@@ -235,6 +239,11 @@ func (ep *endpoint) CopyTo(o datastore.KVObject) error {
|
| 235 | 235 |
ep.iface.CopyTo(dstEp.iface) |
| 236 | 236 |
} |
| 237 | 237 |
|
| 238 |
+ if ep.joinInfo != nil {
|
|
| 239 |
+ dstEp.joinInfo = &endpointJoinInfo{}
|
|
| 240 |
+ ep.joinInfo.CopyTo(dstEp.joinInfo) |
|
| 241 |
+ } |
|
| 242 |
+ |
|
| 238 | 243 |
dstEp.exposedPorts = make([]types.TransportPort, len(ep.exposedPorts)) |
| 239 | 244 |
copy(dstEp.exposedPorts, ep.exposedPorts) |
| 240 | 245 |
|
| ... | ... |
@@ -1073,6 +1082,13 @@ func (ep *endpoint) releaseAddress() {
|
| 1073 | 1073 |
} |
| 1074 | 1074 |
|
| 1075 | 1075 |
func (c *controller) cleanupLocalEndpoints() {
|
| 1076 |
+ // Get used endpoints |
|
| 1077 |
+ eps := make(map[string]interface{})
|
|
| 1078 |
+ for _, sb := range c.sandboxes {
|
|
| 1079 |
+ for _, ep := range sb.endpoints {
|
|
| 1080 |
+ eps[ep.id] = true |
|
| 1081 |
+ } |
|
| 1082 |
+ } |
|
| 1076 | 1083 |
nl, err := c.getNetworksForScope(datastore.LocalScope) |
| 1077 | 1084 |
if err != nil {
|
| 1078 | 1085 |
log.Warnf("Could not get list of networks during endpoint cleanup: %v", err)
|
| ... | ... |
@@ -1087,6 +1103,9 @@ func (c *controller) cleanupLocalEndpoints() {
|
| 1087 | 1087 |
} |
| 1088 | 1088 |
|
| 1089 | 1089 |
for _, ep := range epl {
|
| 1090 |
+ if _, ok := eps[ep.id]; ok {
|
|
| 1091 |
+ continue |
|
| 1092 |
+ } |
|
| 1090 | 1093 |
log.Infof("Removing stale endpoint %s (%s)", ep.name, ep.id)
|
| 1091 | 1094 |
if err := ep.Delete(true); err != nil {
|
| 1092 | 1095 |
log.Warnf("Could not delete local endpoint %s during endpoint cleanup: %v", ep.name, err)
|
| ... | ... |
@@ -414,3 +414,56 @@ func (ep *endpoint) DisableGatewayService() {
|
| 414 | 414 |
|
| 415 | 415 |
ep.joinInfo.disableGatewayService = true |
| 416 | 416 |
} |
| 417 |
+ |
|
| 418 |
+func (epj *endpointJoinInfo) MarshalJSON() ([]byte, error) {
|
|
| 419 |
+ epMap := make(map[string]interface{})
|
|
| 420 |
+ if epj.gw != nil {
|
|
| 421 |
+ epMap["gw"] = epj.gw.String() |
|
| 422 |
+ } |
|
| 423 |
+ if epj.gw6 != nil {
|
|
| 424 |
+ epMap["gw6"] = epj.gw6.String() |
|
| 425 |
+ } |
|
| 426 |
+ epMap["disableGatewayService"] = epj.disableGatewayService |
|
| 427 |
+ epMap["StaticRoutes"] = epj.StaticRoutes |
|
| 428 |
+ return json.Marshal(epMap) |
|
| 429 |
+} |
|
| 430 |
+ |
|
| 431 |
+func (epj *endpointJoinInfo) UnmarshalJSON(b []byte) error {
|
|
| 432 |
+ var ( |
|
| 433 |
+ err error |
|
| 434 |
+ epMap map[string]interface{}
|
|
| 435 |
+ ) |
|
| 436 |
+ if err = json.Unmarshal(b, &epMap); err != nil {
|
|
| 437 |
+ return err |
|
| 438 |
+ } |
|
| 439 |
+ if v, ok := epMap["gw"]; ok {
|
|
| 440 |
+ epj.gw6 = net.ParseIP(v.(string)) |
|
| 441 |
+ } |
|
| 442 |
+ if v, ok := epMap["gw6"]; ok {
|
|
| 443 |
+ epj.gw6 = net.ParseIP(v.(string)) |
|
| 444 |
+ } |
|
| 445 |
+ epj.disableGatewayService = epMap["disableGatewayService"].(bool) |
|
| 446 |
+ |
|
| 447 |
+ var tStaticRoute []types.StaticRoute |
|
| 448 |
+ if v, ok := epMap["StaticRoutes"]; ok {
|
|
| 449 |
+ tb, _ := json.Marshal(v) |
|
| 450 |
+ var tStaticRoute []types.StaticRoute |
|
| 451 |
+ json.Unmarshal(tb, &tStaticRoute) |
|
| 452 |
+ } |
|
| 453 |
+ var StaticRoutes []*types.StaticRoute |
|
| 454 |
+ for _, r := range tStaticRoute {
|
|
| 455 |
+ StaticRoutes = append(StaticRoutes, &r) |
|
| 456 |
+ } |
|
| 457 |
+ epj.StaticRoutes = StaticRoutes |
|
| 458 |
+ |
|
| 459 |
+ return nil |
|
| 460 |
+} |
|
| 461 |
+ |
|
| 462 |
+func (epj *endpointJoinInfo) CopyTo(dstEpj *endpointJoinInfo) error {
|
|
| 463 |
+ dstEpj.disableGatewayService = epj.disableGatewayService |
|
| 464 |
+ dstEpj.StaticRoutes = make([]*types.StaticRoute, len(epj.StaticRoutes)) |
|
| 465 |
+ copy(dstEpj.StaticRoutes, epj.StaticRoutes) |
|
| 466 |
+ dstEpj.gw = types.GetIPCopy(epj.gw) |
|
| 467 |
+ dstEpj.gw = types.GetIPCopy(epj.gw6) |
|
| 468 |
+ return nil |
|
| 469 |
+} |
| ... | ... |
@@ -311,7 +311,16 @@ func (nDB *NetworkDB) bulkSyncTables() {
|
| 311 | 311 |
nid := networks[0] |
| 312 | 312 |
networks = networks[1:] |
| 313 | 313 |
|
| 314 |
- completed, err := nDB.bulkSync(nid, false) |
|
| 314 |
+ nDB.RLock() |
|
| 315 |
+ nodes := nDB.networkNodes[nid] |
|
| 316 |
+ nDB.RUnlock() |
|
| 317 |
+ |
|
| 318 |
+ // No peer nodes on this network. Move on. |
|
| 319 |
+ if len(nodes) == 0 {
|
|
| 320 |
+ continue |
|
| 321 |
+ } |
|
| 322 |
+ |
|
| 323 |
+ completed, err := nDB.bulkSync(nid, nodes, false) |
|
| 315 | 324 |
if err != nil {
|
| 316 | 325 |
logrus.Errorf("periodic bulk sync failure for network %s: %v", nid, err)
|
| 317 | 326 |
continue |
| ... | ... |
@@ -334,11 +343,7 @@ func (nDB *NetworkDB) bulkSyncTables() {
|
| 334 | 334 |
} |
| 335 | 335 |
} |
| 336 | 336 |
|
| 337 |
-func (nDB *NetworkDB) bulkSync(nid string, all bool) ([]string, error) {
|
|
| 338 |
- nDB.RLock() |
|
| 339 |
- nodes := nDB.networkNodes[nid] |
|
| 340 |
- nDB.RUnlock() |
|
| 341 |
- |
|
| 337 |
+func (nDB *NetworkDB) bulkSync(nid string, nodes []string, all bool) ([]string, error) {
|
|
| 342 | 338 |
if !all {
|
| 343 | 339 |
// If not all, then just pick one. |
| 344 | 340 |
nodes = nDB.mRandomNodes(1, nodes) |
| ... | ... |
@@ -2,6 +2,7 @@ package networkdb |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
+ "net" |
|
| 5 | 6 |
"time" |
| 6 | 7 |
|
| 7 | 8 |
"github.com/Sirupsen/logrus" |
| ... | ... |
@@ -210,8 +211,13 @@ func (nDB *NetworkDB) handleBulkSync(buf []byte) {
|
| 210 | 210 |
return |
| 211 | 211 |
} |
| 212 | 212 |
|
| 213 |
+ var nodeAddr net.IP |
|
| 214 |
+ if node, ok := nDB.nodes[bsm.NodeName]; ok {
|
|
| 215 |
+ nodeAddr = node.Addr |
|
| 216 |
+ } |
|
| 217 |
+ |
|
| 213 | 218 |
if err := nDB.bulkSyncNode(bsm.Networks, bsm.NodeName, false); err != nil {
|
| 214 |
- logrus.Errorf("Error in responding to bulk sync from node %s: %v", nDB.nodes[bsm.NodeName].Addr, err)
|
|
| 219 |
+ logrus.Errorf("Error in responding to bulk sync from node %s: %v", nodeAddr, err)
|
|
| 215 | 220 |
} |
| 216 | 221 |
} |
| 217 | 222 |
|
| ... | ... |
@@ -14,6 +14,7 @@ func (e *eventDelegate) NotifyJoin(n *memberlist.Node) {
|
| 14 | 14 |
|
| 15 | 15 |
func (e *eventDelegate) NotifyLeave(n *memberlist.Node) {
|
| 16 | 16 |
e.nDB.deleteNodeTableEntries(n.Name) |
| 17 |
+ e.nDB.deleteNetworkNodeEntries(n.Name) |
|
| 17 | 18 |
e.nDB.Lock() |
| 18 | 19 |
delete(e.nDB.nodes, n.Name) |
| 19 | 20 |
e.nDB.Unlock() |
| ... | ... |
@@ -286,6 +286,23 @@ func (nDB *NetworkDB) DeleteEntry(tname, nid, key string) error {
|
| 286 | 286 |
return nil |
| 287 | 287 |
} |
| 288 | 288 |
|
| 289 |
+func (nDB *NetworkDB) deleteNetworkNodeEntries(deletedNode string) {
|
|
| 290 |
+ nDB.Lock() |
|
| 291 |
+ for nid, nodes := range nDB.networkNodes {
|
|
| 292 |
+ updatedNodes := make([]string, 0, len(nodes)) |
|
| 293 |
+ for _, node := range nodes {
|
|
| 294 |
+ if node == deletedNode {
|
|
| 295 |
+ continue |
|
| 296 |
+ } |
|
| 297 |
+ |
|
| 298 |
+ updatedNodes = append(updatedNodes, node) |
|
| 299 |
+ } |
|
| 300 |
+ |
|
| 301 |
+ nDB.networkNodes[nid] = updatedNodes |
|
| 302 |
+ } |
|
| 303 |
+ nDB.Unlock() |
|
| 304 |
+} |
|
| 305 |
+ |
|
| 289 | 306 |
func (nDB *NetworkDB) deleteNodeTableEntries(node string) {
|
| 290 | 307 |
nDB.Lock() |
| 291 | 308 |
nDB.indexes[byTable].Walk(func(path string, v interface{}) bool {
|
| ... | ... |
@@ -359,6 +376,7 @@ func (nDB *NetworkDB) JoinNetwork(nid string) error {
|
| 359 | 359 |
RetransmitMult: 4, |
| 360 | 360 |
} |
| 361 | 361 |
nDB.networkNodes[nid] = append(nDB.networkNodes[nid], nDB.config.NodeName) |
| 362 |
+ networkNodes := nDB.networkNodes[nid] |
|
| 362 | 363 |
nDB.Unlock() |
| 363 | 364 |
|
| 364 | 365 |
if err := nDB.sendNetworkEvent(nid, NetworkEventTypeJoin, ltime); err != nil {
|
| ... | ... |
@@ -366,7 +384,7 @@ func (nDB *NetworkDB) JoinNetwork(nid string) error {
|
| 366 | 366 |
} |
| 367 | 367 |
|
| 368 | 368 |
logrus.Debugf("%s: joined network %s", nDB.config.NodeName, nid)
|
| 369 |
- if _, err := nDB.bulkSync(nid, true); err != nil {
|
|
| 369 |
+ if _, err := nDB.bulkSync(nid, networkNodes, true); err != nil {
|
|
| 370 | 370 |
logrus.Errorf("Error bulk syncing while joining network %s: %v", nid, err)
|
| 371 | 371 |
} |
| 372 | 372 |
|
| ... | ... |
@@ -2,10 +2,13 @@ package osl |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
+ "io/ioutil" |
|
| 5 | 6 |
"net" |
| 6 | 7 |
"os" |
| 7 | 8 |
"os/exec" |
| 8 | 9 |
"runtime" |
| 10 |
+ "strconv" |
|
| 11 |
+ "strings" |
|
| 9 | 12 |
"sync" |
| 10 | 13 |
"syscall" |
| 11 | 14 |
"time" |
| ... | ... |
@@ -133,6 +136,39 @@ func GC() {
|
| 133 | 133 |
// container id. |
| 134 | 134 |
func GenerateKey(containerID string) string {
|
| 135 | 135 |
maxLen := 12 |
| 136 |
+ // Read sandbox key from host for overlay |
|
| 137 |
+ if strings.HasPrefix(containerID, "-") {
|
|
| 138 |
+ var ( |
|
| 139 |
+ index int |
|
| 140 |
+ indexStr string |
|
| 141 |
+ tmpkey string |
|
| 142 |
+ ) |
|
| 143 |
+ dir, err := ioutil.ReadDir(prefix) |
|
| 144 |
+ if err != nil {
|
|
| 145 |
+ return "" |
|
| 146 |
+ } |
|
| 147 |
+ |
|
| 148 |
+ for _, v := range dir {
|
|
| 149 |
+ id := v.Name() |
|
| 150 |
+ if strings.HasSuffix(id, containerID[:maxLen-1]) {
|
|
| 151 |
+ indexStr = strings.TrimSuffix(id, containerID[:maxLen-1]) |
|
| 152 |
+ tmpindex, err := strconv.Atoi(indexStr) |
|
| 153 |
+ if err != nil {
|
|
| 154 |
+ return "" |
|
| 155 |
+ } |
|
| 156 |
+ if tmpindex > index {
|
|
| 157 |
+ index = tmpindex |
|
| 158 |
+ tmpkey = id |
|
| 159 |
+ } |
|
| 160 |
+ |
|
| 161 |
+ } |
|
| 162 |
+ } |
|
| 163 |
+ containerID = tmpkey |
|
| 164 |
+ if containerID == "" {
|
|
| 165 |
+ return "" |
|
| 166 |
+ } |
|
| 167 |
+ } |
|
| 168 |
+ |
|
| 136 | 169 |
if len(containerID) < maxLen {
|
| 137 | 170 |
maxLen = len(containerID) |
| 138 | 171 |
} |
| ... | ... |
@@ -142,10 +178,14 @@ func GenerateKey(containerID string) string {
|
| 142 | 142 |
|
| 143 | 143 |
// NewSandbox provides a new sandbox instance created in an os specific way |
| 144 | 144 |
// provided a key which uniquely identifies the sandbox |
| 145 |
-func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
|
| 146 |
- err := createNetworkNamespace(key, osCreate) |
|
| 147 |
- if err != nil {
|
|
| 148 |
- return nil, err |
|
| 145 |
+func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
|
| 146 |
+ if !isRestore {
|
|
| 147 |
+ err := createNetworkNamespace(key, osCreate) |
|
| 148 |
+ if err != nil {
|
|
| 149 |
+ return nil, err |
|
| 150 |
+ } |
|
| 151 |
+ } else {
|
|
| 152 |
+ once.Do(createBasePath) |
|
| 149 | 153 |
} |
| 150 | 154 |
|
| 151 | 155 |
n := &networkNamespace{path: key, isDefault: !osCreate}
|
| ... | ... |
@@ -347,3 +387,105 @@ func (n *networkNamespace) Destroy() error {
|
| 347 | 347 |
addToGarbagePaths(n.path) |
| 348 | 348 |
return nil |
| 349 | 349 |
} |
| 350 |
+ |
|
| 351 |
+// Restore restore the network namespace |
|
| 352 |
+func (n *networkNamespace) Restore(ifsopt map[string][]IfaceOption, routes []*types.StaticRoute, gw net.IP, gw6 net.IP) error {
|
|
| 353 |
+ // restore interfaces |
|
| 354 |
+ for name, opts := range ifsopt {
|
|
| 355 |
+ if !strings.Contains(name, "+") {
|
|
| 356 |
+ return fmt.Errorf("wrong iface name in restore osl sandbox interface: %s", name)
|
|
| 357 |
+ } |
|
| 358 |
+ seps := strings.Split(name, "+") |
|
| 359 |
+ srcName := seps[0] |
|
| 360 |
+ dstPrefix := seps[1] |
|
| 361 |
+ i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
|
|
| 362 |
+ i.processInterfaceOptions(opts...) |
|
| 363 |
+ if i.master != "" {
|
|
| 364 |
+ i.dstMaster = n.findDst(i.master, true) |
|
| 365 |
+ if i.dstMaster == "" {
|
|
| 366 |
+ return fmt.Errorf("could not find an appropriate master %q for %q",
|
|
| 367 |
+ i.master, i.srcName) |
|
| 368 |
+ } |
|
| 369 |
+ } |
|
| 370 |
+ if n.isDefault {
|
|
| 371 |
+ i.dstName = i.srcName |
|
| 372 |
+ } else {
|
|
| 373 |
+ links, err := n.nlHandle.LinkList() |
|
| 374 |
+ if err != nil {
|
|
| 375 |
+ return fmt.Errorf("failed to retrieve list of links in network namespace %q during restore", n.path)
|
|
| 376 |
+ } |
|
| 377 |
+ // due to the docker network connect/disconnect, so the dstName should |
|
| 378 |
+ // restore from the namespace |
|
| 379 |
+ for _, link := range links {
|
|
| 380 |
+ addrs, err := n.nlHandle.AddrList(link, netlink.FAMILY_V4) |
|
| 381 |
+ if err != nil {
|
|
| 382 |
+ return err |
|
| 383 |
+ } |
|
| 384 |
+ ifaceName := link.Attrs().Name |
|
| 385 |
+ if strings.HasPrefix(ifaceName, "vxlan") {
|
|
| 386 |
+ if i.dstName == "vxlan" {
|
|
| 387 |
+ i.dstName = ifaceName |
|
| 388 |
+ break |
|
| 389 |
+ } |
|
| 390 |
+ } |
|
| 391 |
+ // find the interface name by ip |
|
| 392 |
+ if i.address != nil {
|
|
| 393 |
+ for _, addr := range addrs {
|
|
| 394 |
+ if addr.IPNet.String() == i.address.String() {
|
|
| 395 |
+ i.dstName = ifaceName |
|
| 396 |
+ break |
|
| 397 |
+ } |
|
| 398 |
+ continue |
|
| 399 |
+ } |
|
| 400 |
+ if i.dstName == ifaceName {
|
|
| 401 |
+ break |
|
| 402 |
+ } |
|
| 403 |
+ } |
|
| 404 |
+ // This is to find the interface name of the pair in overlay sandbox |
|
| 405 |
+ if strings.HasPrefix(ifaceName, "veth") {
|
|
| 406 |
+ if i.master != "" && i.dstName == "veth" {
|
|
| 407 |
+ i.dstName = ifaceName |
|
| 408 |
+ } |
|
| 409 |
+ } |
|
| 410 |
+ } |
|
| 411 |
+ |
|
| 412 |
+ var index int |
|
| 413 |
+ indexStr := strings.TrimPrefix(i.dstName, dstPrefix) |
|
| 414 |
+ if indexStr != "" {
|
|
| 415 |
+ index, err = strconv.Atoi(indexStr) |
|
| 416 |
+ if err != nil {
|
|
| 417 |
+ return err |
|
| 418 |
+ } |
|
| 419 |
+ } |
|
| 420 |
+ index++ |
|
| 421 |
+ n.Lock() |
|
| 422 |
+ if index > n.nextIfIndex {
|
|
| 423 |
+ n.nextIfIndex = index |
|
| 424 |
+ } |
|
| 425 |
+ n.iFaces = append(n.iFaces, i) |
|
| 426 |
+ n.Unlock() |
|
| 427 |
+ } |
|
| 428 |
+ } |
|
| 429 |
+ |
|
| 430 |
+ // restore routes |
|
| 431 |
+ for _, r := range routes {
|
|
| 432 |
+ n.Lock() |
|
| 433 |
+ n.staticRoutes = append(n.staticRoutes, r) |
|
| 434 |
+ n.Unlock() |
|
| 435 |
+ } |
|
| 436 |
+ |
|
| 437 |
+ // restore gateway |
|
| 438 |
+ if len(gw) > 0 {
|
|
| 439 |
+ n.Lock() |
|
| 440 |
+ n.gw = gw |
|
| 441 |
+ n.Unlock() |
|
| 442 |
+ } |
|
| 443 |
+ |
|
| 444 |
+ if len(gw6) > 0 {
|
|
| 445 |
+ n.Lock() |
|
| 446 |
+ n.gwv6 = gw6 |
|
| 447 |
+ n.Unlock() |
|
| 448 |
+ } |
|
| 449 |
+ |
|
| 450 |
+ return nil |
|
| 451 |
+} |
| ... | ... |
@@ -15,7 +15,7 @@ func GenerateKey(containerID string) string {
|
| 15 | 15 |
|
| 16 | 16 |
// NewSandbox provides a new sandbox instance created in an os specific way |
| 17 | 17 |
// provided a key which uniquely identifies the sandbox |
| 18 |
-func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
|
| 18 |
+func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
|
| 19 | 19 |
return nil, nil |
| 20 | 20 |
} |
| 21 | 21 |
|
| ... | ... |
@@ -58,6 +58,9 @@ type Sandbox interface {
|
| 58 | 58 |
|
| 59 | 59 |
// Destroy the sandbox |
| 60 | 60 |
Destroy() error |
| 61 |
+ |
|
| 62 |
+ // restore sandbox |
|
| 63 |
+ Restore(ifsopt map[string][]IfaceOption, routes []*types.StaticRoute, gw net.IP, gw6 net.IP) error |
|
| 61 | 64 |
} |
| 62 | 65 |
|
| 63 | 66 |
// NeighborOptionSetter interface defines the option setter methods for interface options |
| ... | ... |
@@ -15,7 +15,7 @@ func GenerateKey(containerID string) string {
|
| 15 | 15 |
|
| 16 | 16 |
// NewSandbox provides a new sandbox instance created in an os specific way |
| 17 | 17 |
// provided a key which uniquely identifies the sandbox |
| 18 |
-func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
|
| 18 |
+func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
|
| 19 | 19 |
return nil, nil |
| 20 | 20 |
} |
| 21 | 21 |
|
| ... | ... |
@@ -11,7 +11,7 @@ var ( |
| 11 | 11 |
|
| 12 | 12 |
// NewSandbox provides a new sandbox instance created in an os specific way |
| 13 | 13 |
// provided a key which uniquely identifies the sandbox |
| 14 |
-func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
|
| 14 |
+func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
|
| 15 | 15 |
return nil, ErrNotImplemented |
| 16 | 16 |
} |
| 17 | 17 |
|
| ... | ... |
@@ -19,6 +19,13 @@ func init() {
|
| 19 | 19 |
reexec.Register("setup-resolver", reexecSetupResolver)
|
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 |
+const ( |
|
| 23 |
+ // outputChain used for docker embed dns |
|
| 24 |
+ outputChain = "DOCKER_OUTPUT" |
|
| 25 |
+ //postroutingchain used for docker embed dns |
|
| 26 |
+ postroutingchain = "DOCKER_POSTROUTING" |
|
| 27 |
+) |
|
| 28 |
+ |
|
| 22 | 29 |
func reexecSetupResolver() {
|
| 23 | 30 |
runtime.LockOSThread() |
| 24 | 31 |
defer runtime.UnlockOSThread() |
| ... | ... |
@@ -31,10 +38,10 @@ func reexecSetupResolver() {
|
| 31 | 31 |
_, ipPort, _ := net.SplitHostPort(os.Args[2]) |
| 32 | 32 |
_, tcpPort, _ := net.SplitHostPort(os.Args[3]) |
| 33 | 33 |
rules := [][]string{
|
| 34 |
- {"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[2]},
|
|
| 35 |
- {"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "udp", "--sport", ipPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
|
|
| 36 |
- {"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "tcp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[3]},
|
|
| 37 |
- {"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "tcp", "--sport", tcpPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
|
|
| 34 |
+ {"-t", "nat", "-I", outputChain, "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[2]},
|
|
| 35 |
+ {"-t", "nat", "-I", postroutingchain, "-s", resolverIP, "-p", "udp", "--sport", ipPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
|
|
| 36 |
+ {"-t", "nat", "-I", outputChain, "-d", resolverIP, "-p", "tcp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[3]},
|
|
| 37 |
+ {"-t", "nat", "-I", postroutingchain, "-s", resolverIP, "-p", "tcp", "--sport", tcpPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
|
|
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 | 40 |
f, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0) |
| ... | ... |
@@ -50,6 +57,23 @@ func reexecSetupResolver() {
|
| 50 | 50 |
os.Exit(3) |
| 51 | 51 |
} |
| 52 | 52 |
|
| 53 |
+ // insert outputChain and postroutingchain |
|
| 54 |
+ err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "OUTPUT", "-d", resolverIP, "-j", outputChain)
|
|
| 55 |
+ if err == nil {
|
|
| 56 |
+ iptables.RawCombinedOutputNative("-t", "nat", "-F", outputChain)
|
|
| 57 |
+ } else {
|
|
| 58 |
+ iptables.RawCombinedOutputNative("-t", "nat", "-N", outputChain)
|
|
| 59 |
+ iptables.RawCombinedOutputNative("-t", "nat", "-I", "OUTPUT", "-d", resolverIP, "-j", outputChain)
|
|
| 60 |
+ } |
|
| 61 |
+ |
|
| 62 |
+ err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
|
|
| 63 |
+ if err == nil {
|
|
| 64 |
+ iptables.RawCombinedOutputNative("-t", "nat", "-F", postroutingchain)
|
|
| 65 |
+ } else {
|
|
| 66 |
+ iptables.RawCombinedOutputNative("-t", "nat", "-N", postroutingchain)
|
|
| 67 |
+ iptables.RawCombinedOutputNative("-t", "nat", "-I", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
|
|
| 68 |
+ } |
|
| 69 |
+ |
|
| 53 | 70 |
for _, rule := range rules {
|
| 54 | 71 |
if iptables.RawCombinedOutputNative(rule...) != nil {
|
| 55 | 72 |
log.Errorf("setting up rule failed, %v", rule)
|
| ... | ... |
@@ -700,6 +700,52 @@ func (sb *sandbox) releaseOSSbox() {
|
| 700 | 700 |
osSbox.Destroy() |
| 701 | 701 |
} |
| 702 | 702 |
|
| 703 |
+func (sb *sandbox) restoreOslSandbox() error {
|
|
| 704 |
+ var routes []*types.StaticRoute |
|
| 705 |
+ |
|
| 706 |
+ // restore osl sandbox |
|
| 707 |
+ Ifaces := make(map[string][]osl.IfaceOption) |
|
| 708 |
+ for _, ep := range sb.endpoints {
|
|
| 709 |
+ var ifaceOptions []osl.IfaceOption |
|
| 710 |
+ ep.Lock() |
|
| 711 |
+ joinInfo := ep.joinInfo |
|
| 712 |
+ i := ep.iface |
|
| 713 |
+ ep.Unlock() |
|
| 714 |
+ ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes)) |
|
| 715 |
+ if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
|
|
| 716 |
+ ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6)) |
|
| 717 |
+ } |
|
| 718 |
+ if i.mac != nil {
|
|
| 719 |
+ ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac)) |
|
| 720 |
+ } |
|
| 721 |
+ if len(i.llAddrs) != 0 {
|
|
| 722 |
+ ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().LinkLocalAddresses(i.llAddrs)) |
|
| 723 |
+ } |
|
| 724 |
+ Ifaces[fmt.Sprintf("%s+%s", i.srcName, i.dstPrefix)] = ifaceOptions
|
|
| 725 |
+ if joinInfo != nil {
|
|
| 726 |
+ for _, r := range joinInfo.StaticRoutes {
|
|
| 727 |
+ routes = append(routes, r) |
|
| 728 |
+ } |
|
| 729 |
+ } |
|
| 730 |
+ if ep.needResolver() {
|
|
| 731 |
+ sb.startResolver() |
|
| 732 |
+ } |
|
| 733 |
+ } |
|
| 734 |
+ |
|
| 735 |
+ gwep := sb.getGatewayEndpoint() |
|
| 736 |
+ if gwep == nil {
|
|
| 737 |
+ return nil |
|
| 738 |
+ } |
|
| 739 |
+ |
|
| 740 |
+ // restore osl sandbox |
|
| 741 |
+ err := sb.osSbox.Restore(Ifaces, routes, gwep.joinInfo.gw, gwep.joinInfo.gw6) |
|
| 742 |
+ if err != nil {
|
|
| 743 |
+ return err |
|
| 744 |
+ } |
|
| 745 |
+ |
|
| 746 |
+ return nil |
|
| 747 |
+} |
|
| 748 |
+ |
|
| 703 | 749 |
func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
| 704 | 750 |
sb.Lock() |
| 705 | 751 |
if sb.osSbox == nil {
|
| ... | ... |
@@ -139,6 +139,16 @@ func (sb *sandbox) updateParentHosts() error {
|
| 139 | 139 |
return nil |
| 140 | 140 |
} |
| 141 | 141 |
|
| 142 |
+func (sb *sandbox) restorePath() {
|
|
| 143 |
+ if sb.config.resolvConfPath == "" {
|
|
| 144 |
+ sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf" |
|
| 145 |
+ } |
|
| 146 |
+ sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash" |
|
| 147 |
+ if sb.config.hostsPath == "" {
|
|
| 148 |
+ sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts" |
|
| 149 |
+ } |
|
| 150 |
+} |
|
| 151 |
+ |
|
| 142 | 152 |
func (sb *sandbox) setupDNS() error {
|
| 143 | 153 |
var newRC *resolvconf.File |
| 144 | 154 |
|
| ... | ... |
@@ -20,12 +20,13 @@ type epState struct {
|
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 | 22 |
type sbState struct {
|
| 23 |
- ID string |
|
| 24 |
- Cid string |
|
| 25 |
- c *controller |
|
| 26 |
- dbIndex uint64 |
|
| 27 |
- dbExists bool |
|
| 28 |
- Eps []epState |
|
| 23 |
+ ID string |
|
| 24 |
+ Cid string |
|
| 25 |
+ c *controller |
|
| 26 |
+ dbIndex uint64 |
|
| 27 |
+ dbExists bool |
|
| 28 |
+ Eps []epState |
|
| 29 |
+ EpPriority map[string]int |
|
| 29 | 30 |
} |
| 30 | 31 |
|
| 31 | 32 |
func (sbs *sbState) Key() []string {
|
| ... | ... |
@@ -106,6 +107,7 @@ func (sbs *sbState) CopyTo(o datastore.KVObject) error {
|
| 106 | 106 |
dstSbs.Cid = sbs.Cid |
| 107 | 107 |
dstSbs.dbIndex = sbs.dbIndex |
| 108 | 108 |
dstSbs.dbExists = sbs.dbExists |
| 109 |
+ dstSbs.EpPriority = sbs.EpPriority |
|
| 109 | 110 |
|
| 110 | 111 |
for _, eps := range sbs.Eps {
|
| 111 | 112 |
dstSbs.Eps = append(dstSbs.Eps, eps) |
| ... | ... |
@@ -120,9 +122,10 @@ func (sbs *sbState) DataScope() string {
|
| 120 | 120 |
|
| 121 | 121 |
func (sb *sandbox) storeUpdate() error {
|
| 122 | 122 |
sbs := &sbState{
|
| 123 |
- c: sb.controller, |
|
| 124 |
- ID: sb.id, |
|
| 125 |
- Cid: sb.containerID, |
|
| 123 |
+ c: sb.controller, |
|
| 124 |
+ ID: sb.id, |
|
| 125 |
+ Cid: sb.containerID, |
|
| 126 |
+ EpPriority: sb.epPriority, |
|
| 126 | 127 |
} |
| 127 | 128 |
|
| 128 | 129 |
retry: |
| ... | ... |
@@ -166,7 +169,7 @@ func (sb *sandbox) storeDelete() error {
|
| 166 | 166 |
return sb.controller.deleteFromStore(sbs) |
| 167 | 167 |
} |
| 168 | 168 |
|
| 169 |
-func (c *controller) sandboxCleanup() {
|
|
| 169 |
+func (c *controller) sandboxCleanup(activeSandboxes map[string]interface{}) {
|
|
| 170 | 170 |
store := c.getStore(datastore.LocalScope) |
| 171 | 171 |
if store == nil {
|
| 172 | 172 |
logrus.Errorf("Could not find local scope store while trying to cleanup sandboxes")
|
| ... | ... |
@@ -192,15 +195,27 @@ func (c *controller) sandboxCleanup() {
|
| 192 | 192 |
controller: sbs.c, |
| 193 | 193 |
containerID: sbs.Cid, |
| 194 | 194 |
endpoints: epHeap{},
|
| 195 |
- epPriority: map[string]int{},
|
|
| 196 | 195 |
dbIndex: sbs.dbIndex, |
| 197 | 196 |
isStub: true, |
| 198 | 197 |
dbExists: true, |
| 199 | 198 |
} |
| 200 | 199 |
|
| 201 |
- sb.osSbox, err = osl.NewSandbox(sb.Key(), true) |
|
| 200 |
+ msg := " for cleanup" |
|
| 201 |
+ create := true |
|
| 202 |
+ isRestore := false |
|
| 203 |
+ if val, ok := activeSandboxes[sb.ID()]; ok {
|
|
| 204 |
+ msg = "" |
|
| 205 |
+ sb.isStub = false |
|
| 206 |
+ isRestore = true |
|
| 207 |
+ opts := val.([]SandboxOption) |
|
| 208 |
+ sb.processOptions(opts...) |
|
| 209 |
+ sb.restorePath() |
|
| 210 |
+ create = !sb.config.useDefaultSandBox |
|
| 211 |
+ heap.Init(&sb.endpoints) |
|
| 212 |
+ } |
|
| 213 |
+ sb.osSbox, err = osl.NewSandbox(sb.Key(), create, isRestore) |
|
| 202 | 214 |
if err != nil {
|
| 203 |
- logrus.Errorf("failed to create new osl sandbox while trying to build sandbox for cleanup: %v", err)
|
|
| 215 |
+ logrus.Errorf("failed to create osl sandbox while trying to restore sandbox %s%s: %v", sb.ID()[0:7], msg, err)
|
|
| 204 | 216 |
continue |
| 205 | 217 |
} |
| 206 | 218 |
|
| ... | ... |
@@ -222,13 +237,34 @@ func (c *controller) sandboxCleanup() {
|
| 222 | 222 |
ep = &endpoint{id: eps.Eid, network: n, sandboxID: sbs.ID}
|
| 223 | 223 |
} |
| 224 | 224 |
} |
| 225 |
- |
|
| 226 | 225 |
heap.Push(&sb.endpoints, ep) |
| 227 | 226 |
} |
| 228 | 227 |
|
| 229 |
- logrus.Infof("Removing stale sandbox %s (%s)", sb.id, sb.containerID)
|
|
| 230 |
- if err := sb.delete(true); err != nil {
|
|
| 231 |
- logrus.Errorf("failed to delete sandbox %s while trying to cleanup: %v", sb.id, err)
|
|
| 228 |
+ if _, ok := activeSandboxes[sb.ID()]; !ok {
|
|
| 229 |
+ logrus.Infof("Removing stale sandbox %s (%s)", sb.id, sb.containerID)
|
|
| 230 |
+ if err := sb.delete(true); err != nil {
|
|
| 231 |
+ logrus.Errorf("Failed to delete sandbox %s while trying to cleanup: %v", sb.id, err)
|
|
| 232 |
+ } |
|
| 233 |
+ continue |
|
| 234 |
+ } |
|
| 235 |
+ |
|
| 236 |
+ // reconstruct osl sandbox field |
|
| 237 |
+ if !sb.config.useDefaultSandBox {
|
|
| 238 |
+ if err := sb.restoreOslSandbox(); err != nil {
|
|
| 239 |
+ logrus.Errorf("failed to populate fields for osl sandbox %s", sb.ID())
|
|
| 240 |
+ continue |
|
| 241 |
+ } |
|
| 242 |
+ } else {
|
|
| 243 |
+ c.sboxOnce.Do(func() {
|
|
| 244 |
+ c.defOsSbox = sb.osSbox |
|
| 245 |
+ }) |
|
| 246 |
+ } |
|
| 247 |
+ |
|
| 248 |
+ for _, ep := range sb.endpoints {
|
|
| 249 |
+ // Watch for service records |
|
| 250 |
+ if !c.isAgent() {
|
|
| 251 |
+ c.watchSvcRecord(ep) |
|
| 252 |
+ } |
|
| 232 | 253 |
} |
| 233 | 254 |
} |
| 234 | 255 |
} |