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
This commit is contained in:
Pavlin Radoslavov 2015-01-09 11:59:07 -08:00 committed by Gerrit Code Review
parent c02c0b8546
commit d36a74b11d
8 changed files with 313 additions and 19 deletions

View File

@ -31,6 +31,8 @@ import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service; import org.apache.felix.scr.annotations.Service;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.ConnectPoint; import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device; import org.onosproject.net.Device;
import org.onosproject.net.Host; import org.onosproject.net.Host;
@ -41,7 +43,12 @@ import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService; 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.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.flow.TrafficTreatment;
import org.onosproject.net.host.HostService; import org.onosproject.net.host.HostService;
import org.onosproject.net.host.InterfaceIpAddress; import org.onosproject.net.host.InterfaceIpAddress;
@ -72,12 +79,20 @@ public class ProxyArpManager implements ProxyArpService {
private final Logger log = getLogger(getClass()); private final Logger log = getLogger(getClass());
private static final int FLOW_RULE_PRIORITY = 40000;
private static final String MAC_ADDR_NULL = "Mac address cannot be null."; private static final String MAC_ADDR_NULL = "Mac address cannot be null.";
private static final String REQUEST_NULL = "Arp request cannot be null."; private static final String REQUEST_NULL = "Arp request cannot be null.";
private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request."; private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request.";
private static final String NOT_ARP_REQUEST = "ARP is not a request."; private static final String NOT_ARP_REQUEST = "ARP is not a request.";
private static final String NOT_ARP_REPLY = "ARP is not a reply."; private static final String NOT_ARP_REPLY = "ARP is not a reply.";
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService; protected HostService hostService;
@ -96,15 +111,22 @@ public class ProxyArpManager implements ProxyArpService {
private final Multimap<Device, PortNumber> externalPorts = private final Multimap<Device, PortNumber> externalPorts =
HashMultimap.<Device, PortNumber>create(); HashMultimap.<Device, PortNumber>create();
private ApplicationId appId;
/** /**
* Listens to both device service and link service to determine * Listens to both device service and link service to determine
* whether a port is internal or external. * whether a port is internal or external.
*/ */
@Activate @Activate
public void activate() { public void activate() {
appId =
coreService.registerApplication("org.onosproject.net.proxyarp");
deviceService.addListener(new InternalDeviceListener()); deviceService.addListener(new InternalDeviceListener());
linkService.addListener(new InternalLinkListener()); linkService.addListener(new InternalLinkListener());
determinePortLocations(); determinePortLocations();
pushRules();
log.info("Started"); log.info("Started");
} }
@ -396,6 +418,36 @@ public class ProxyArpManager implements ProxyArpService {
return eth; return eth;
} }
/**
* 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);
}
public class InternalLinkListener implements LinkListener { public class InternalLinkListener implements LinkListener {
@Override @Override
@ -440,6 +492,8 @@ public class ProxyArpManager implements ProxyArpService {
Device device = event.subject(); Device device = event.subject();
switch (event.type()) { switch (event.type()) {
case DEVICE_ADDED: case DEVICE_ADDED:
pushRules(device);
break;
case DEVICE_AVAILABILITY_CHANGED: case DEVICE_AVAILABILITY_CHANGED:
case DEVICE_SUSPENDED: case DEVICE_SUSPENDED:
case DEVICE_UPDATED: case DEVICE_UPDATED:

View File

@ -18,6 +18,7 @@ package org.onosproject.net.proxyarp.impl;
import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -32,6 +33,9 @@ import java.util.Set;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.net.ConnectPoint; import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultHost; import org.onosproject.net.DefaultHost;
import org.onosproject.net.Device; import org.onosproject.net.Device;
@ -44,6 +48,8 @@ import org.onosproject.net.Port;
import org.onosproject.net.PortNumber; import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService; import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.host.HostService; import org.onosproject.net.host.HostService;
@ -97,9 +103,13 @@ public class ProxyArpManagerTest {
private TestPacketService packetService; private TestPacketService packetService;
private CoreService coreService;
private DeviceService deviceService; private DeviceService deviceService;
private FlowRuleService flowRuleService;
private LinkService linkService; private LinkService linkService;
private HostService hostService; private HostService hostService;
private ApplicationId appId = new DefaultApplicationId((short) 100,
"org.onosproject.net.proxyarp");
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@ -113,7 +123,9 @@ public class ProxyArpManagerTest {
proxyArp.hostService = hostService; proxyArp.hostService = hostService;
createTopology(); createTopology();
proxyArp.coreService = coreService;
proxyArp.deviceService = deviceService; proxyArp.deviceService = deviceService;
proxyArp.flowRuleService = flowRuleService;
proxyArp.linkService = linkService; proxyArp.linkService = linkService;
proxyArp.activate(); proxyArp.activate();
@ -130,6 +142,16 @@ public class ProxyArpManagerTest {
* addresses configured. * addresses configured.
*/ */
private void createTopology() { private void createTopology() {
coreService = createMock(CoreService.class);
expect(coreService.registerApplication(appId.name()))
.andReturn(appId).anyTimes();
replay(coreService);
flowRuleService = createMock(FlowRuleService.class);
flowRuleService.applyFlowRules(anyObject(FlowRule.class));
expectLastCall().anyTimes();
replay(flowRuleService);
deviceService = createMock(DeviceService.class); deviceService = createMock(DeviceService.class);
linkService = createMock(LinkService.class); linkService = createMock(LinkService.class);

View File

@ -52,6 +52,11 @@
<classifier>tests</classifier> <classifier>tests</classifier>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -22,14 +22,23 @@ import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality; 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.ConnectPoint;
import org.onosproject.net.DeviceId; import org.onosproject.net.Device;
import org.onosproject.net.Host; import org.onosproject.net.Host;
import org.onosproject.net.HostId; import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation; import org.onosproject.net.HostLocation;
import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService; 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.DefaultHostDescription;
import org.onosproject.net.host.HostDescription; import org.onosproject.net.host.HostDescription;
import org.onosproject.net.host.HostProvider; import org.onosproject.net.host.HostProvider;
@ -68,6 +77,14 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
private final Logger log = getLogger(getClass()); 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) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostProviderRegistry providerRegistry; protected HostProviderRegistry providerRegistry;
@ -88,6 +105,8 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
private final InternalHostProvider processor = new InternalHostProvider(); private final InternalHostProvider processor = new InternalHostProvider();
private final DeviceListener deviceListener = new InternalDeviceListener(); private final DeviceListener deviceListener = new InternalDeviceListener();
private ApplicationId appId;
@Property(name = "hostRemovalEnabled", boolValue = true, @Property(name = "hostRemovalEnabled", boolValue = true,
label = "Enable host removal on port/device down events") label = "Enable host removal on port/device down events")
private boolean hostRemovalEnabled = true; private boolean hostRemovalEnabled = true;
@ -102,10 +121,15 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
@Activate @Activate
public void activate(ComponentContext context) { public void activate(ComponentContext context) {
appId =
coreService.registerApplication("org.onosproject.provider.host");
modified(context); modified(context);
providerService = providerRegistry.register(this); providerService = providerRegistry.register(this);
pktService.addProcessor(processor, 1); pktService.addProcessor(processor, 1);
deviceService.addListener(deviceListener); deviceService.addListener(deviceListener);
pushRules();
log.info("Started"); log.info("Started");
} }
@ -137,6 +161,36 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
log.info("Triggering probe on device {}", host); 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 { private class InternalHostProvider implements PacketProcessor {
@Override @Override
@ -204,23 +258,40 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
private class InternalDeviceListener implements DeviceListener { private class InternalDeviceListener implements DeviceListener {
@Override @Override
public void event(DeviceEvent event) { public void event(DeviceEvent event) {
if (!hostRemovalEnabled) { Device device = event.subject();
return; switch (event.type()) {
case DEVICE_ADDED:
pushRules(device);
break;
case DEVICE_AVAILABILITY_CHANGED:
if (hostRemovalEnabled &&
!deviceService.isAvailable(device.id())) {
removeHosts(hostService.getConnectedHosts(device.id()));
} }
break;
DeviceEvent.Type type = event.type(); case DEVICE_SUSPENDED:
DeviceId deviceId = event.subject().id(); case DEVICE_UPDATED:
if (type == DeviceEvent.Type.PORT_UPDATED) { // Nothing to do?
ConnectPoint point = new ConnectPoint(deviceId, event.port().number()); 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)); removeHosts(hostService.getConnectedHosts(point));
} else if (type == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
if (!deviceService.isAvailable(deviceId)) {
removeHosts(hostService.getConnectedHosts(deviceId));
} }
break;
} else if (type == DeviceEvent.Type.DEVICE_REMOVED) { case PORT_REMOVED:
removeHosts(hostService.getConnectedHosts(deviceId)); // Nothing to do?
break;
default:
break;
} }
} }
} }

View File

@ -15,10 +15,19 @@
*/ */
package org.onosproject.provider.host.impl; package org.onosproject.provider.host.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.ImmutableSet; import com.google.common.collect.ImmutableSet;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.net.ConnectPoint; import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultDevice; import org.onosproject.net.DefaultDevice;
import org.onosproject.net.DefaultHost; import org.onosproject.net.DefaultHost;
@ -31,6 +40,8 @@ import org.onosproject.net.HostLocation;
import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceServiceAdapter; 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.flow.TrafficTreatment;
import org.onosproject.net.host.HostDescription; import org.onosproject.net.host.HostDescription;
import org.onosproject.net.host.HostProvider; import org.onosproject.net.host.HostProvider;
@ -56,6 +67,7 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId; import org.onlab.packet.VlanId;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Dictionary; import java.util.Dictionary;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Set; import java.util.Set;
@ -118,10 +130,29 @@ public class HostLocationProviderTest {
private final TestPacketService packetService = new TestPacketService(); private final TestPacketService packetService = new TestPacketService();
private PacketProcessor testProcessor; private PacketProcessor testProcessor;
private CoreService coreService;
private FlowRuleService flowRuleService;
private TestHostProviderService providerService; private TestHostProviderService providerService;
private ApplicationId appId = new DefaultApplicationId((short) 100,
"org.onosproject.provider.host");
@Before @Before
public void setUp() { 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));
expectLastCall().anyTimes();
replay(flowRuleService);
provider.coreService = coreService;
provider.flowRuleService = flowRuleService;
provider.providerRegistry = hostRegistry; provider.providerRegistry = hostRegistry;
provider.topologyService = topoService; provider.topologyService = topoService;
provider.pktService = packetService; provider.pktService = packetService;
@ -189,8 +220,9 @@ public class HostLocationProviderTest {
@After @After
public void tearDown() { public void tearDown() {
provider.deactivate(); provider.deactivate();
provider.coreService = null;
provider.flowRuleService = null;
provider.providerRegistry = null; provider.providerRegistry = null;
} }
private class TestHostRegistry implements HostProviderRegistry { private class TestHostRegistry implements HostProviderRegistry {
@ -339,6 +371,11 @@ public class HostLocationProviderTest {
public void addListener(DeviceListener listener) { public void addListener(DeviceListener listener) {
this.listener = listener; this.listener = listener;
} }
@Override
public Iterable<Device> getDevices() {
return Collections.emptyList();
}
} }
private class TestHostService extends HostServiceAdapter { private class TestHostService extends HostServiceAdapter {

View File

@ -44,5 +44,12 @@
<classifier>tests</classifier> <classifier>tests</classifier>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -22,6 +22,9 @@ import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality; 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.MastershipEvent;
import org.onosproject.mastership.MastershipListener; import org.onosproject.mastership.MastershipListener;
import org.onosproject.mastership.MastershipService; import org.onosproject.mastership.MastershipService;
@ -32,6 +35,13 @@ import org.onosproject.net.Port;
import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService; 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.LinkProvider;
import org.onosproject.net.link.LinkProviderRegistry; import org.onosproject.net.link.LinkProviderRegistry;
import org.onosproject.net.link.LinkProviderService; import org.onosproject.net.link.LinkProviderService;
@ -67,7 +77,6 @@ import static org.slf4j.LoggerFactory.getLogger;
@Component(immediate = true) @Component(immediate = true)
public class LLDPLinkProvider extends AbstractProvider implements LinkProvider { public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
private static final String PROP_USE_BDDP = "useBDDP"; private static final String PROP_USE_BDDP = "useBDDP";
private static final String PROP_LLDP_SUPPRESSION = "lldpSuppression"; private static final String PROP_LLDP_SUPPRESSION = "lldpSuppression";
@ -76,6 +85,14 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
private final Logger log = getLogger(getClass()); 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) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkProviderRegistry providerRegistry; protected LinkProviderRegistry providerRegistry;
@ -111,6 +128,7 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>(); protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
private SuppressionRules rules; private SuppressionRules rules;
private ApplicationId appId;
/** /**
* Creates an OpenFlow link provider. * Creates an OpenFlow link provider.
@ -121,6 +139,9 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
@Activate @Activate
public void activate() { public void activate() {
appId =
coreService.registerApplication("org.onosproject.provider.lldp");
loadSuppressionRules(); loadSuppressionRules();
providerService = providerRegistry.register(this); providerService = providerRegistry.register(this);
@ -153,6 +174,8 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
executor.scheduleAtFixedRate(new SyncDeviceInfoTask(), INIT_DELAY, executor.scheduleAtFixedRate(new SyncDeviceInfoTask(), INIT_DELAY,
DELAY, TimeUnit.SECONDS); DELAY, TimeUnit.SECONDS);
pushRules();
log.info("Started"); log.info("Started");
} }
@ -210,6 +233,48 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
// should refresh discoverers when we need dynamic reconfiguration // 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 { private class InternalRoleListener implements MastershipListener {
@Override @Override
@ -258,6 +323,8 @@ public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
final DeviceId deviceId = device.id(); final DeviceId deviceId = device.id();
switch (event.type()) { switch (event.type()) {
case DEVICE_ADDED: case DEVICE_ADDED:
pushRules(device);
// FALLTHROUGH
case DEVICE_UPDATED: case DEVICE_UPDATED:
synchronized (discoverers) { synchronized (discoverers) {
ld = discoverers.get(deviceId); ld = discoverers.get(deviceId);

View File

@ -15,6 +15,11 @@
*/ */
package org.onosproject.provider.lldp.impl; 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.ArrayListMultimap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@ -25,6 +30,9 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.onosproject.cluster.NodeId; import org.onosproject.cluster.NodeId;
import org.onosproject.cluster.RoleInfo; 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.MastershipListener;
import org.onosproject.mastership.MastershipService; import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint; import org.onosproject.net.ConnectPoint;
@ -38,6 +46,8 @@ import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceServiceAdapter; 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.flow.TrafficTreatment;
import org.onosproject.net.link.LinkDescription; import org.onosproject.net.link.LinkDescription;
import org.onosproject.net.link.LinkProvider; import org.onosproject.net.link.LinkProvider;
@ -80,14 +90,33 @@ public class LLDPLinkProviderTest {
private final TestDeviceService deviceService = new TestDeviceService(); private final TestDeviceService deviceService = new TestDeviceService();
private final TestMasterShipService masterService = new TestMasterShipService(); private final TestMasterShipService masterService = new TestMasterShipService();
private CoreService coreService;
private FlowRuleService flowRuleService;
private TestLinkProviderService providerService; private TestLinkProviderService providerService;
private PacketProcessor testProcessor; private PacketProcessor testProcessor;
private DeviceListener deviceListener; private DeviceListener deviceListener;
private ApplicationId appId = new DefaultApplicationId((short) 100,
"org.onosproject.provider.lldp");
@Before @Before
public void setUp() { 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.deviceService = deviceService;
provider.packetSevice = packetService; provider.packetSevice = packetService;
provider.providerRegistry = linkService; provider.providerRegistry = linkService;
@ -178,6 +207,8 @@ public class LLDPLinkProviderTest {
@After @After
public void tearDown() { public void tearDown() {
provider.deactivate(); provider.deactivate();
provider.coreService = null;
provider.flowRuleService = null;
provider.providerRegistry = null; provider.providerRegistry = null;
provider.deviceService = null; provider.deviceService = null;
provider.packetSevice = null; provider.packetSevice = null;