ONOS-5463 OFAgent - handle LLDP (based on OVX's handling of LLDP)
Change-Id: Ie1f78ba0e4f632b9566a007aa63fcc16d0976f4d
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchOperationService.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchOperationService.java
index ea71fa0..640c5d6 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchOperationService.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchOperationService.java
@@ -17,9 +17,11 @@
import io.netty.channel.Channel;
import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.packet.InboundPacket;
import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPacketOut;
/**
* Service for providing OpenFlow operations.
@@ -121,6 +123,14 @@
void processLldp(Channel channel, OFMessage msg);
/**
+ * Sends lldp response to the controller.
+ *
+ * @param ofPacketOut packet out message with lldp
+ * @param inPort in port to be used for packet in message
+ */
+ void sendLldpResponse(OFPacketOut ofPacketOut, PortNumber inPort);
+
+ /**
* Sends hello to the controller.
*
* @param channel received channel
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java
index 30f6d37..395f08e 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java
@@ -16,8 +16,10 @@
package org.onosproject.ofagent.api;
import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.device.PortStatistics;
import java.util.List;
@@ -70,4 +72,13 @@
*/
List<PortStatistics> getPortStatistics(NetworkId networkId, DeviceId deviceId);
+ /**
+ * Returns neighbour port of the specified port in the specified network.
+ *
+ * @param networkId network id
+ * @param deviceId device id
+ * @param portNumber port number
+ * @return connect point; null if none exists
+ */
+ ConnectPoint neighbour(NetworkId networkId, DeviceId deviceId, PortNumber portNumber);
}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java
index 8efcf1c..72a0c2f 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java
@@ -19,14 +19,17 @@
import io.netty.channel.Channel;
import org.onlab.osgi.ServiceDirectory;
import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.device.PortStatistics;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.PortNumber;
import org.onosproject.ofagent.api.OFSwitch;
import org.onosproject.ofagent.api.OFSwitchCapabilities;
import org.onosproject.ofagent.api.OFSwitchService;
+import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.OFBarrierReply;
import org.projectfloodlight.openflow.protocol.OFControllerRole;
import org.projectfloodlight.openflow.protocol.OFEchoReply;
@@ -38,6 +41,9 @@
import org.projectfloodlight.openflow.protocol.OFHello;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFPacketInReason;
+import org.projectfloodlight.openflow.protocol.OFPacketOut;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortReason;
import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
@@ -50,6 +56,10 @@
import org.projectfloodlight.openflow.protocol.OFStatsRequest;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.U64;
@@ -349,7 +359,46 @@
@Override
public void processLldp(Channel channel, OFMessage msg) {
- // TODO process lldp
+ log.trace("processLldp msg{}", msg);
+
+ // For each output port, look up neighbour port.
+ // If neighbour port exists, have the neighbour switch send lldp response.
+ // Modeled after how OpenVirtex handles lldp from external controller.
+ OFPacketOut ofPacketOut = (OFPacketOut) msg;
+ List<OFAction> actions = ofPacketOut.getActions();
+ for (final OFAction action : actions) {
+ OFActionType actionType = action.getType();
+ if (actionType.equals(OFActionType.OUTPUT)) {
+ OFActionOutput ofActionOutput = (OFActionOutput) action;
+ OFPort ofPort = ofActionOutput.getPort();
+ ConnectPoint neighbourCp =
+ ofSwitchService.neighbour(networkId, deviceId,
+ PortNumber.portNumber(ofPort.getPortNumber()));
+ if (neighbourCp == null) {
+ log.trace("No neighbour found for {} {}", deviceId, ofPort);
+ continue;
+ }
+ OFSwitch neighbourSwitch = ofSwitchService.ofSwitch(networkId,
+ neighbourCp.deviceId());
+ neighbourSwitch.sendLldpResponse(ofPacketOut, neighbourCp.port());
+ }
+ }
+ }
+
+ @Override
+ public void sendLldpResponse(OFPacketOut po, PortNumber inPort) {
+ Match.Builder matchB = FACTORY.buildMatch();
+ matchB.setExact(MatchField.IN_PORT, OFPort.of((int) inPort.toLong()));
+ OFPacketIn pi = FACTORY.buildPacketIn()
+ .setBufferId(po.getBufferId())
+ .setMatch(matchB.build())
+ .setReason(OFPacketInReason.NO_MATCH)
+ .setData(po.getData())
+ .build();
+ log.trace("Sending packet in {}", pi);
+ controllerChannels().forEach(channel -> {
+ channel.writeAndFlush(Collections.singletonList(pi));
+ });
}
@Override
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java
index cbf3569..aea97d1 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java
@@ -124,6 +124,10 @@
case ROLE_REQUEST:
handler.ofSwitch.processRoleRequest(handler.channel, msg);
break;
+ case PACKET_OUT:
+ // TODO: check if this is lldp - ignore if it is not lldp
+ handler.ofSwitch.processLldp(handler.channel, msg);
+ break;
case ERROR:
handler.logErrorClose((OFErrorMsg) msg);
break;
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
index 36be111..101e531 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
@@ -34,9 +34,12 @@
import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualPort;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
@@ -44,6 +47,7 @@
import org.onosproject.net.flow.FlowRuleEvent;
import org.onosproject.net.flow.FlowRuleListener;
import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.link.LinkService;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
@@ -181,6 +185,19 @@
return portStatistics;
}
+ @Override
+ public ConnectPoint neighbour(NetworkId networkId, DeviceId deviceId, PortNumber portNumber) {
+ ConnectPoint cp = new ConnectPoint(deviceId, portNumber);
+ LinkService linkService = virtualNetService.get(networkId, LinkService.class);
+ Set<Link> links = linkService.getEgressLinks(cp);
+ log.trace("neighbour cp {} egressLinks {}", cp, links);
+ if (links != null && links.size() > 0) {
+ Link link = links.iterator().next();
+ return link.src();
+ }
+ return null;
+ }
+
private void addOFSwitch(NetworkId networkId, DeviceId deviceId) {
OFSwitch ofSwitch = DefaultOFSwitch.of(
dpidWithDeviceId(deviceId),