Browse Source

Merge pull request #1126 from mrjana/networkdb

Add driver api enhancements for gossip
Alessandro Boch 9 năm trước cách đây
mục cha
commit
5108711b88

+ 5 - 1
libnetwork/cmd/ovrouter/ovrouter.go

@@ -92,6 +92,10 @@ func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int,
 	return nil
 }
 
+func (ep *endpoint) AddTableEntry(tableName string, key string, value []byte) error {
+	return nil
+}
+
 func (ep *endpoint) DisableGatewayService() {}
 
 func main() {
@@ -120,7 +124,7 @@ func main() {
 	}
 
 	if err := r.d.CreateNetwork("testnetwork",
-		map[string]interface{}{}, nil, nil); err != nil {
+		map[string]interface{}{}, nil, nil, nil); err != nil {
 		fmt.Printf("Failed to create network in the driver: %v\n", err)
 		os.Exit(1)
 	}

+ 1 - 1
libnetwork/controller.go

@@ -506,7 +506,7 @@ func (c *controller) addNetwork(n *network) error {
 	}
 
 	// Create the network
-	if err := d.CreateNetwork(n.id, n.generic, n.getIPData(4), n.getIPData(6)); err != nil {
+	if err := d.CreateNetwork(n.id, n.generic, nil, n.getIPData(4), n.getIPData(6)); err != nil {
 		return err
 	}
 

+ 39 - 4
libnetwork/driverapi/driverapi.go

@@ -23,10 +23,15 @@ type Driver interface {
 	// associated with a given network id.
 	NetworkFree(nid string) error
 
-	// CreateNetwork invokes the driver method to create a network passing
-	// the network id and network specific config. The config mechanism will
-	// eventually be replaced with labels which are yet to be introduced.
-	CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []IPAMData) error
+	// CreateNetwork invokes the driver method to create a network
+	// passing the network id and network specific config. The
+	// config mechanism will eventually be replaced with labels
+	// which are yet to be introduced. The driver can return a
+	// list of table names for which it is interested in receiving
+	// notification when a CRUD operation is performed on any
+	// entry in that table. This will be ignored for local scope
+	// drivers.
+	CreateNetwork(nid string, options map[string]interface{}, nInfo NetworkInfo, ipV4Data, ipV6Data []IPAMData) error
 
 	// DeleteNetwork invokes the driver method to delete network passing
 	// the network id.
@@ -60,10 +65,24 @@ type Driver interface {
 	// programming that was done so far
 	RevokeExternalConnectivity(nid, eid string) error
 
+	// EventNotify notifies the driver when a CRUD operation has
+	// happened on a table of its interest as soon as this node
+	// receives such an event in the gossip layer. This method is
+	// only invoked for the global scope driver.
+	EventNotify(event EventType, nid string, tableName string, key string, value []byte)
+
 	// Type returns the the type of this driver, the network type this driver manages
 	Type() string
 }
 
+// NetworkInfo provides a go interface for drivers to provide network
+// specific information to libnetwork.
+type NetworkInfo interface {
+	// TableEventRegister registers driver interest in a given
+	// table name.
+	TableEventRegister(tableName string) error
+}
+
 // InterfaceInfo provides a go interface for drivers to retrive
 // network information to interface resources.
 type InterfaceInfo interface {
@@ -112,6 +131,10 @@ type JoinInfo interface {
 
 	// DisableGatewayService tells libnetwork not to provide Default GW for the container
 	DisableGatewayService()
+
+	// AddTableEntry adds a table entry to the gossip layer
+	// passing the table name, key and an opaque value.
+	AddTableEntry(tableName string, key string, value []byte) error
 }
 
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
@@ -134,3 +157,15 @@ type IPAMData struct {
 	Gateway      *net.IPNet
 	AuxAddresses map[string]*net.IPNet
 }
+
+// EventType defines a type for the CRUD event
+type EventType uint8
+
+const (
+	// Create event is generated when a table entry is created,
+	Create EventType = 1 + iota
+	// Update event is generated when a table entry is updated.
+	Update
+	// Delete event is generated when a table entry is deleted.
+	Delete
+)

+ 4 - 1
libnetwork/drivers/bridge/bridge.go

@@ -543,8 +543,11 @@ func (d *driver) NetworkFree(id string) error {
 	return types.NotImplementedErrorf("not implemented")
 }
 
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}
+
 // Create a new network using bridge plugin
-func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
 		return types.BadRequestErrorf("ipv4 pool is empty")
 	}

+ 17 - 13
libnetwork/drivers/bridge/bridge_test.go

@@ -69,7 +69,7 @@ func TestCreateFullOptions(t *testing.T) {
 			AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
 		},
 	}
-	err := d.CreateNetwork("dummy", netOption, ipdList, nil)
+	err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -95,7 +95,7 @@ func TestCreateNoConfig(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 
-	if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err != nil {
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 }
@@ -142,7 +142,7 @@ func TestCreateFullOptionsLabels(t *testing.T) {
 		},
 	}
 
-	err := d.CreateNetwork("dummy", netOption, ipdList, ipd6List)
+	err := d.CreateNetwork("dummy", netOption, nil, ipdList, ipd6List)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -211,11 +211,11 @@ func TestCreate(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 
-	if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err != nil {
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 
-	err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil)
+	err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil)
 	if err == nil {
 		t.Fatalf("Expected bridge driver to refuse creation of second network with default name")
 	}
@@ -236,7 +236,7 @@ func TestCreateFail(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 
-	if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err == nil {
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err == nil {
 		t.Fatal("Bridge creation was expected to fail")
 	}
 }
@@ -258,13 +258,13 @@ func TestCreateMultipleNetworks(t *testing.T) {
 	config1 := &networkConfiguration{BridgeName: "net_test_1"}
 	genericOption = make(map[string]interface{})
 	genericOption[netlabel.GenericData] = config1
-	if err := d.CreateNetwork("1", genericOption, getIPv4Data(t), nil); err != nil {
+	if err := d.CreateNetwork("1", genericOption, nil, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 
 	config2 := &networkConfiguration{BridgeName: "net_test_2"}
 	genericOption[netlabel.GenericData] = config2
-	if err := d.CreateNetwork("2", genericOption, getIPv4Data(t), nil); err != nil {
+	if err := d.CreateNetwork("2", genericOption, nil, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 
@@ -273,7 +273,7 @@ func TestCreateMultipleNetworks(t *testing.T) {
 
 	config3 := &networkConfiguration{BridgeName: "net_test_3"}
 	genericOption[netlabel.GenericData] = config3
-	if err := d.CreateNetwork("3", genericOption, getIPv4Data(t), nil); err != nil {
+	if err := d.CreateNetwork("3", genericOption, nil, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 
@@ -282,7 +282,7 @@ func TestCreateMultipleNetworks(t *testing.T) {
 
 	config4 := &networkConfiguration{BridgeName: "net_test_4"}
 	genericOption[netlabel.GenericData] = config4
-	if err := d.CreateNetwork("4", genericOption, getIPv4Data(t), nil); err != nil {
+	if err := d.CreateNetwork("4", genericOption, nil, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 
@@ -429,6 +429,10 @@ func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, ne
 	return nil
 }
 
+func (te *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
+	return nil
+}
+
 func (te *testEndpoint) DisableGatewayService() {}
 
 func TestQueryEndpointInfo(t *testing.T) {
@@ -462,7 +466,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
 	genericOption[netlabel.GenericData] = netconfig
 
 	ipdList := getIPv4Data(t)
-	err := d.CreateNetwork("net1", genericOption, ipdList, nil)
+	err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -563,7 +567,7 @@ func TestLinkContainers(t *testing.T) {
 	genericOption[netlabel.GenericData] = netconfig
 
 	ipdList := getIPv4Data(t)
-	err := d.CreateNetwork("net1", genericOption, ipdList, nil)
+	err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -789,7 +793,7 @@ func TestSetDefaultGw(t *testing.T) {
 	genericOption[netlabel.EnableIPv6] = true
 	genericOption[netlabel.GenericData] = config
 
-	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}

+ 4 - 4
libnetwork/drivers/bridge/network_test.go

@@ -27,7 +27,7 @@ func TestLinkCreate(t *testing.T) {
 	genericOption[netlabel.GenericData] = config
 
 	ipdList := getIPv4Data(t)
-	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -119,7 +119,7 @@ func TestLinkCreateTwo(t *testing.T) {
 	genericOption[netlabel.GenericData] = config
 
 	ipdList := getIPv4Data(t)
-	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -155,7 +155,7 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
 	genericOption[netlabel.GenericData] = config
 
 	ipdList := getIPv4Data(t)
-	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
@@ -190,7 +190,7 @@ func TestLinkDelete(t *testing.T) {
 	genericOption[netlabel.GenericData] = config
 
 	ipdList := getIPv4Data(t)
-	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}

+ 1 - 1
libnetwork/drivers/bridge/port_mapping_test.go

@@ -45,7 +45,7 @@ func TestPortMappingConfig(t *testing.T) {
 	netOptions[netlabel.GenericData] = netConfig
 
 	ipdList := getIPv4Data(t)
-	err := d.CreateNetwork("dummy", netOptions, ipdList, nil)
+	err := d.CreateNetwork("dummy", netOptions, nil, ipdList, nil)
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 	}

+ 4 - 1
libnetwork/drivers/host/host.go

@@ -32,7 +32,10 @@ func (d *driver) NetworkFree(id string) error {
 	return types.NotImplementedErrorf("not implemented")
 }
 
-func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}
+
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	d.Lock()
 	defer d.Unlock()
 

+ 2 - 2
libnetwork/drivers/host/host_test.go

@@ -14,7 +14,7 @@ func TestDriver(t *testing.T) {
 		t.Fatalf("Unexpected network type returned by driver")
 	}
 
-	err := d.CreateNetwork("first", nil, nil, nil)
+	err := d.CreateNetwork("first", nil, nil, nil, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -23,7 +23,7 @@ func TestDriver(t *testing.T) {
 		t.Fatalf("Unexpected network id stored")
 	}
 
-	err = d.CreateNetwork("second", nil, nil, nil)
+	err = d.CreateNetwork("second", nil, nil, nil, nil)
 	if err == nil {
 		t.Fatalf("Second network creation should fail on this driver")
 	}

+ 3 - 0
libnetwork/drivers/ipvlan/ipvlan.go

@@ -98,3 +98,6 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{})
 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
 	return nil
 }
+
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}

+ 1 - 1
libnetwork/drivers/ipvlan/ipvlan_network.go

@@ -14,7 +14,7 @@ import (
 )
 
 // CreateNetwork the network for the specified driver type
-func (d *driver) CreateNetwork(nid string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	defer osl.InitOSContext()()
 	kv, err := kernel.GetKernelVersion()
 	if err != nil {

+ 3 - 0
libnetwork/drivers/macvlan/macvlan.go

@@ -100,3 +100,6 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{})
 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
 	return nil
 }
+
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}

+ 1 - 1
libnetwork/drivers/macvlan/macvlan_network.go

@@ -14,7 +14,7 @@ import (
 )
 
 // CreateNetwork the network for the specified driver type
-func (d *driver) CreateNetwork(nid string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	defer osl.InitOSContext()()
 	kv, err := kernel.GetKernelVersion()
 	if err != nil {

+ 4 - 1
libnetwork/drivers/null/null.go

@@ -32,7 +32,10 @@ func (d *driver) NetworkFree(id string) error {
 	return types.NotImplementedErrorf("not implemented")
 }
 
-func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}
+
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	d.Lock()
 	defer d.Unlock()
 

+ 2 - 2
libnetwork/drivers/null/null_test.go

@@ -14,7 +14,7 @@ func TestDriver(t *testing.T) {
 		t.Fatalf("Unexpected network type returned by driver")
 	}
 
-	err := d.CreateNetwork("first", nil, nil, nil)
+	err := d.CreateNetwork("first", nil, nil, nil, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -23,7 +23,7 @@ func TestDriver(t *testing.T) {
 		t.Fatalf("Unexpected network id stored")
 	}
 
-	err = d.CreateNetwork("second", nil, nil, nil)
+	err = d.CreateNetwork("second", nil, nil, nil, nil)
 	if err == nil {
 		t.Fatalf("Second network creation should fail on this driver")
 	}

+ 4 - 1
libnetwork/drivers/overlay/ov_network.go

@@ -67,7 +67,10 @@ func (d *driver) NetworkFree(id string) error {
 	return types.NotImplementedErrorf("not implemented")
 }
 
-func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}
+
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	if id == "" {
 		return fmt.Errorf("invalid network id")
 	}

+ 4 - 1
libnetwork/drivers/overlay/ovmanager/ovmanager.go

@@ -187,10 +187,13 @@ func (n *network) releaseVxlanID() {
 	}
 }
 
-func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	return types.NotImplementedErrorf("not implemented")
 }
 
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}
+
 func (d *driver) DeleteNetwork(nid string) error {
 	return types.NotImplementedErrorf("not implemented")
 }

+ 4 - 1
libnetwork/drivers/remote/driver.go

@@ -91,7 +91,10 @@ func (d *driver) NetworkFree(id string) error {
 	return types.NotImplementedErrorf("not implemented")
 }
 
-func (d *driver) CreateNetwork(id string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}
+
+func (d *driver) CreateNetwork(id string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	create := &api.CreateNetworkRequest{
 		NetworkID: id,
 		Options:   options,

+ 5 - 1
libnetwork/drivers/remote/driver_test.go

@@ -199,6 +199,10 @@ func (test *testEndpoint) DisableGatewayService() {
 	test.disableGatewayService = true
 }
 
+func (test *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
+	return nil
+}
+
 func TestGetEmptyCapabilities(t *testing.T) {
 	var plugin = "test-net-driver-empty-cap"
 
@@ -400,7 +404,7 @@ func TestRemoteDriver(t *testing.T) {
 	}
 
 	netID := "dummy-network"
-	err = d.CreateNetwork(netID, map[string]interface{}{}, nil, nil)
+	err = d.CreateNetwork(netID, map[string]interface{}{}, nil, nil, nil)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 4 - 1
libnetwork/drivers/windows/windows.go

@@ -149,8 +149,11 @@ func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []d
 	return nil
 }
 
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}
+
 // Create a new network
-func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	if _, err := d.getNetwork(id); err == nil {
 		return types.ForbiddenErrorf("network %s exists", id)
 	}

+ 4 - 1
libnetwork/drvregistry/drvregistry_test.go

@@ -25,7 +25,7 @@ func mockDriverInit(reg driverapi.DriverCallback, opt map[string]interface{}) er
 	return reg.RegisterDriver(mockDriverName, &md, driverapi.Capability{DataScope: datastore.LocalScope})
 }
 
-func (m *mockDriver) CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (m *mockDriver) CreateNetwork(nid string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	return nil
 }
 
@@ -81,6 +81,9 @@ func (m *mockDriver) NetworkFree(id string) error {
 	return nil
 }
 
+func (m *mockDriver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}
+
 func getNew(t *testing.T) *DrvRegistry {
 	reg, err := New(nil, nil, nil, nil)
 	if err != nil {

+ 4 - 0
libnetwork/endpoint_info.go

@@ -292,6 +292,10 @@ func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHo
 	return nil
 }
 
+func (ep *endpoint) AddTableEntry(tableName, key string, value []byte) error {
+	return nil
+}
+
 func (ep *endpoint) Sandbox() Sandbox {
 	cnt, ok := ep.getSandbox()
 	if !ok {

+ 4 - 1
libnetwork/libnetwork_internal_test.go

@@ -393,7 +393,7 @@ func badDriverInit(reg driverapi.DriverCallback, opt map[string]interface{}) err
 	return reg.RegisterDriver(badDriverName, &bd, driverapi.Capability{DataScope: datastore.LocalScope})
 }
 
-func (b *badDriver) CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+func (b *badDriver) CreateNetwork(nid string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	if b.failNetworkCreation {
 		return fmt.Errorf("I will not create any network")
 	}
@@ -440,3 +440,6 @@ func (b *badDriver) NetworkAllocate(id string, option map[string]string, ipV4Dat
 func (b *badDriver) NetworkFree(id string) error {
 	return types.NotImplementedErrorf("not implemented")
 }
+
+func (b *badDriver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
+}