Bläddra i källkod

Vendoring of libnetwork

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>
Flavio Crisciani 7 år sedan
förälder
incheckning
c1e1fb6fa5

+ 1 - 1
vendor.conf

@@ -30,7 +30,7 @@ github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
 github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
 
 #get libnetwork packages
-github.com/docker/libnetwork 64ae58878fc8f95e4a167499d654e13fa36abdc7
+github.com/docker/libnetwork 9bca9a4a220b158cc94402e0f8c2c7714eb6f503
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec

+ 5 - 3
vendor/github.com/docker/libnetwork/agent.go

@@ -293,11 +293,13 @@ func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr, d
 			c.Config().Daemon.NetworkControlPlaneMTU, netDBConf.PacketBufferSize)
 	}
 	nDB, err := networkdb.New(netDBConf)
-
 	if err != nil {
 		return err
 	}
 
+	// Register the diagnose handlers
+	c.DiagnoseServer.RegisterHandler(nDB, networkdb.NetDbPaths2Func)
+
 	var cancelList []func()
 	ch, cancel := nDB.Watch(libnetworkEPTable, "", "")
 	cancelList = append(cancelList, cancel)
@@ -436,7 +438,7 @@ func (n *network) Services() map[string]ServiceInfo {
 	for eid, value := range entries {
 		var epRec EndpointRecord
 		nid := n.ID()
-		if err := proto.Unmarshal(value.([]byte), &epRec); err != nil {
+		if err := proto.Unmarshal(value.Value, &epRec); err != nil {
 			logrus.Errorf("Unmarshal of libnetworkEPTable failed for endpoint %s in network %s, %v", eid, nid, err)
 			continue
 		}
@@ -461,7 +463,7 @@ func (n *network) Services() map[string]ServiceInfo {
 		}
 		entries := agent.networkDB.GetTableByNetwork(table.name, n.id)
 		for key, value := range entries {
-			epID, info := d.DecodeTableEntry(table.name, key, value.([]byte))
+			epID, info := d.DecodeTableEntry(table.name, key, value.Value)
 			if ep, ok := eps[epID]; !ok {
 				logrus.Errorf("Inconsistent driver and libnetwork state for endpoint %s", epID)
 			} else {

+ 36 - 0
vendor/github.com/docker/libnetwork/controller.go

@@ -60,6 +60,7 @@ import (
 	"github.com/docker/libnetwork/cluster"
 	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/diagnose"
 	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/drvregistry"
@@ -133,6 +134,13 @@ type NetworkController interface {
 
 	// SetKeys configures the encryption key for gossip and overlay data path
 	SetKeys(keys []*types.EncryptionKey) error
+
+	// StartDiagnose start the network diagnose mode
+	StartDiagnose(port int)
+	// StopDiagnose start the network diagnose mode
+	StopDiagnose()
+	// IsDiagnoseEnabled returns true if the diagnose is enabled
+	IsDiagnoseEnabled() bool
 }
 
 // NetworkWalker is a client provided function which will be used to walk the Networks.
@@ -167,6 +175,7 @@ type controller struct {
 	agentStopDone          chan struct{}
 	keys                   []*types.EncryptionKey
 	clusterConfigAvailable bool
+	DiagnoseServer         *diagnose.Server
 	sync.Mutex
 }
 
@@ -185,7 +194,9 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 		serviceBindings: make(map[serviceKey]*service),
 		agentInitDone:   make(chan struct{}),
 		networkLocker:   locker.New(),
+		DiagnoseServer:  diagnose.New(),
 	}
+	c.DiagnoseServer.Init()
 
 	if err := c.initStores(); err != nil {
 		return nil, err
@@ -1291,3 +1302,28 @@ func (c *controller) Stop() {
 	c.stopExternalKeyListener()
 	osl.GC()
 }
+
+// StartDiagnose start the network diagnose mode
+func (c *controller) StartDiagnose(port int) {
+	c.Lock()
+	if !c.DiagnoseServer.IsDebugEnable() {
+		c.DiagnoseServer.EnableDebug("127.0.0.1", port)
+	}
+	c.Unlock()
+}
+
+// StopDiagnose start the network diagnose mode
+func (c *controller) StopDiagnose() {
+	c.Lock()
+	if c.DiagnoseServer.IsDebugEnable() {
+		c.DiagnoseServer.DisableDebug()
+	}
+	c.Unlock()
+}
+
+// IsDiagnoseEnabled returns true if the diagnose is enabled
+func (c *controller) IsDiagnoseEnabled() bool {
+	c.Lock()
+	defer c.Unlock()
+	return c.DiagnoseServer.IsDebugEnable()
+}

+ 0 - 133
vendor/github.com/docker/libnetwork/diagnose/diagnose.go

@@ -1,133 +0,0 @@
-package diagnose
-
-import (
-	"fmt"
-	"net"
-	"net/http"
-	"sync"
-
-	"github.com/sirupsen/logrus"
-)
-
-// HTTPHandlerFunc TODO
-type HTTPHandlerFunc func(interface{}, http.ResponseWriter, *http.Request)
-
-type httpHandlerCustom struct {
-	ctx interface{}
-	F   func(interface{}, http.ResponseWriter, *http.Request)
-}
-
-// ServeHTTP TODO
-func (h httpHandlerCustom) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	h.F(h.ctx, w, r)
-}
-
-var diagPaths2Func = map[string]HTTPHandlerFunc{
-	"/":      notImplemented,
-	"/help":  help,
-	"/ready": ready,
-}
-
-// Server when the debug is enabled exposes a
-// This data structure is protected by the Agent mutex so does not require and additional mutex here
-type Server struct {
-	sk                net.Listener
-	port              int
-	mux               *http.ServeMux
-	registeredHanders []string
-	sync.Mutex
-}
-
-// Init TODO
-func (n *Server) Init() {
-	n.mux = http.NewServeMux()
-
-	// Register local handlers
-	n.RegisterHandler(n, diagPaths2Func)
-}
-
-// RegisterHandler TODO
-func (n *Server) RegisterHandler(ctx interface{}, hdlrs map[string]HTTPHandlerFunc) {
-	n.Lock()
-	defer n.Unlock()
-	for path, fun := range hdlrs {
-		n.mux.Handle(path, httpHandlerCustom{ctx, fun})
-		n.registeredHanders = append(n.registeredHanders, path)
-	}
-}
-
-// EnableDebug opens a TCP socket to debug the passed network DB
-func (n *Server) EnableDebug(ip string, port int) {
-	n.Lock()
-	defer n.Unlock()
-
-	n.port = port
-	logrus.SetLevel(logrus.DebugLevel)
-
-	if n.sk != nil {
-		logrus.Infof("The server is already up and running")
-		return
-	}
-
-	logrus.Infof("Starting the server listening on %d for commands", port)
-
-	// // Create the socket
-	// var err error
-	// n.sk, err = net.Listen("tcp", listeningAddr)
-	// if err != nil {
-	// 	log.Fatal(err)
-	// }
-	//
-	// go func() {
-	// 	http.Serve(n.sk, n.mux)
-	// }()
-	http.ListenAndServe(fmt.Sprintf(":%d", port), n.mux)
-}
-
-// DisableDebug stop the dubug and closes the tcp socket
-func (n *Server) DisableDebug() {
-	n.Lock()
-	defer n.Unlock()
-	n.sk.Close()
-	n.sk = nil
-}
-
-// IsDebugEnable returns true when the debug is enabled
-func (n *Server) IsDebugEnable() bool {
-	n.Lock()
-	defer n.Unlock()
-	return n.sk != nil
-}
-
-func notImplemented(ctx interface{}, w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintf(w, "URL path: %s no method implemented check /help\n", r.URL.Path)
-}
-
-func help(ctx interface{}, w http.ResponseWriter, r *http.Request) {
-	n, ok := ctx.(*Server)
-	if ok {
-		for _, path := range n.registeredHanders {
-			fmt.Fprintf(w, "%s\n", path)
-		}
-	}
-}
-
-func ready(ctx interface{}, w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintf(w, "OK\n")
-}
-
-// DebugHTTPForm TODO
-func DebugHTTPForm(r *http.Request) {
-	r.ParseForm()
-	for k, v := range r.Form {
-		logrus.Debugf("Form[%q] = %q\n", k, v)
-	}
-}
-
-// HTTPReplyError TODO
-func HTTPReplyError(w http.ResponseWriter, message, usage string) {
-	fmt.Fprintf(w, "%s\n", message)
-	if usage != "" {
-		fmt.Fprintf(w, "Usage: %s\n", usage)
-	}
-}

+ 228 - 0
vendor/github.com/docker/libnetwork/diagnose/server.go

@@ -0,0 +1,228 @@
+package diagnose
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"sync"
+	"sync/atomic"
+
+	stackdump "github.com/docker/docker/pkg/signal"
+	"github.com/docker/libnetwork/common"
+	"github.com/sirupsen/logrus"
+)
+
+// HTTPHandlerFunc TODO
+type HTTPHandlerFunc func(interface{}, http.ResponseWriter, *http.Request)
+
+type httpHandlerCustom struct {
+	ctx interface{}
+	F   func(interface{}, http.ResponseWriter, *http.Request)
+}
+
+// ServeHTTP TODO
+func (h httpHandlerCustom) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	h.F(h.ctx, w, r)
+}
+
+var diagPaths2Func = map[string]HTTPHandlerFunc{
+	"/":          notImplemented,
+	"/help":      help,
+	"/ready":     ready,
+	"/stackdump": stackTrace,
+}
+
+// Server when the debug is enabled exposes a
+// This data structure is protected by the Agent mutex so does not require and additional mutex here
+type Server struct {
+	enable            int32
+	srv               *http.Server
+	port              int
+	mux               *http.ServeMux
+	registeredHanders map[string]bool
+	sync.Mutex
+}
+
+// New creates a new diagnose server
+func New() *Server {
+	return &Server{
+		registeredHanders: make(map[string]bool),
+	}
+}
+
+// Init initialize the mux for the http handling and register the base hooks
+func (s *Server) Init() {
+	s.mux = http.NewServeMux()
+
+	// Register local handlers
+	s.RegisterHandler(s, diagPaths2Func)
+}
+
+// RegisterHandler allows to register new handlers to the mux and to a specific path
+func (s *Server) RegisterHandler(ctx interface{}, hdlrs map[string]HTTPHandlerFunc) {
+	s.Lock()
+	defer s.Unlock()
+	for path, fun := range hdlrs {
+		if _, ok := s.registeredHanders[path]; ok {
+			continue
+		}
+		s.mux.Handle(path, httpHandlerCustom{ctx, fun})
+		s.registeredHanders[path] = true
+	}
+}
+
+// ServeHTTP this is the method called bu the ListenAndServe, and is needed to allow us to
+// use our custom mux
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	s.mux.ServeHTTP(w, r)
+}
+
+// EnableDebug opens a TCP socket to debug the passed network DB
+func (s *Server) EnableDebug(ip string, port int) {
+	s.Lock()
+	defer s.Unlock()
+
+	s.port = port
+
+	if s.enable == 1 {
+		logrus.Info("The server is already up and running")
+		return
+	}
+
+	logrus.Infof("Starting the diagnose server listening on %d for commands", port)
+	srv := &http.Server{Addr: fmt.Sprintf("127.0.0.1:%d", port), Handler: s}
+	s.srv = srv
+	s.enable = 1
+	go func(n *Server) {
+		// Ingore ErrServerClosed that is returned on the Shutdown call
+		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+			logrus.Errorf("ListenAndServe error: %s", err)
+			atomic.SwapInt32(&n.enable, 0)
+		}
+	}(s)
+
+}
+
+// DisableDebug stop the dubug and closes the tcp socket
+func (s *Server) DisableDebug() {
+	s.Lock()
+	defer s.Unlock()
+
+	s.srv.Shutdown(context.Background())
+	s.srv = nil
+	s.enable = 0
+	logrus.Info("Disabling the diagnose server")
+}
+
+// IsDebugEnable returns true when the debug is enabled
+func (s *Server) IsDebugEnable() bool {
+	s.Lock()
+	defer s.Unlock()
+	return s.enable == 1
+}
+
+func notImplemented(ctx interface{}, w http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	_, json := ParseHTTPFormOptions(r)
+	rsp := WrongCommand("not implemented", fmt.Sprintf("URL path: %s no method implemented check /help\n", r.URL.Path))
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("command not implemented done")
+
+	HTTPReply(w, rsp, json)
+}
+
+func help(ctx interface{}, w http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	_, json := ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("help done")
+
+	n, ok := ctx.(*Server)
+	var result string
+	if ok {
+		for path := range n.registeredHanders {
+			result += fmt.Sprintf("%s\n", path)
+		}
+		HTTPReply(w, CommandSucceed(&StringCmd{Info: result}), json)
+	}
+}
+
+func ready(ctx interface{}, w http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	_, json := ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("ready done")
+	HTTPReply(w, CommandSucceed(&StringCmd{Info: "OK"}), json)
+}
+
+func stackTrace(ctx interface{}, w http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	_, json := ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("stack trace")
+
+	path, err := stackdump.DumpStacks("/tmp/")
+	if err != nil {
+		log.WithError(err).Error("failed to write goroutines dump")
+		HTTPReply(w, FailCommand(err), json)
+	} else {
+		log.Info("stack trace done")
+		HTTPReply(w, CommandSucceed(&StringCmd{Info: fmt.Sprintf("goroutine stacks written to %s", path)}), json)
+	}
+}
+
+// DebugHTTPForm helper to print the form url parameters
+func DebugHTTPForm(r *http.Request) {
+	for k, v := range r.Form {
+		logrus.Debugf("Form[%q] = %q\n", k, v)
+	}
+}
+
+// JSONOutput contains details on JSON output printing
+type JSONOutput struct {
+	enable      bool
+	prettyPrint bool
+}
+
+// ParseHTTPFormOptions easily parse the JSON printing options
+func ParseHTTPFormOptions(r *http.Request) (bool, *JSONOutput) {
+	_, unsafe := r.Form["unsafe"]
+	v, json := r.Form["json"]
+	var pretty bool
+	if len(v) > 0 {
+		pretty = v[0] == "pretty"
+	}
+	return unsafe, &JSONOutput{enable: json, prettyPrint: pretty}
+}
+
+// HTTPReply helper function that takes care of sending the message out
+func HTTPReply(w http.ResponseWriter, r *HTTPResult, j *JSONOutput) (int, error) {
+	var response []byte
+	if j.enable {
+		w.Header().Set("Content-Type", "application/json")
+		var err error
+		if j.prettyPrint {
+			response, err = json.MarshalIndent(r, "", "  ")
+			if err != nil {
+				response, _ = json.MarshalIndent(FailCommand(err), "", "  ")
+			}
+		} else {
+			response, err = json.Marshal(r)
+			if err != nil {
+				response, _ = json.Marshal(FailCommand(err))
+			}
+		}
+	} else {
+		response = []byte(r.String())
+	}
+	return fmt.Fprint(w, string(response))
+}

+ 122 - 0
vendor/github.com/docker/libnetwork/diagnose/types.go

@@ -0,0 +1,122 @@
+package diagnose
+
+import "fmt"
+
+// StringInterface interface that has to be implemented by messages
+type StringInterface interface {
+	String() string
+}
+
+// CommandSucceed creates a success message
+func CommandSucceed(result StringInterface) *HTTPResult {
+	return &HTTPResult{
+		Message: "OK",
+		Details: result,
+	}
+}
+
+// FailCommand creates a failure message with error
+func FailCommand(err error) *HTTPResult {
+	return &HTTPResult{
+		Message: "FAIL",
+		Details: &ErrorCmd{Error: err.Error()},
+	}
+}
+
+// WrongCommand creates a wrong command response
+func WrongCommand(message, usage string) *HTTPResult {
+	return &HTTPResult{
+		Message: message,
+		Details: &UsageCmd{Usage: usage},
+	}
+}
+
+// HTTPResult Diagnose Server HTTP result operation
+type HTTPResult struct {
+	Message string          `json:"message"`
+	Details StringInterface `json:"details"`
+}
+
+func (h *HTTPResult) String() string {
+	rsp := h.Message
+	if h.Details != nil {
+		rsp += "\n" + h.Details.String()
+	}
+	return rsp
+}
+
+// UsageCmd command with usage field
+type UsageCmd struct {
+	Usage string `json:"usage"`
+}
+
+func (u *UsageCmd) String() string {
+	return "Usage: " + u.Usage
+}
+
+// StringCmd command with info string
+type StringCmd struct {
+	Info string `json:"info"`
+}
+
+func (s *StringCmd) String() string {
+	return s.Info
+}
+
+// ErrorCmd command with error
+type ErrorCmd struct {
+	Error string `json:"error"`
+}
+
+func (e *ErrorCmd) String() string {
+	return "Error: " + e.Error
+}
+
+// TableObj network db table object
+type TableObj struct {
+	Length   int               `json:"size"`
+	Elements []StringInterface `json:"entries"`
+}
+
+func (t *TableObj) String() string {
+	output := fmt.Sprintf("total entries: %d\n", t.Length)
+	for _, e := range t.Elements {
+		output += e.String()
+	}
+	return output
+}
+
+// PeerEntryObj entry in the networkdb peer table
+type PeerEntryObj struct {
+	Index int    `json:"-"`
+	Name  string `json:"-=name"`
+	IP    string `json:"ip"`
+}
+
+func (p *PeerEntryObj) String() string {
+	return fmt.Sprintf("%d) %s -> %s\n", p.Index, p.Name, p.IP)
+}
+
+// TableEntryObj network db table entry object
+type TableEntryObj struct {
+	Index int    `json:"-"`
+	Key   string `json:"key"`
+	Value string `json:"value"`
+	Owner string `json:"owner"`
+}
+
+func (t *TableEntryObj) String() string {
+	return fmt.Sprintf("%d) k:`%s` -> v:`%s` owner:`%s`\n", t.Index, t.Key, t.Value, t.Owner)
+}
+
+// TableEndpointsResult fully typed message for proper unmarshaling on the client side
+type TableEndpointsResult struct {
+	TableObj
+	Elements []TableEntryObj `json:"entries"`
+}
+
+// TablePeersResult fully typed message for proper unmarshaling on the client side
+type TablePeersResult struct {
+	TableObj
+	Elements []PeerEntryObj `json:"entries"`
+}

+ 69 - 83
vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -42,6 +42,14 @@ const (
 	DefaultGatewayV6AuxKey = "DefaultGatewayIPv6"
 )
 
+type defaultBridgeNetworkConflict struct {
+	ID string
+}
+
+func (d defaultBridgeNetworkConflict) Error() string {
+	return fmt.Sprintf("Stale default bridge network %s", d.ID)
+}
+
 type iptableCleanFunc func() error
 type iptablesCleanFuncs []iptableCleanFunc
 
@@ -137,6 +145,7 @@ type driver struct {
 	networks       map[string]*bridgeNetwork
 	store          datastore.DataStore
 	nlh            *netlink.Handle
+	configNetwork  sync.Mutex
 	sync.Mutex
 }
 
@@ -322,41 +331,6 @@ func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) err
 	return nil
 }
 
-// Checks whether this network's configuration for the network with this id conflicts with any of the passed networks
-func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridgeNetwork) error {
-	for _, nw := range others {
-
-		nw.Lock()
-		nwID := nw.id
-		nwConfig := nw.config
-		nwBridge := nw.bridge
-		nw.Unlock()
-
-		if nwID == id {
-			continue
-		}
-		// Verify the name (which may have been set by newInterface()) does not conflict with
-		// existing bridge interfaces. Ironically the system chosen name gets stored in the config...
-		// Basically we are checking if the two original configs were both empty.
-		if nwConfig.BridgeName == c.BridgeName {
-			return types.ForbiddenErrorf("conflicts with network %s (%s) by bridge name", nwID, nwConfig.BridgeName)
-		}
-		// If this network config specifies the AddressIPv4, we need
-		// to make sure it does not conflict with any previously allocated
-		// bridges. This could not be completely caught by the config conflict
-		// check, because networks which config does not specify the AddressIPv4
-		// get their address and subnet selected by the driver (see electBridgeIPv4())
-		if c.AddressIPv4 != nil && nwBridge.bridgeIPv4 != nil {
-			if nwBridge.bridgeIPv4.Contains(c.AddressIPv4.IP) ||
-				c.AddressIPv4.Contains(nwBridge.bridgeIPv4.IP) {
-				return types.ForbiddenErrorf("conflicts with network %s (%s) by ip network", nwID, nwConfig.BridgeName)
-			}
-		}
-	}
-
-	return nil
-}
-
 func (d *driver) configure(option map[string]interface{}) error {
 	var (
 		config         *configuration
@@ -602,11 +576,27 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
 		return err
 	}
 
-	err = config.processIPAM(id, ipV4Data, ipV6Data)
-	if err != nil {
+	if err = config.processIPAM(id, ipV4Data, ipV6Data); err != nil {
 		return err
 	}
 
+	// start the critical section, from this point onward we are dealing with the list of networks
+	// so to be consistent we cannot allow that the list changes
+	d.configNetwork.Lock()
+	defer d.configNetwork.Unlock()
+
+	// check network conflicts
+	if err = d.checkConflict(config); err != nil {
+		nerr, ok := err.(defaultBridgeNetworkConflict)
+		if !ok {
+			return err
+		}
+		// Got a conflict with a stale default network, clean that up and continue
+		logrus.Warn(nerr)
+		d.deleteNetwork(nerr.ID)
+	}
+
+	// there is no conflict, now create the network
 	if err = d.createNetwork(config); err != nil {
 		return err
 	}
@@ -614,34 +604,48 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
 	return d.storeUpdate(config)
 }
 
-func (d *driver) createNetwork(config *networkConfiguration) error {
-	var err error
-
-	defer osl.InitOSContext()()
-
+func (d *driver) checkConflict(config *networkConfiguration) error {
 	networkList := d.getNetworks()
-	for i, nw := range networkList {
+	for _, nw := range networkList {
 		nw.Lock()
 		nwConfig := nw.config
 		nw.Unlock()
 		if err := nwConfig.Conflicts(config); err != nil {
 			if config.DefaultBridge {
 				// We encountered and identified a stale default network
-				// We must delete it as libnetwork is the source of thruth
+				// We must delete it as libnetwork is the source of truth
 				// The default network being created must be the only one
 				// This can happen only from docker 1.12 on ward
-				logrus.Infof("Removing stale default bridge network %s (%s)", nwConfig.ID, nwConfig.BridgeName)
-				if err := d.DeleteNetwork(nwConfig.ID); err != nil {
-					logrus.Warnf("Failed to remove stale default network: %s (%s): %v. Will remove from store.", nwConfig.ID, nwConfig.BridgeName, err)
-					d.storeDelete(nwConfig)
-				}
-				networkList = append(networkList[:i], networkList[i+1:]...)
-			} else {
-				return types.ForbiddenErrorf("cannot create network %s (%s): conflicts with network %s (%s): %s",
-					config.ID, config.BridgeName, nwConfig.ID, nwConfig.BridgeName, err.Error())
+				logrus.Infof("Found stale default bridge network %s (%s)", nwConfig.ID, nwConfig.BridgeName)
+				return defaultBridgeNetworkConflict{nwConfig.ID}
 			}
+
+			return types.ForbiddenErrorf("cannot create network %s (%s): conflicts with network %s (%s): %s",
+				config.ID, config.BridgeName, nwConfig.ID, nwConfig.BridgeName, err.Error())
 		}
 	}
+	return nil
+}
+
+func (d *driver) createNetwork(config *networkConfiguration) error {
+	var err error
+
+	defer osl.InitOSContext()()
+
+	networkList := d.getNetworks()
+
+	// Initialize handle when needed
+	d.Lock()
+	if d.nlh == nil {
+		d.nlh = ns.NlHandle()
+	}
+	d.Unlock()
+
+	// Create or retrieve the bridge L3 interface
+	bridgeIface, err := newInterface(d.nlh, config)
+	if err != nil {
+		return err
+	}
 
 	// Create and set network handler in driver
 	network := &bridgeNetwork{
@@ -649,6 +653,7 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
 		endpoints:  make(map[string]*bridgeEndpoint),
 		config:     config,
 		portMapper: portmapper.New(d.config.UserlandProxyPath),
+		bridge:     bridgeIface,
 		driver:     d,
 	}
 
@@ -665,35 +670,15 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
 		}
 	}()
 
-	// Initialize handle when needed
-	d.Lock()
-	if d.nlh == nil {
-		d.nlh = ns.NlHandle()
-	}
-	d.Unlock()
-
-	// Create or retrieve the bridge L3 interface
-	bridgeIface, err := newInterface(d.nlh, config)
-	if err != nil {
-		return err
-	}
-	network.bridge = bridgeIface
-
-	// Verify the network configuration does not conflict with previously installed
-	// networks. This step is needed now because driver might have now set the bridge
-	// name on this config struct. And because we need to check for possible address
-	// conflicts, so we need to check against operationa lnetworks.
-	if err = config.conflictsWithNetworks(config.ID, networkList); err != nil {
-		return err
-	}
-
+	// Add inter-network communication rules.
 	setupNetworkIsolationRules := func(config *networkConfiguration, i *bridgeInterface) error {
 		if err := network.isolateNetwork(networkList, true); err != nil {
-			if err := network.isolateNetwork(networkList, false); err != nil {
+			if err = network.isolateNetwork(networkList, false); err != nil {
 				logrus.Warnf("Failed on removing the inter-network iptables rules on cleanup: %v", err)
 			}
 			return err
 		}
+		// register the cleanup function
 		network.registerIptCleanFunc(func() error {
 			nwList := d.getNetworks()
 			return network.isolateNetwork(nwList, false)
@@ -767,10 +752,17 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
 }
 
 func (d *driver) DeleteNetwork(nid string) error {
+
+	d.configNetwork.Lock()
+	defer d.configNetwork.Unlock()
+
+	return d.deleteNetwork(nid)
+}
+
+func (d *driver) deleteNetwork(nid string) error {
 	var err error
 
 	defer osl.InitOSContext()()
-
 	// Get network handler and remove it from driver
 	d.Lock()
 	n, ok := d.networks[nid]
@@ -814,12 +806,6 @@ func (d *driver) DeleteNetwork(nid string) error {
 		}
 	}()
 
-	// Sanity check
-	if n == nil {
-		err = driverapi.ErrNoNetwork(nid)
-		return err
-	}
-
 	switch config.BridgeIfaceCreator {
 	case ifaceCreatedByLibnetwork, ifaceCreatorUnknown:
 		// We only delete the bridge if it was created by the bridge driver and

+ 1 - 1
vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go

@@ -9,7 +9,7 @@ func (n *bridgeNetwork) setupFirewalld(config *networkConfiguration, i *bridgeIn
 	d.Unlock()
 
 	// Sanity check.
-	if driverConfig.EnableIPTables == false {
+	if !driverConfig.EnableIPTables {
 		return IPTableCfgError(config.BridgeName)
 	}
 

+ 11 - 0
vendor/github.com/docker/libnetwork/drivers/overlay/ov_network.go

@@ -696,6 +696,12 @@ func (n *network) initSandbox(restore bool) error {
 	var nlSock *nl.NetlinkSocket
 	sbox.InvokeFunc(func() {
 		nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH)
+		if err != nil {
+			return
+		}
+		// set the receive timeout to not remain stuck on the RecvFrom if the fd gets closed
+		tv := syscall.NsecToTimeval(soTimeout.Nanoseconds())
+		err = nlSock.SetReceiveTimeout(&tv)
 	})
 	n.setNetlinkSocket(nlSock)
 
@@ -721,6 +727,11 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
 				// The netlink socket got closed, simply exit to not leak this goroutine
 				return
 			}
+			// When the receive timeout expires the receive will return EAGAIN
+			if err == syscall.EAGAIN {
+				// we continue here to avoid spam for timeouts
+				continue
+			}
 			logrus.Errorf("Failed to receive from netlink: %v ", err)
 			continue
 		}

+ 16 - 0
vendor/github.com/docker/libnetwork/ipvs/ipvs.go

@@ -5,12 +5,19 @@ package ipvs
 import (
 	"net"
 	"syscall"
+	"time"
 
 	"fmt"
+
 	"github.com/vishvananda/netlink/nl"
 	"github.com/vishvananda/netns"
 )
 
+const (
+	netlinkRecvSocketsTimeout = 3 * time.Second
+	netlinkSendSocketTimeout  = 30 * time.Second
+)
+
 // Service defines an IPVS service in its entirety.
 type Service struct {
 	// Virtual service address.
@@ -82,6 +89,15 @@ func New(path string) (*Handle, error) {
 	if err != nil {
 		return nil, err
 	}
+	// Add operation timeout to avoid deadlocks
+	tv := syscall.NsecToTimeval(netlinkSendSocketTimeout.Nanoseconds())
+	if err := sock.SetSendTimeout(&tv); err != nil {
+		return nil, err
+	}
+	tv = syscall.NsecToTimeval(netlinkRecvSocketsTimeout.Nanoseconds())
+	if err := sock.SetReceiveTimeout(&tv); err != nil {
+		return nil, err
+	}
 
 	return &Handle{sock: sock}, nil
 }

+ 7 - 4
vendor/github.com/docker/libnetwork/ipvs/netlink.go

@@ -203,10 +203,6 @@ func newGenlRequest(familyID int, cmd uint8) *nl.NetlinkRequest {
 }
 
 func execute(s *nl.NetlinkSocket, req *nl.NetlinkRequest, resType uint16) ([][]byte, error) {
-	var (
-		err error
-	)
-
 	if err := s.Send(req); err != nil {
 		return nil, err
 	}
@@ -222,6 +218,13 @@ done:
 	for {
 		msgs, err := s.Receive()
 		if err != nil {
+			if s.GetFd() == -1 {
+				return nil, fmt.Errorf("Socket got closed on receive")
+			}
+			if err == syscall.EAGAIN {
+				// timeout fired
+				continue
+			}
 			return nil, err
 		}
 		for _, m := range msgs {

+ 1 - 1
vendor/github.com/docker/libnetwork/networkdb/event_delegate.go

@@ -72,7 +72,7 @@ func (e *eventDelegate) NotifyLeave(mn *memberlist.Node) {
 	// If the node instead left because was going down, then it makes sense to just delete all its state
 	e.nDB.Lock()
 	defer e.nDB.Unlock()
-	e.nDB.deleteNetworkEntriesForNode(mn.Name)
+	e.nDB.deleteNodeFromNetworks(mn.Name)
 	e.nDB.deleteNodeTableEntries(mn.Name)
 	if n, ok := e.nDB.nodes[mn.Name]; ok {
 		delete(e.nDB.nodes, mn.Name)

+ 13 - 5
vendor/github.com/docker/libnetwork/networkdb/networkdb.go

@@ -401,17 +401,23 @@ func (nDB *NetworkDB) UpdateEntry(tname, nid, key string, value []byte) error {
 	return nil
 }
 
+// TableElem elem
+type TableElem struct {
+	Value []byte
+	owner string
+}
+
 // GetTableByNetwork walks the networkdb by the give table and network id and
 // returns a map of keys and values
-func (nDB *NetworkDB) GetTableByNetwork(tname, nid string) map[string]interface{} {
-	entries := make(map[string]interface{})
+func (nDB *NetworkDB) GetTableByNetwork(tname, nid string) map[string]*TableElem {
+	entries := make(map[string]*TableElem)
 	nDB.indexes[byTable].WalkPrefix(fmt.Sprintf("/%s/%s", tname, nid), func(k string, v interface{}) bool {
 		entry := v.(*entry)
 		if entry.deleting {
 			return false
 		}
 		key := k[strings.LastIndex(k, "/")+1:]
-		entries[key] = entry.value
+		entries[key] = &TableElem{Value: entry.value, owner: entry.node}
 		return false
 	})
 	return entries
@@ -445,7 +451,7 @@ func (nDB *NetworkDB) DeleteEntry(tname, nid, key string) error {
 	return nil
 }
 
-func (nDB *NetworkDB) deleteNetworkEntriesForNode(deletedNode string) {
+func (nDB *NetworkDB) deleteNodeFromNetworks(deletedNode string) {
 	for nid, nodes := range nDB.networkNodes {
 		updatedNodes := make([]string, 0, len(nodes))
 		for _, node := range nodes {
@@ -547,7 +553,9 @@ func (nDB *NetworkDB) deleteNodeTableEntries(node string) {
 
 		nDB.deleteEntry(nid, tname, key)
 
-		nDB.broadcaster.Write(makeEvent(opDelete, tname, nid, key, oldEntry.value))
+		if !oldEntry.deleting {
+			nDB.broadcaster.Write(makeEvent(opDelete, tname, nid, key, oldEntry.value))
+		}
 		return false
 	})
 }

+ 198 - 44
vendor/github.com/docker/libnetwork/networkdb/networkdbdiagnose.go

@@ -1,17 +1,19 @@
 package networkdb
 
 import (
+	"encoding/base64"
 	"fmt"
 	"net/http"
 	"strings"
 
-	stackdump "github.com/docker/docker/pkg/signal"
+	"github.com/docker/libnetwork/common"
 	"github.com/docker/libnetwork/diagnose"
 	"github.com/sirupsen/logrus"
 )
 
 const (
 	missingParameter = "missing parameter"
+	dbNotAvailable   = "database not available"
 )
 
 // NetDbPaths2Func TODO
@@ -26,14 +28,21 @@ var NetDbPaths2Func = map[string]diagnose.HTTPHandlerFunc{
 	"/deleteentry":  dbDeleteEntry,
 	"/getentry":     dbGetEntry,
 	"/gettable":     dbGetTable,
-	"/dump":         dbStackTrace,
 }
 
 func dbJoin(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	_, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("join cluster")
+
 	if len(r.Form["members"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?members=ip1,ip2,...", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?members=ip1,ip2,...", r.URL.Path))
+		log.Error("join cluster failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
@@ -41,51 +50,88 @@ func dbJoin(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	if ok {
 		err := nDB.Join(strings.Split(r.Form["members"][0], ","))
 		if err != nil {
-			fmt.Fprintf(w, "%s error in the DB join %s\n", r.URL.Path, err)
+			rsp := diagnose.FailCommand(fmt.Errorf("%s error in the DB join %s", r.URL.Path, err))
+			log.WithError(err).Error("join cluster failed")
+			diagnose.HTTPReply(w, rsp, json)
 			return
 		}
 
-		fmt.Fprintf(w, "OK\n")
+		log.Info("join cluster done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(nil), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	_, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("network peers")
+
 	if len(r.Form["nid"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?nid=test", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?nid=test", r.URL.Path))
+		log.Error("network peers failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
 	nDB, ok := ctx.(*NetworkDB)
 	if ok {
 		peers := nDB.Peers(r.Form["nid"][0])
-		fmt.Fprintf(w, "Network:%s Total peers: %d\n", r.Form["nid"], len(peers))
+		rsp := &diagnose.TableObj{Length: len(peers)}
 		for i, peerInfo := range peers {
-			fmt.Fprintf(w, "%d) %s -> %s\n", i, peerInfo.Name, peerInfo.IP)
+			rsp.Elements = append(rsp.Elements, &diagnose.PeerEntryObj{Index: i, Name: peerInfo.Name, IP: peerInfo.IP})
 		}
+		log.WithField("response", fmt.Sprintf("%+v", rsp)).Info("network peers done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(rsp), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbClusterPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	diagnose.DebugHTTPForm(r)
+	_, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("cluster peers")
+
 	nDB, ok := ctx.(*NetworkDB)
 	if ok {
 		peers := nDB.ClusterPeers()
-		fmt.Fprintf(w, "Total peers: %d\n", len(peers))
+		rsp := &diagnose.TableObj{Length: len(peers)}
 		for i, peerInfo := range peers {
-			fmt.Fprintf(w, "%d) %s -> %s\n", i, peerInfo.Name, peerInfo.IP)
+			rsp.Elements = append(rsp.Elements, &diagnose.PeerEntryObj{Index: i, Name: peerInfo.Name, IP: peerInfo.IP})
 		}
+		log.WithField("response", fmt.Sprintf("%+v", rsp)).Info("cluster peers done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(rsp), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbCreateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	unsafe, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("create entry")
+
 	if len(r.Form["tname"]) < 1 ||
 		len(r.Form["nid"]) < 1 ||
 		len(r.Form["key"]) < 1 ||
 		len(r.Form["value"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k&value=v", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k&value=v", r.URL.Path))
+		log.Error("create entry failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
@@ -93,25 +139,48 @@ func dbCreateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	nid := r.Form["nid"][0]
 	key := r.Form["key"][0]
 	value := r.Form["value"][0]
+	decodedValue := []byte(value)
+	if !unsafe {
+		var err error
+		decodedValue, err = base64.StdEncoding.DecodeString(value)
+		if err != nil {
+			log.WithError(err).Error("create entry failed")
+			diagnose.HTTPReply(w, diagnose.FailCommand(err), json)
+			return
+		}
+	}
 
 	nDB, ok := ctx.(*NetworkDB)
 	if ok {
-		if err := nDB.CreateEntry(tname, nid, key, []byte(value)); err != nil {
-			diagnose.HTTPReplyError(w, err.Error(), "")
+		if err := nDB.CreateEntry(tname, nid, key, decodedValue); err != nil {
+			rsp := diagnose.FailCommand(err)
+			diagnose.HTTPReply(w, rsp, json)
+			log.WithError(err).Error("create entry failed")
 			return
 		}
-		fmt.Fprintf(w, "OK\n")
+		log.Info("create entry done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(nil), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbUpdateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	unsafe, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("update entry")
+
 	if len(r.Form["tname"]) < 1 ||
 		len(r.Form["nid"]) < 1 ||
 		len(r.Form["key"]) < 1 ||
 		len(r.Form["value"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k&value=v", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k&value=v", r.URL.Path))
+		log.Error("update entry failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
@@ -119,24 +188,46 @@ func dbUpdateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	nid := r.Form["nid"][0]
 	key := r.Form["key"][0]
 	value := r.Form["value"][0]
+	decodedValue := []byte(value)
+	if !unsafe {
+		var err error
+		decodedValue, err = base64.StdEncoding.DecodeString(value)
+		if err != nil {
+			log.WithError(err).Error("update entry failed")
+			diagnose.HTTPReply(w, diagnose.FailCommand(err), json)
+			return
+		}
+	}
 
 	nDB, ok := ctx.(*NetworkDB)
 	if ok {
-		if err := nDB.UpdateEntry(tname, nid, key, []byte(value)); err != nil {
-			diagnose.HTTPReplyError(w, err.Error(), "")
+		if err := nDB.UpdateEntry(tname, nid, key, decodedValue); err != nil {
+			log.WithError(err).Error("update entry failed")
+			diagnose.HTTPReply(w, diagnose.FailCommand(err), json)
 			return
 		}
-		fmt.Fprintf(w, "OK\n")
+		log.Info("update entry done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(nil), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbDeleteEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	_, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("delete entry")
+
 	if len(r.Form["tname"]) < 1 ||
 		len(r.Form["nid"]) < 1 ||
 		len(r.Form["key"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k", r.URL.Path))
+		log.Error("delete entry failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
@@ -148,20 +239,32 @@ func dbDeleteEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	if ok {
 		err := nDB.DeleteEntry(tname, nid, key)
 		if err != nil {
-			diagnose.HTTPReplyError(w, err.Error(), "")
+			log.WithError(err).Error("delete entry failed")
+			diagnose.HTTPReply(w, diagnose.FailCommand(err), json)
 			return
 		}
-		fmt.Fprintf(w, "OK\n")
+		log.Info("delete entry done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(nil), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbGetEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	unsafe, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("get entry")
+
 	if len(r.Form["tname"]) < 1 ||
 		len(r.Form["nid"]) < 1 ||
 		len(r.Form["key"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id&key=k", r.URL.Path))
+		log.Error("get entry failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
@@ -173,18 +276,39 @@ func dbGetEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	if ok {
 		value, err := nDB.GetEntry(tname, nid, key)
 		if err != nil {
-			diagnose.HTTPReplyError(w, err.Error(), "")
+			log.WithError(err).Error("get entry failed")
+			diagnose.HTTPReply(w, diagnose.FailCommand(err), json)
 			return
 		}
-		fmt.Fprintf(w, "key:`%s` value:`%s`\n", key, string(value))
+
+		var encodedValue string
+		if unsafe {
+			encodedValue = string(value)
+		} else {
+			encodedValue = base64.StdEncoding.EncodeToString(value)
+		}
+
+		rsp := &diagnose.TableEntryObj{Key: key, Value: encodedValue}
+		log.WithField("response", fmt.Sprintf("%+v", rsp)).Info("update entry done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(rsp), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbJoinNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	_, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("join network")
+
 	if len(r.Form["nid"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?nid=network_id", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?nid=network_id", r.URL.Path))
+		log.Error("join network failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
@@ -193,18 +317,30 @@ func dbJoinNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	nDB, ok := ctx.(*NetworkDB)
 	if ok {
 		if err := nDB.JoinNetwork(nid); err != nil {
-			diagnose.HTTPReplyError(w, err.Error(), "")
+			log.WithError(err).Error("join network failed")
+			diagnose.HTTPReply(w, diagnose.FailCommand(err), json)
 			return
 		}
-		fmt.Fprintf(w, "OK\n")
+		log.Info("join network done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(nil), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbLeaveNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	_, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("leave network")
+
 	if len(r.Form["nid"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?nid=network_id", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?nid=network_id", r.URL.Path))
+		log.Error("leave network failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
@@ -213,19 +349,31 @@ func dbLeaveNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	nDB, ok := ctx.(*NetworkDB)
 	if ok {
 		if err := nDB.LeaveNetwork(nid); err != nil {
-			diagnose.HTTPReplyError(w, err.Error(), "")
+			log.WithError(err).Error("leave network failed")
+			diagnose.HTTPReply(w, diagnose.FailCommand(err), json)
 			return
 		}
-		fmt.Fprintf(w, "OK\n")
+		log.Info("leave network done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(nil), json)
+		return
 	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }
 
 func dbGetTable(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	r.ParseForm()
 	diagnose.DebugHTTPForm(r)
+	unsafe, json := diagnose.ParseHTTPFormOptions(r)
+
+	// audit logs
+	log := logrus.WithFields(logrus.Fields{"component": "diagnose", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
+	log.Info("get table")
+
 	if len(r.Form["tname"]) < 1 ||
 		len(r.Form["nid"]) < 1 {
-		diagnose.HTTPReplyError(w, missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id", r.URL.Path))
+		rsp := diagnose.WrongCommand(missingParameter, fmt.Sprintf("%s?tname=table_name&nid=network_id", r.URL.Path))
+		log.Error("get table failed, wrong input")
+		diagnose.HTTPReply(w, rsp, json)
 		return
 	}
 
@@ -235,20 +383,26 @@ func dbGetTable(ctx interface{}, w http.ResponseWriter, r *http.Request) {
 	nDB, ok := ctx.(*NetworkDB)
 	if ok {
 		table := nDB.GetTableByNetwork(tname, nid)
-		fmt.Fprintf(w, "total elements: %d\n", len(table))
-		i := 0
+		rsp := &diagnose.TableObj{Length: len(table)}
+		var i = 0
 		for k, v := range table {
-			fmt.Fprintf(w, "%d) k:`%s` -> v:`%s`\n", i, k, string(v.([]byte)))
-			i++
+			var encodedValue string
+			if unsafe {
+				encodedValue = string(v.Value)
+			} else {
+				encodedValue = base64.StdEncoding.EncodeToString(v.Value)
+			}
+			rsp.Elements = append(rsp.Elements,
+				&diagnose.TableEntryObj{
+					Index: i,
+					Key:   k,
+					Value: encodedValue,
+					Owner: v.owner,
+				})
 		}
+		log.WithField("response", fmt.Sprintf("%+v", rsp)).Info("get table done")
+		diagnose.HTTPReply(w, diagnose.CommandSucceed(rsp), json)
+		return
 	}
-}
-
-func dbStackTrace(ctx interface{}, w http.ResponseWriter, r *http.Request) {
-	path, err := stackdump.DumpStacks("/tmp/")
-	if err != nil {
-		logrus.WithError(err).Error("failed to write goroutines dump")
-	} else {
-		fmt.Fprintf(w, "goroutine stacks written to %s", path)
-	}
+	diagnose.HTTPReply(w, diagnose.FailCommand(fmt.Errorf("%s", dbNotAvailable)), json)
 }

+ 1 - 1
vendor/github.com/docker/libnetwork/vendor.conf

@@ -45,7 +45,7 @@ github.com/sirupsen/logrus v1.0.3
 github.com/stretchr/testify dab07ac62d4905d3e48d17dc549c684ac3b7c15a
 github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
 github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
-github.com/vishvananda/netlink bd6d5de5ccef2d66b0a26177928d0d8895d7f969
+github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e
 github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
 golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6