Add explicit flow rules to receive control packets: ARP, LLDP, BDDP
This fixes ONOS-540
NOTES:
* Currently, the flow rules are pushed by each module that needs to receive
the corresponding control packets:
- ARP: ProxyArpManager, HostLocationProvider
- LLDP and BDDP: LLDPLinkProvider
* Pushing the corresponding IPv6 rules for Neighbor Discovery is not done yet
* In the future, we might want to consider an explicit service to
subscribe for receiving particular control packets
Change-Id: I292ad11a2e48390624f381c278e55e5d0af93c6d
diff --git a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
index ffe6c41..7c3d2ec 100644
--- a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
+++ b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
@@ -22,14 +22,23 @@
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
+import org.onosproject.net.Device;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostDescription;
import org.onosproject.net.host.HostProvider;
@@ -68,6 +77,14 @@
private final Logger log = getLogger(getClass());
+ private static final int FLOW_RULE_PRIORITY = 40000;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowRuleService flowRuleService;
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostProviderRegistry providerRegistry;
@@ -88,6 +105,8 @@
private final InternalHostProvider processor = new InternalHostProvider();
private final DeviceListener deviceListener = new InternalDeviceListener();
+ private ApplicationId appId;
+
@Property(name = "hostRemovalEnabled", boolValue = true,
label = "Enable host removal on port/device down events")
private boolean hostRemovalEnabled = true;
@@ -102,10 +121,15 @@
@Activate
public void activate(ComponentContext context) {
+ appId =
+ coreService.registerApplication("org.onosproject.provider.host");
+
modified(context);
providerService = providerRegistry.register(this);
pktService.addProcessor(processor, 1);
deviceService.addListener(deviceListener);
+ pushRules();
+
log.info("Started");
}
@@ -137,6 +161,36 @@
log.info("Triggering probe on device {}", host);
}
+ /**
+ * Pushes flow rules to all devices.
+ */
+ private void pushRules() {
+ for (Device device : deviceService.getDevices()) {
+ pushRules(device);
+ }
+ }
+
+ /**
+ * Pushes flow rules to the device to receive control packets that need
+ * to be processed.
+ *
+ * @param device the device to push the rules to
+ */
+ private synchronized void pushRules(Device device) {
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+
+ // Get all ARP packets
+ sbuilder.matchEthType(Ethernet.TYPE_ARP);
+ tbuilder.punt();
+ FlowRule flowArp =
+ new DefaultFlowRule(device.id(),
+ sbuilder.build(), tbuilder.build(),
+ FLOW_RULE_PRIORITY, appId, 0, true);
+
+ flowRuleService.applyFlowRules(flowArp);
+ }
+
private class InternalHostProvider implements PacketProcessor {
@Override
@@ -204,23 +258,40 @@
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
- if (!hostRemovalEnabled) {
- return;
- }
-
- DeviceEvent.Type type = event.type();
- DeviceId deviceId = event.subject().id();
- if (type == DeviceEvent.Type.PORT_UPDATED) {
- ConnectPoint point = new ConnectPoint(deviceId, event.port().number());
- removeHosts(hostService.getConnectedHosts(point));
-
- } else if (type == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
- if (!deviceService.isAvailable(deviceId)) {
- removeHosts(hostService.getConnectedHosts(deviceId));
+ Device device = event.subject();
+ switch (event.type()) {
+ case DEVICE_ADDED:
+ pushRules(device);
+ break;
+ case DEVICE_AVAILABILITY_CHANGED:
+ if (hostRemovalEnabled &&
+ !deviceService.isAvailable(device.id())) {
+ removeHosts(hostService.getConnectedHosts(device.id()));
}
-
- } else if (type == DeviceEvent.Type.DEVICE_REMOVED) {
- removeHosts(hostService.getConnectedHosts(deviceId));
+ break;
+ case DEVICE_SUSPENDED:
+ case DEVICE_UPDATED:
+ // Nothing to do?
+ break;
+ case DEVICE_REMOVED:
+ if (hostRemovalEnabled) {
+ removeHosts(hostService.getConnectedHosts(device.id()));
+ }
+ break;
+ case PORT_ADDED:
+ break;
+ case PORT_UPDATED:
+ if (hostRemovalEnabled) {
+ ConnectPoint point =
+ new ConnectPoint(device.id(), event.port().number());
+ removeHosts(hostService.getConnectedHosts(point));
+ }
+ break;
+ case PORT_REMOVED:
+ // Nothing to do?
+ break;
+ default:
+ break;
}
}
}