[ONOS-2262] - OVSDB -- Create the implementation of HostProvider using
OVSDB prototol.
1.Notify the Host System when the ovsdb vm port is added.
2.Notify the Host System when the ovsdb vm port is removed.

Change-Id: I46355cec84db897360a6eb37190a5bd7a8f3047d
diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/DefaultEventSubject.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/DefaultEventSubject.java
new file mode 100644
index 0000000..5d9134b
--- /dev/null
+++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/DefaultEventSubject.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ovsdb.controller;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+import java.util.Objects;
+import java.util.Set;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+
+/**
+ * This class is default event subject that implements OvsdbEventSubject.
+ */
+public class DefaultEventSubject implements OvsdbEventSubject {
+    private final MacAddress mac;
+    private final Set<IpAddress> ips;
+    private final OvsdbPortName portname;
+    private final OvsdbPortNumber portnumber;
+    private final OvsdbDatapathId dpid;
+    private final OvsdbPortType portType;
+    private final OvsdbIfaceId ifaceid;
+
+    /**
+     * Creates an end-station event subject using the supplied information.
+     *
+     * @param mac host MAC address
+     * @param ips host MAC ips
+     * @param portname port name
+     * @param portnumber port number
+     * @param dpid ovs dpid
+     * @param portType port type
+     * @param ifaceid  vm ifaceid
+     */
+    public DefaultEventSubject(MacAddress mac, Set<IpAddress> ips,
+                               OvsdbPortName portname, OvsdbPortNumber portnumber, OvsdbDatapathId dpid,
+                               OvsdbPortType portType, OvsdbIfaceId ifaceid) {
+        super();
+        this.mac = mac;
+        this.ips = ips;
+        this.portname = portname;
+        this.portnumber = portnumber;
+        this.dpid = dpid;
+        this.portType = portType;
+        this.ifaceid = ifaceid;
+    }
+
+    @Override
+    public MacAddress hwAddress() {
+        return mac;
+    }
+
+    @Override
+    public Set<IpAddress> ipAddress() {
+        return ips;
+    }
+
+    @Override
+    public OvsdbPortName portName() {
+        return portname;
+    }
+
+    @Override
+    public OvsdbPortNumber portNumber() {
+        return portnumber;
+    }
+
+    @Override
+    public OvsdbPortType portType() {
+        return portType;
+    }
+
+    @Override
+    public OvsdbDatapathId dpid() {
+        return dpid;
+    }
+
+    @Override
+    public OvsdbIfaceId ifaceid() {
+        return ifaceid;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mac, portname, portnumber, dpid, portType, ifaceid);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultEventSubject) {
+            final DefaultEventSubject other = (DefaultEventSubject) obj;
+            return Objects.equals(this.mac, other.mac)
+                    && Objects.equals(this.portname, other.portname)
+                    && Objects.equals(this.portnumber, other.portnumber)
+                    && Objects.equals(this.dpid, other.dpid)
+                    && Objects.equals(this.portType, other.portType)
+                    && Objects.equals(this.ifaceid, other.ifaceid);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("mac", mac).add("portname", portname)
+                .add("portnumber", portnumber).add("portType", portType)
+                .add("ipAddresses", ips).add("dpid", dpid).add("ifaceid", ifaceid)
+                .toString();
+    }
+}
diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java
new file mode 100644
index 0000000..263027f
--- /dev/null
+++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbEventSubject.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ovsdb.controller;
+
+import java.util.Set;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+
+/**
+ * Represents for a entity that carry important information for listener.
+ */
+public interface OvsdbEventSubject extends EventSubject {
+    /**
+     * Returns the MAC address associated with this host (NIC).
+     *
+     * @return the MAC address of this host
+     */
+    MacAddress hwAddress();
+
+    /**
+     * Returns the IP address associated with this host's MAC.
+     *
+     * @return host IP address
+     */
+    Set<IpAddress> ipAddress();
+
+    /**
+     * Returns the Port name associated with the host.
+     *
+     * @return port name
+     */
+    OvsdbPortName portName();
+
+    /**
+     * Returns the Port number associated with the host.
+     *
+     * @return port number
+     */
+    OvsdbPortNumber portNumber();
+
+    /**
+     * Returns the Port type associated with the host.
+     *
+     * @return port type
+     */
+    OvsdbPortType portType();
+
+    /**
+     * Returns the Ovs dpid associated with the host.
+     *
+     * @return Ovs dpid
+     */
+    OvsdbDatapathId dpid();
+
+    /**
+     * Returns the vm ifaceid associated with the host.
+     *
+     * @return vm ifaceid
+     */
+    OvsdbIfaceId ifaceid();
+}
diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java
new file mode 100644
index 0000000..b0535d2
--- /dev/null
+++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbIfaceId.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ovsdb.controller;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.util.Objects;
+
+/**
+ * The class representing a ifaceid. This class is immutable.
+ */
+public class OvsdbIfaceId {
+    private final String value;
+
+    /**
+     * Constructor from a String ifaceid.
+     *
+     * @param value the ifaceid to use
+     */
+    public OvsdbIfaceId(String value) {
+        checkNotNull(value, "value is not null");
+        this.value = value;
+    }
+
+    /**
+     * Gets the value of the ifaceid.
+     *
+     * @return the value of the ifaceid
+     */
+    public String value() {
+        return value;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(value);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof OvsdbIfaceId) {
+            final OvsdbIfaceId otherIfaceId = (OvsdbIfaceId) obj;
+            return Objects.equals(this.value, otherIfaceId.value);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("value", value).toString();
+    }
+}
diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortType.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortType.java
new file mode 100644
index 0000000..bf05fc7
--- /dev/null
+++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbPortType.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ovsdb.controller;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+/**
+ * The class representing a port type. This class is immutable.
+ */
+public class OvsdbPortType {
+
+    private final String value;
+
+    /**
+     * Constructor from a String port type.
+     *
+     * @param value the port type to use
+     */
+    public OvsdbPortType(String value) {
+        checkNotNull(value, "value is not null");
+        this.value = value;
+    }
+
+    /**
+     * Gets the value of the port type.
+     *
+     * @return the value of the port type
+     */
+    public String value() {
+        return value;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(value);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof OvsdbPortType) {
+            final OvsdbPortType otherOvsdbPortType = (OvsdbPortType) obj;
+            return Objects.equals(this.value, otherOvsdbPortType.value);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("value", value).toString();
+    }
+}
diff --git a/providers/ovsdb/host/pom.xml b/providers/ovsdb/host/pom.xml
new file mode 100644
index 0000000..d019025
--- /dev/null
+++ b/providers/ovsdb/host/pom.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<project
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+    xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-ovsdb-providers</artifactId>
+        <version>1.3.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-ovsdb-provider-host</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-ovsdb-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java b/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java
new file mode 100644
index 0000000..7aa63f6
--- /dev/null
+++ b/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/OvsdbHostProvider.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ovsdb.provider.host;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.toHex;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.host.DefaultHostDescription;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.ovsdb.controller.EventSubject;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbEvent;
+import org.onosproject.ovsdb.controller.OvsdbEventListener;
+import org.onosproject.ovsdb.controller.OvsdbEventSubject;
+import org.slf4j.Logger;
+
+/**
+ * Provider which uses an ovsdb controller to detect host.
+ */
+@Component(immediate = true)
+@Service
+public class OvsdbHostProvider extends AbstractProvider implements HostProvider {
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostProviderRegistry providerRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostService hostService;
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OvsdbController controller;
+
+    private HostProviderService providerService;
+    private OvsdbEventListener innerEventListener = new InnerOvsdbEventListener();
+
+    @Activate
+    public void activate() {
+        providerService = providerRegistry.register(this);
+        controller.addOvsdbEventListener(innerEventListener);
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        providerRegistry.unregister(this);
+        providerService = null;
+        log.info("Stopped");
+    }
+
+    public OvsdbHostProvider() {
+        super(new ProviderId("ovsdb", "org.onosproject.ovsdb.provider.host"));
+    }
+
+    @Override
+    public void triggerProbe(Host host) {
+        log.info("Triggering probe on host {}", host);
+    }
+
+    private class InnerOvsdbEventListener implements OvsdbEventListener {
+
+        @Override
+        public void handle(OvsdbEvent<EventSubject> event) {
+            OvsdbEventSubject subject = null;
+            if (event.subject() instanceof OvsdbEventSubject) {
+                subject = (OvsdbEventSubject) event.subject();
+            }
+            checkNotNull(subject, "EventSubject is not null");
+            // If ifaceid is null,it indicates this is not a vm port.
+            if (subject.ifaceid() == null) {
+                return;
+            }
+            switch (event.type()) {
+            case PORT_ADDED:
+                HostId hostId = HostId.hostId(subject.hwAddress(), null);
+                DeviceId deviceId = DeviceId.deviceId(uri(subject.dpid().value()));
+                PortNumber portNumber = PortNumber.portNumber(subject
+                        .portNumber().value(), subject.portName().value());
+                HostLocation loaction = new HostLocation(deviceId, portNumber,
+                                                         0L);
+                DefaultAnnotations annotations = DefaultAnnotations.builder()
+                        .set("ifaceid", subject.ifaceid().value()).build();
+                HostDescription hostDescription = new DefaultHostDescription(
+                                                                             subject.hwAddress(),
+                                                                             VlanId.vlanId(),
+                                                                             loaction,
+                                                                             annotations);
+                providerService.hostDetected(hostId, hostDescription);
+                break;
+            case PORT_REMOVED:
+                HostId host = HostId.hostId(subject.hwAddress(), null);
+                providerService.hostVanished(host);
+                break;
+            default:
+                break;
+            }
+
+        }
+
+    }
+
+    public URI uri(String value) {
+        try {
+            return new URI("of", toHex(Long.valueOf(value)), null);
+        } catch (URISyntaxException e) {
+            return null;
+        }
+    }
+}
diff --git a/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/package-info.java b/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/package-info.java
new file mode 100644
index 0000000..895ae2e
--- /dev/null
+++ b/providers/ovsdb/host/src/main/java/org/onosproject/ovsdb/provider/host/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ *Provider that uses ovsdb controller as a means of infrastructure host discovery.
+ *
+ */
+package org.onosproject.ovsdb.provider.host;
\ No newline at end of file
diff --git a/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java b/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java
new file mode 100644
index 0000000..bf18606
--- /dev/null
+++ b/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ovsdb.provider.host;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.ovsdb.controller.DefaultEventSubject;
+import org.onosproject.ovsdb.controller.EventSubject;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbDatapathId;
+import org.onosproject.ovsdb.controller.OvsdbEvent;
+import org.onosproject.ovsdb.controller.OvsdbEventListener;
+import org.onosproject.ovsdb.controller.OvsdbIfaceId;
+import org.onosproject.ovsdb.controller.OvsdbNodeId;
+import org.onosproject.ovsdb.controller.OvsdbNodeListener;
+import org.onosproject.ovsdb.controller.OvsdbPortName;
+import org.onosproject.ovsdb.controller.OvsdbPortNumber;
+import org.onosproject.ovsdb.controller.OvsdbPortType;
+
+/**
+ * Test for ovsdb host provider.
+ */
+public class OvsdbHostProviderTest {
+    private static final MacAddress MAC = MacAddress
+            .valueOf("00:00:11:00:00:01");
+    private final OvsdbHostProvider provider = new OvsdbHostProvider();
+    private final TestHostRegistry hostRegistry = new TestHostRegistry();
+    protected OvsdbControllerTest controller = new OvsdbControllerTest();
+    private TestHostProviderService providerService;
+
+    @Before
+    public void setUp() {
+        provider.providerRegistry = hostRegistry;
+        provider.controller = controller;
+        provider.activate();
+    }
+
+    @Test
+    public void basics() {
+        assertNotNull("registration expected", providerService);
+        assertEquals("incorrect provider", provider, providerService.provider());
+    }
+
+    @Test
+    public void portAdded() {
+        DefaultEventSubject eventSubject = new DefaultEventSubject(MAC, null,
+                                                                   new OvsdbPortName("portName"),
+                                                                   new OvsdbPortNumber(0L),
+                                                                   new OvsdbDatapathId("10002"),
+                                                                   new OvsdbPortType("vxlan"),
+                                                                   new OvsdbIfaceId("102345"));
+        controller.ovsdbEventListener
+                .handle(new OvsdbEvent<EventSubject>(
+                                                     OvsdbEvent.Type.PORT_ADDED,
+                                                     eventSubject));
+        assertNotNull("never went throught the provider service",
+                      providerService.added);
+
+    }
+
+    @Test
+    public void portRemoved() {
+        DefaultEventSubject eventSubject = new DefaultEventSubject(MAC, null,
+                                                                   new OvsdbPortName("portName"),
+                                                                   new OvsdbPortNumber(0L),
+                                                                   new OvsdbDatapathId("10002"),
+                                                                   new OvsdbPortType("vxlan"),
+                                                                   new OvsdbIfaceId("102345"));
+        controller.ovsdbEventListener
+                .handle(new OvsdbEvent<EventSubject>(
+                                                     OvsdbEvent.Type.PORT_REMOVED,
+                                                     eventSubject));
+        assertEquals("port status unhandled", 1, providerService.removeCount);
+    }
+
+    @After
+    public void tearDown() {
+        provider.deactivate();
+        provider.coreService = null;
+        provider.providerRegistry = null;
+    }
+
+    private class TestHostRegistry implements HostProviderRegistry {
+
+        @Override
+        public HostProviderService register(HostProvider provider) {
+            providerService = new TestHostProviderService(provider);
+            return providerService;
+        }
+
+        @Override
+        public void unregister(HostProvider provider) {
+        }
+
+        @Override
+        public Set<ProviderId> getProviders() {
+            return null;
+        }
+
+    }
+
+    private class TestHostProviderService
+            extends AbstractProviderService<HostProvider>
+            implements HostProviderService {
+
+        DeviceId added = null;
+        DeviceId moved = null;
+        DeviceId spine = null;
+        public int removeCount;
+
+        protected TestHostProviderService(HostProvider provider) {
+            super(provider);
+        }
+
+        @Override
+        public void hostDetected(HostId hostId, HostDescription hostDescription) {
+            DeviceId descr = hostDescription.location().deviceId();
+            if (added == null) {
+                added = descr;
+            } else if ((moved == null) && !descr.equals(added)) {
+                moved = descr;
+            } else {
+                spine = descr;
+            }
+        }
+
+        @Override
+        public void hostVanished(HostId hostId) {
+            removeCount++;
+        }
+
+    }
+
+    private class OvsdbControllerTest implements OvsdbController {
+        private OvsdbEventListener ovsdbEventListener = null;
+
+        @Override
+        public void addNodeListener(OvsdbNodeListener listener) {
+
+        }
+
+        @Override
+        public void removeNodeListener(OvsdbNodeListener listener) {
+
+        }
+
+        @Override
+        public void addOvsdbEventListener(OvsdbEventListener listener) {
+            ovsdbEventListener = listener;
+
+        }
+
+        @Override
+        public void removeOvsdbEventListener(OvsdbEventListener listener) {
+            ovsdbEventListener = null;
+
+        }
+
+        @Override
+        public List<OvsdbNodeId> getNodeIds() {
+            return null;
+        }
+
+        @Override
+        public OvsdbClientService getOvsdbClient(OvsdbNodeId nodeId) {
+            return null;
+        }
+    }
+}
diff --git a/providers/ovsdb/pom.xml b/providers/ovsdb/pom.xml
index 861344a..6359410 100644
--- a/providers/ovsdb/pom.xml
+++ b/providers/ovsdb/pom.xml
@@ -15,6 +15,7 @@
 
     <modules>
         <module>device</module>
+        <module>host</module>
     </modules>
 
     <dependencies>