[CORD-631] ICMPv6 Echo support
Changes:
- ICMPv6 Echo support;
- Introduces SegmentRoutingNeighbourHandler;
- Simplifies ArpHandler;
- Simplifies IcmpHandler;
Change-Id: I93f04d94ff15f43ca83f96cbab3da5064c215f9c
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
index 5ea5694..ae32bfc 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
@@ -16,51 +16,180 @@
package org.onosproject.segmentrouting;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
-import org.onosproject.incubator.net.neighbour.NeighbourMessageHandler;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.HostService;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
+import org.onosproject.segmentrouting.config.DeviceConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.nio.ByteBuffer;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
- * This handler deals with the ICMPv6 Echo protocol
- * and ICMPv6 ND protocol.
+ * This handler provides provides useful functions to the
+ * neighbour handlers (ARP, NDP).
*/
-public class SegmentRoutingNeighbourHandler implements NeighbourMessageHandler {
+public class SegmentRoutingNeighbourHandler {
private static Logger log = LoggerFactory.getLogger(SegmentRoutingNeighbourHandler.class);
- private SegmentRoutingManager manager;
+
+ protected SegmentRoutingManager srManager;
+ protected DeviceConfiguration config;
/**
- * Create a segment routing neighbour handler.
+ * Creates an SegmentRoutingNeighbourHandler object.
*
- * @param segmentRoutingManager the segment routing manager
+ * @param srManager SegmentRoutingManager object
*/
- public SegmentRoutingNeighbourHandler(SegmentRoutingManager segmentRoutingManager) {
- this.manager = segmentRoutingManager;
+ public SegmentRoutingNeighbourHandler(SegmentRoutingManager srManager) {
+ this.srManager = srManager;
+ this.config = checkNotNull(srManager.deviceConfiguration);
}
- /*
- * We use this method to handle the NDP messages
+ /**
+ * Creates an SegmentRoutingNeighbourHandler object.
*/
- @Override
- public void handleMessage(NeighbourMessageContext context, HostService hostService) {
- log.debug("Received a {} packet {}", context.protocol(), context.packet());
- switch (context.protocol()) {
- case ARP:
- if (this.manager.arpHandler != null) {
- this.manager.arpHandler.processPacketIn(context, hostService);
+ public SegmentRoutingNeighbourHandler() {
+ this.srManager = null;
+ this.config = null;
+ }
+
+ /**
+ * Retrieve router (device) info.
+ *
+ * @param mac where to copy the mac
+ * @param ip where to copy the ip
+ * @param deviceId the device id
+ * @param targetAddress the target address
+ */
+ protected void getSenderInfo(byte[] mac,
+ byte[] ip,
+ DeviceId deviceId,
+ IpAddress targetAddress) {
+ byte[] senderMacAddress;
+ byte[] senderIpAddress;
+ try {
+ senderMacAddress = config.getDeviceMac(deviceId).toBytes();
+ senderIpAddress = config.getRouterIpAddressForASubnetHost(targetAddress.getIp4Address())
+ .toOctets();
+ } catch (DeviceConfigNotFoundException e) {
+ log.warn(e.getMessage() + " Aborting sendArpRequest.");
+ return;
+ }
+ /*
+ * FIXME understand how to manage IPv4/IPv6 together.
+ */
+ System.arraycopy(senderMacAddress, 0, mac, 0, senderMacAddress.length);
+ System.arraycopy(senderIpAddress, 0, ip, 0, senderIpAddress.length);
+ }
+
+ /**
+ * Utility to send a ND reply using the supplied information.
+ *
+ * @param pkt the request
+ * @param targetMac the target mac
+ * @param hostService the host service
+ */
+ protected void sendResponse(NeighbourMessageContext pkt, MacAddress targetMac, HostService hostService) {
+ HostId dstId = HostId.hostId(pkt.srcMac(), pkt.vlan());
+ Host dst = hostService.getHost(dstId);
+ if (dst == null) {
+ log.warn("Cannot send {} response to host {} - does not exist in the store",
+ pkt.protocol(), dstId);
+ return;
+ }
+ pkt.reply(targetMac);
+ }
+
+ /**
+ * Flood to all ports in the same subnet.
+ *
+ * @param packet packet to be flooded
+ * @param inPort where the packet comes from
+ * @param targetAddress the target address
+ */
+ protected void flood(Ethernet packet, ConnectPoint inPort, IpAddress targetAddress) {
+ try {
+ srManager.deviceConfiguration
+ .getSubnetPortsMap(inPort.deviceId()).forEach((subnet, ports) -> {
+ if (subnet.contains(targetAddress)) {
+ ports.stream()
+ .filter(port -> port != inPort.port())
+ .forEach(port -> {
+ forward(packet, new ConnectPoint(inPort.deviceId(), port));
+ });
}
- break;
- case NDP:
- if (this.manager.icmpHandler != null) {
- this.manager.icmpHandler.processPacketIn(context, hostService);
- }
- break;
- default:
- log.warn("Unknown protocol", context.protocol());
+ });
+ } catch (DeviceConfigNotFoundException e) {
+ log.warn(e.getMessage()
+ + " Cannot flood in subnet as device config not available"
+ + " for device: " + inPort.deviceId());
}
}
+ /*
+ * Floods only on the port which have been configured with the subnet
+ * of the target address. The in port is excluded.
+ *
+ * @param pkt the ndp/arp packet and context information
+ */
+ protected void flood(NeighbourMessageContext pkt) {
+ try {
+ srManager.deviceConfiguration
+ .getSubnetPortsMap(pkt.inPort().deviceId()).forEach((subnet, ports) -> {
+ if (subnet.contains(pkt.target())) {
+ ports.stream()
+ .filter(port -> port != pkt.inPort().port())
+ .forEach(port -> {
+ ConnectPoint outPoint = new ConnectPoint(
+ pkt.inPort().deviceId(),
+ port
+ );
+ pkt.forward(outPoint);
+ });
+ }
+ });
+ } catch (DeviceConfigNotFoundException e) {
+ log.warn(e.getMessage()
+ + " Cannot flood in subnet as device config not available"
+ + " for device: " + pkt.inPort().deviceId());
+ }
+ }
+
+ /**
+ * Packet out to given port.
+ *
+ * Note: In current implementation, we expect all communication with
+ * end hosts within a subnet to be untagged.
+ * <p>
+ * For those pipelines that internally assigns a VLAN, the VLAN tag will be
+ * removed before egress.
+ * <p>
+ * For those pipelines that do not assign internal VLAN, the packet remains
+ * untagged.
+ *
+ * @param packet packet to be forwarded
+ * @param outPort where the packet should be forwarded
+ */
+ private void forward(Ethernet packet, ConnectPoint outPort) {
+ ByteBuffer buf = ByteBuffer.wrap(packet.serialize());
+
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+ tbuilder.setOutput(outPort.port());
+ srManager.packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
+ tbuilder.build(), buf));
+ }
}