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/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
index 0fe9676..0169e02 100644
--- a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
+++ b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
@@ -22,6 +22,9 @@
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
import org.onosproject.mastership.MastershipEvent;
import org.onosproject.mastership.MastershipListener;
import org.onosproject.mastership.MastershipService;
@@ -32,6 +35,13 @@
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.link.LinkProvider;
import org.onosproject.net.link.LinkProviderRegistry;
import org.onosproject.net.link.LinkProviderService;
@@ -67,7 +77,6 @@
@Component(immediate = true)
public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
-
private static final String PROP_USE_BDDP = "useBDDP";
private static final String PROP_LLDP_SUPPRESSION = "lldpSuppression";
@@ -76,6 +85,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 LinkProviderRegistry providerRegistry;
@@ -111,6 +128,7 @@
protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
private SuppressionRules rules;
+ private ApplicationId appId;
/**
* Creates an OpenFlow link provider.
@@ -121,6 +139,9 @@
@Activate
public void activate() {
+ appId =
+ coreService.registerApplication("org.onosproject.provider.lldp");
+
loadSuppressionRules();
providerService = providerRegistry.register(this);
@@ -153,6 +174,8 @@
executor.scheduleAtFixedRate(new SyncDeviceInfoTask(), INIT_DELAY,
DELAY, TimeUnit.SECONDS);
+ pushRules();
+
log.info("Started");
}
@@ -210,6 +233,48 @@
// should refresh discoverers when we need dynamic reconfiguration
}
+ /**
+ * 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;
+ TrafficTreatment.Builder tbuilder;
+
+ // Get all LLDP packets
+ sbuilder = DefaultTrafficSelector.builder();
+ tbuilder = DefaultTrafficTreatment.builder();
+ sbuilder.matchEthType(Ethernet.TYPE_LLDP);
+ tbuilder.punt();
+ FlowRule flowLldp =
+ new DefaultFlowRule(device.id(),
+ sbuilder.build(), tbuilder.build(),
+ FLOW_RULE_PRIORITY, appId, 0, true);
+
+ // Get all BDDP packets
+ sbuilder = DefaultTrafficSelector.builder();
+ tbuilder = DefaultTrafficTreatment.builder();
+ sbuilder.matchEthType(Ethernet.TYPE_BSN);
+ tbuilder.punt();
+ FlowRule flowBddp =
+ new DefaultFlowRule(device.id(),
+ sbuilder.build(), tbuilder.build(),
+ FLOW_RULE_PRIORITY, appId, 0, true);
+
+ flowRuleService.applyFlowRules(flowLldp, flowBddp);
+ }
+
private class InternalRoleListener implements MastershipListener {
@Override
@@ -258,6 +323,8 @@
final DeviceId deviceId = device.id();
switch (event.type()) {
case DEVICE_ADDED:
+ pushRules(device);
+ // FALLTHROUGH
case DEVICE_UPDATED:
synchronized (discoverers) {
ld = discoverers.get(deviceId);
diff --git a/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java b/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java
index b37ee00..6da1716 100644
--- a/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java
+++ b/providers/lldp/src/test/java/org/onosproject/provider/lldp/impl/LLDPLinkProviderTest.java
@@ -15,6 +15,11 @@
*/
package org.onosproject.provider.lldp.impl;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
@@ -25,6 +30,9 @@
import org.junit.Test;
import org.onosproject.cluster.NodeId;
import org.onosproject.cluster.RoleInfo;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultApplicationId;
import org.onosproject.mastership.MastershipListener;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint;
@@ -38,6 +46,8 @@
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.link.LinkDescription;
import org.onosproject.net.link.LinkProvider;
@@ -80,14 +90,33 @@
private final TestDeviceService deviceService = new TestDeviceService();
private final TestMasterShipService masterService = new TestMasterShipService();
+ private CoreService coreService;
+ private FlowRuleService flowRuleService;
private TestLinkProviderService providerService;
private PacketProcessor testProcessor;
private DeviceListener deviceListener;
+ private ApplicationId appId = new DefaultApplicationId((short) 100,
+ "org.onosproject.provider.lldp");
+
@Before
public void setUp() {
+ coreService = createMock(CoreService.class);
+ expect(coreService.registerApplication(appId.name()))
+ .andReturn(appId).anyTimes();
+ replay(coreService);
+
+ flowRuleService = createMock(FlowRuleService.class);
+ flowRuleService.applyFlowRules(anyObject(FlowRule.class),
+ anyObject(FlowRule.class));
+ expectLastCall().anyTimes();
+ replay(flowRuleService);
+
+ provider.coreService = coreService;
+ provider.flowRuleService = flowRuleService;
+
provider.deviceService = deviceService;
provider.packetSevice = packetService;
provider.providerRegistry = linkService;
@@ -178,6 +207,8 @@
@After
public void tearDown() {
provider.deactivate();
+ provider.coreService = null;
+ provider.flowRuleService = null;
provider.providerRegistry = null;
provider.deviceService = null;
provider.packetSevice = null;