IPv6 Unsolicited RA application.
Change-Id: I7dac31918708d85247a7831fd38f83d2e8781183
diff --git a/apps/pom.xml b/apps/pom.xml
index a5dba52..8ed0f84 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -91,13 +91,14 @@
<module>yang</module>
<module>openroadm</module>
<module>netconf/client</module>
- <module>gluon</module>
+ <module>gluon</module>
<module>evpnopenflow</module>
<module>route-service</module>
<module>evpn-route-service</module>
<module>l3vpn</module>
<module>openstacknetworkingui</module>
<module>cfm</module>
+ <module>routeradvertisement</module>
</modules>
<properties>
diff --git a/apps/routeradvertisement/BUCK b/apps/routeradvertisement/BUCK
new file mode 100644
index 0000000..9673f0c
--- /dev/null
+++ b/apps/routeradvertisement/BUCK
@@ -0,0 +1,15 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+ '//incubator/api:onos-incubator-api'
+]
+
+osgi_jar (
+ deps = COMPILE_DEPS,
+)
+
+onos_app (
+ title = 'IPv6 RA Generator',
+ category = 'Traffic Steering',
+ url = 'http://onosproject.org',
+ description = 'Application for generating IPv6 RAs',
+)
diff --git a/apps/routeradvertisement/pom.xml b/apps/routeradvertisement/pom.xml
new file mode 100644
index 0000000..ecf6c38
--- /dev/null
+++ b/apps/routeradvertisement/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2015-present Open Networking Foundation
+ ~ Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ ~ Advisers: Keqiu Li and Heng Qi
+ ~ This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ ~ and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!--suppress MavenModelInspection -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-apps</artifactId>
+ <version>1.12.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>onos-app-routeradvertisement</artifactId>
+ <version>1.12.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <description>ONOS IPv6 RA application</description>
+ <url>http://onosproject.org</url>
+
+ <properties>
+ <onos.app.name>org.infosys.routeradvertisement</onos.app.name>
+ <onos.app.title>IPv6 RA Generator</onos.app.title>
+ <onos.app.category>Traffic Steering</onos.app.category>
+ <onos.app.url>http://onosproject.org</onos.app.url>
+ <onos.app.readme>Application for generating IPv6 RA</onos.app.readme>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-incubator-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-misc</artifactId>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/apps/routeradvertisement/src/main/java/org/onosproject/ra/RouterAdvertisementManager.java b/apps/routeradvertisement/src/main/java/org/onosproject/ra/RouterAdvertisementManager.java
new file mode 100644
index 0000000..cfefa84
--- /dev/null
+++ b/apps/routeradvertisement/src/main/java/org/onosproject/ra/RouterAdvertisementManager.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.ra;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+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.EthType;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.ndp.RouterAdvertisement;
+import org.onlab.packet.ndp.NeighborDiscoveryOptions;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.intf.Interface;
+import org.onosproject.net.intf.InterfaceEvent;
+import org.onosproject.net.intf.InterfaceListener;
+import org.onosproject.net.intf.InterfaceService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.InterfaceIpAddress;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.osgi.service.component.ComponentContext;
+
+import javax.annotation.concurrent.GuardedBy;
+import java.nio.ByteBuffer;
+import java.util.Dictionary;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Arrays;
+import java.util.Optional;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+import static org.onlab.util.Tools.groupedThreads;
+
+/**
+ * Manages IPv6 Router Advertisements.
+ */
+@Component(immediate = true)
+public class RouterAdvertisementManager {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final String PROP_RA_THREADS_POOL = "raPoolSize";
+ private static final int DEFAULT_RA_THREADS_POOL_SIZE = 10;
+ private static final String PROP_RA_THREADS_DELAY = "raThreadDelay";
+ private static final int DEFAULT_RA_THREADS_DELAY = 5;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ PacketService packetService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService componentConfigService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ public InterfaceService interfaceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ public MastershipService mastershipService;
+
+ @Property(name = PROP_RA_THREADS_POOL, intValue = DEFAULT_RA_THREADS_POOL_SIZE,
+ label = "Router Advertisement thread pool capacity")
+ protected int raPoolSize = DEFAULT_RA_THREADS_POOL_SIZE;
+
+ @Property(name = PROP_RA_THREADS_DELAY, intValue = DEFAULT_RA_THREADS_DELAY,
+ label = "Router Advertisement thread delay in seconds")
+ protected int raThreadDelay = DEFAULT_RA_THREADS_DELAY;
+
+ private ScheduledExecutorService executors = null;
+
+ @GuardedBy(value = "this")
+ private final Map<ConnectPoint, ScheduledFuture<?>> transmitters = new LinkedHashMap<>();
+
+ private static final String APP_NAME = "org.onosproject.routeradvertisement";
+ private ApplicationId appId;
+
+ // Listener for handling dynamic interface modifications.
+ private class InternalInterfaceListener implements InterfaceListener {
+ @Override
+ public void event(InterfaceEvent event) {
+ Interface i = event.subject();
+ switch (event.type()) {
+ case INTERFACE_ADDED:
+ if (mastershipService.getLocalRole(i.connectPoint().deviceId())
+ == MastershipRole.MASTER) {
+ activateRouterAdvertisement(i.connectPoint(),
+ i.ipAddressesList());
+ }
+ break;
+ case INTERFACE_REMOVED:
+ if (mastershipService.getLocalRole(i.connectPoint().deviceId())
+ == MastershipRole.MASTER) {
+ deactivateRouterAdvertisement(i.connectPoint(),
+ i.ipAddressesList());
+ }
+ break;
+ case INTERFACE_UPDATED:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ private final InterfaceListener interfaceListener = new InternalInterfaceListener();
+
+ // Enables RA threads on 'connectPoint' with configured IPv6s
+ private void activateRouterAdvertisement(ConnectPoint connectPoint, List<InterfaceIpAddress> addresses) {
+ synchronized (this) {
+ RAWorkerThread worker = new RAWorkerThread(connectPoint, addresses, raThreadDelay);
+ ScheduledFuture<?> handler = executors.scheduleAtFixedRate(worker, raThreadDelay,
+ raThreadDelay, TimeUnit.SECONDS);
+ transmitters.put(connectPoint, handler);
+ }
+
+ }
+
+ // Disables already activated RA threads on 'connectPoint'
+ private void deactivateRouterAdvertisement(ConnectPoint connectPoint, List<InterfaceIpAddress> addresses) {
+ synchronized (this) {
+ if (connectPoint != null) {
+ ScheduledFuture<?> handler = transmitters.get(connectPoint);
+ handler.cancel(false);
+ transmitters.remove(connectPoint);
+ }
+ }
+ }
+
+ @Activate
+ protected void activate(ComponentContext context) {
+ // Basic application registrations.
+ appId = coreService.registerApplication(APP_NAME);
+ componentConfigService.registerProperties(getClass());
+
+ // Loading configured properties.
+ if (context != null) {
+ Dictionary<?, ?> properties = context.getProperties();
+ try {
+ String s = get(properties, PROP_RA_THREADS_POOL);
+ raPoolSize = isNullOrEmpty(s) ?
+ DEFAULT_RA_THREADS_POOL_SIZE : Integer.parseInt(s.trim());
+
+ s = get(properties, PROP_RA_THREADS_DELAY);
+ raThreadDelay = isNullOrEmpty(s) ?
+ DEFAULT_RA_THREADS_DELAY : Integer.parseInt(s.trim());
+
+ } catch (NumberFormatException e) {
+ log.warn("Component configuration had invalid value, loading default values.", e);
+ }
+ }
+
+ // Interface listener for dynamic RA handling.
+ interfaceService.addListener(interfaceListener);
+
+ // Initialize RA thread pool
+ executors = Executors.newScheduledThreadPool(raPoolSize,
+ groupedThreads("RouterAdvertisement", "event-%d", log));
+
+ // Start Router Advertisement Transmission for all configured interfaces.
+ interfaceService.getInterfaces()
+ .stream()
+ .filter(i -> mastershipService.getLocalRole(i.connectPoint().deviceId())
+ == MastershipRole.MASTER)
+ .filter(i -> i.ipAddressesList()
+ .stream()
+ .anyMatch(ia -> ia.ipAddress().version().equals(IpAddress.Version.INET6)))
+ .forEach(j ->
+ activateRouterAdvertisement(j.connectPoint(), j.ipAddressesList())
+ );
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ // Unregister resources.
+ componentConfigService.unregisterProperties(getClass(), false);
+ interfaceService.removeListener(interfaceListener);
+
+ // Clear out Router Advertisement Transmission for all configured interfaces.
+ interfaceService.getInterfaces()
+ .stream()
+ .filter(i -> mastershipService.getLocalRole(i.connectPoint().deviceId())
+ == MastershipRole.MASTER)
+ .filter(i -> i.ipAddressesList()
+ .stream()
+ .anyMatch(ia -> ia.ipAddress().version().equals(IpAddress.Version.INET6)))
+ .forEach(j ->
+ deactivateRouterAdvertisement(j.connectPoint(), j.ipAddressesList())
+ );
+ }
+
+ // Worker thread for actually sending ICMPv6 RA packets.
+ private class RAWorkerThread implements Runnable {
+
+ ConnectPoint connectPoint;
+ List<InterfaceIpAddress> ipAddresses;
+ int retransmitPeriod;
+
+ // Various fixed values in RA packet
+ public static final byte RA_HOP_LIMIT = (byte) 0xff;
+ public static final short RA_ROUTER_LIFETIME = (short) 1800;
+ public static final int RA_OPTIONS_BUFFER_SIZE = 500;
+ public static final int RA_OPTION_MTU_VALUE = 1500;
+ public static final int RA_OPTION_PREFIX_VALID_LIFETIME = 600;
+ public static final int RA_OPTION_PREFIX_PREFERRED_LIFETIME = 600;
+ public static final int RA_RETRANSMIT_CALIBRATION_PERIOD = 1;
+
+
+ RAWorkerThread(ConnectPoint connectPoint, List<InterfaceIpAddress> ipAddresses, int period) {
+ this.connectPoint = connectPoint;
+ this.ipAddresses = ipAddresses;
+ retransmitPeriod = period;
+ }
+
+ public void run() {
+ // Router Advertisement header filling. Please refer RFC-2461.
+ RouterAdvertisement ra = new RouterAdvertisement();
+ ra.setCurrentHopLimit(RA_HOP_LIMIT);
+ ra.setMFlag((byte) 0x01);
+ ra.setOFlag((byte) 0x00);
+ ra.setRouterLifetime(RA_ROUTER_LIFETIME);
+ ra.setReachableTime(0);
+ ra.setRetransmitTimer(retransmitPeriod + RA_RETRANSMIT_CALIBRATION_PERIOD);
+
+ // Option : Source link-layer address.
+ byte[] optionBuffer = new byte[RA_OPTIONS_BUFFER_SIZE];
+ ByteBuffer option = ByteBuffer.wrap(optionBuffer);
+ Optional<MacAddress> macAddress = interfaceService.getInterfacesByPort(connectPoint).stream()
+ .map(Interface::mac).findFirst();
+ if (!macAddress.isPresent()) {
+ log.warn("Unable to retrieve interface {} MAC address. Terminating RA transmission.", connectPoint);
+ return;
+ }
+ option.put(macAddress.get().toBytes());
+ ra.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS,
+ Arrays.copyOfRange(option.array(), 0, option.position()));
+
+ // Option : MTU.
+ option.rewind();
+ option.putShort((short) 0);
+ option.putInt(RA_OPTION_MTU_VALUE);
+ ra.addOption(NeighborDiscoveryOptions.TYPE_MTU,
+ Arrays.copyOfRange(option.array(), 0, option.position()));
+
+ // Option : Prefix information.
+ ipAddresses.stream()
+ .filter(i -> i.ipAddress().version().equals(IpAddress.Version.INET6))
+ .forEach(i -> {
+ option.rewind();
+ option.put((byte) i.subnetAddress().prefixLength());
+ // Enable "onlink" option only.
+ option.put((byte) 0x80);
+ option.putInt(RA_OPTION_PREFIX_VALID_LIFETIME);
+ option.putInt(RA_OPTION_PREFIX_PREFERRED_LIFETIME);
+ // Clear reserved fields
+ option.putInt(0x00000000);
+ option.put(IpAddress.makeMaskedAddress(i.ipAddress(),
+ i.subnetAddress().prefixLength()).toOctets());
+ ra.addOption(NeighborDiscoveryOptions.TYPE_PREFIX_INFORMATION,
+ Arrays.copyOfRange(option.array(), 0, option.position()));
+
+ });
+
+ // ICMPv6 header filling.
+ ICMP6 icmpv6 = new ICMP6();
+ icmpv6.setIcmpType(ICMP6.ROUTER_ADVERTISEMENT);
+ icmpv6.setIcmpCode((byte) 0);
+ icmpv6.setPayload(ra);
+
+ // IPv6 header filling.
+ byte[] ip6AllNodesAddress = Ip6Address.valueOf("ff02::1").toOctets();
+ IPv6 ipv6 = new IPv6();
+ ipv6.setDestinationAddress(ip6AllNodesAddress);
+ /* RA packet L2 source address created from port MAC address.
+ * Note : As per RFC-4861 RAs should be sent from link-local address.
+ */
+ ipv6.setSourceAddress(IPv6.getLinkLocalAddress(macAddress.get().toBytes()));
+ ipv6.setNextHeader(IPv6.PROTOCOL_ICMP6);
+ ipv6.setHopLimit(RA_HOP_LIMIT);
+ ipv6.setTrafficClass((byte) 0xe0);
+ ipv6.setPayload(icmpv6);
+
+ // Ethernet header filling.
+ Ethernet ethernet = new Ethernet();
+
+ /* Ethernet IPv6 multicast address creation.
+ * Refer : RFC 2624 section 7.
+ */
+ byte[] l2Ipv6MulticastAddress = MacAddress.IPV6_MULTICAST.toBytes();
+ IntStream.range(1, 4).forEach(i -> l2Ipv6MulticastAddress[l2Ipv6MulticastAddress.length - i] =
+ ip6AllNodesAddress[ip6AllNodesAddress.length - i]);
+
+ ethernet.setDestinationMACAddress(MacAddress.valueOf(l2Ipv6MulticastAddress));
+ ethernet.setSourceMACAddress(macAddress.get().toBytes());
+ ethernet.setEtherType(EthType.EtherType.IPV6.ethType().toShort());
+ ethernet.setVlanID(Ethernet.VLAN_UNTAGGED);
+ ethernet.setPayload(ipv6);
+ ethernet.setPad(false);
+
+ // Flush out PACKET_OUT.
+ ByteBuffer stream = ByteBuffer.wrap(ethernet.serialize());
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
+ OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
+ treatment, stream);
+ packetService.emit(packet);
+ }
+ }
+}
diff --git a/apps/routeradvertisement/src/main/java/org/onosproject/ra/package-info.java b/apps/routeradvertisement/src/main/java/org/onosproject/ra/package-info.java
new file mode 100644
index 0000000..c99fd94
--- /dev/null
+++ b/apps/routeradvertisement/src/main/java/org/onosproject/ra/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * IPv6 Router Advertisement application.
+ */
+package org.onosproject.ra;
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index 23bbf07..4eec890 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -31,6 +31,7 @@
import org.onosproject.net.neighbour.NeighbourMessageType;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.intf.Interface;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.HostService;
@@ -204,21 +205,31 @@
IPv6 ipv6Packet = (IPv6) eth.getPayload();
Ip6Address destinationAddress = Ip6Address.valueOf(ipv6Packet.getDestinationAddress());
Set<IpAddress> gatewayIpAddresses = config.getPortIPs(deviceId);
+ MacAddress interfaceMac;
IpAddress routerIp;
+
try {
routerIp = config.getRouterIpv6(deviceId);
+ Optional<MacAddress> macAddress = srManager.interfaceService.getInterfacesByPort(inPort).stream()
+ .map(Interface::mac)
+ .findFirst();
+ if (!macAddress.isPresent()) {
+ log.warn("Failed in fetching MAC address of {}. Aborting ICMP6 processing.", inPort);
+ return;
+ }
+ interfaceMac = MacAddress.valueOf(macAddress.get().toBytes());
+
+ // Ensure ICMP to the router IP, gateway IP or link-local EUI-64
+ ICMP6 icmp6 = (ICMP6) ipv6Packet.getPayload();
+ if (icmp6.getIcmpType() == ICMP6.ECHO_REQUEST && (destinationAddress.equals(routerIp.getIp6Address()) ||
+ destinationAddress.equals(Ip6Address.valueOf(IPv6.getLinkLocalAddress(interfaceMac.toBytes()))) ||
+ gatewayIpAddresses.contains(destinationAddress))) {
+ sendIcmpv6Response(eth, inPort);
+ } else {
+ log.trace("Ignore ICMPv6 that targets for {}", destinationAddress);
+ }
} catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting processPacketIn.");
- return;
- }
- ICMP6 icmp6 = (ICMP6) ipv6Packet.getPayload();
- // ICMP to the router IP or gateway IP
- if (icmp6.getIcmpType() == ICMP6.ECHO_REQUEST &&
- (destinationAddress.equals(routerIp.getIp6Address()) ||
- gatewayIpAddresses.contains(destinationAddress))) {
- sendIcmpv6Response(eth, inPort);
- } else {
- log.trace("Ignore ICMPv6 that targets for {}", destinationAddress);
+ log.warn(e.getMessage() + " Ignore ICMPv6 that targets to {}.", destinationAddress);
}
}
@@ -256,11 +267,15 @@
}
}
- int sid = config.getIPv6SegmentId(destRouterAddress);
- if (sid < 0) {
- log.warn("Failed to lookup SID of the switch that {} attaches to. " +
- "Unable to process ICMPv6 request.", destIpAddress);
- return;
+ // Search SID only if store lookup is success otherwise proceed with "sid=-1"
+ int sid = -1;
+ if (destRouterAddress != null) {
+ sid = config.getIPv6SegmentId(destRouterAddress);
+ if (sid < 0) {
+ log.warn("Failed to lookup SID of the switch that {} attaches to. " +
+ "Unable to process ICMPv6 request.", destIpAddress);
+ return;
+ }
}
sendPacketOut(outport, ethReply, sid, destIpAddress, icmpReplyIpv6.getHopLimit());
}
@@ -301,16 +316,39 @@
/**
* Helper method to handle the ndp requests.
- *
* @param pkt the ndp packet request and context information
* @param hostService the host service
*/
private void handleNdpRequest(NeighbourMessageContext pkt, HostService hostService) {
// ND request for the gateway. We have to reply on behalf of the gateway.
if (isNdpForGateway(pkt)) {
- log.trace("Sending NDP reply on behalf of gateway IP for pkt: {}", pkt);
- sendResponse(pkt, config.getRouterMacForAGatewayIp(pkt.target()), hostService);
+ log.trace("Sending NDP reply on behalf of gateway IP for pkt: {}", pkt.target());
+ MacAddress routerMac = config.getRouterMacForAGatewayIp(pkt.target());
+ sendResponse(pkt, routerMac, hostService);
} else {
+
+ // Process NDP targets towards EUI-64 address.
+ try {
+ DeviceId deviceId = pkt.inPort().deviceId();
+ Optional<MacAddress> macAddress = srManager.interfaceService.getInterfacesByPort(pkt.inPort())
+ .stream()
+ .map(Interface::mac)
+ .findFirst();
+ if (!macAddress.isPresent()) {
+ log.warn("Failed in fetching MAC address of {}. Aborting NDP processing.", pkt.inPort());
+ return;
+ }
+ MacAddress interfaceMac = MacAddress.valueOf(macAddress.get().toBytes());
+ Ip6Address interfaceLinkLocalIP = Ip6Address.valueOf(IPv6.getLinkLocalAddress(interfaceMac.toBytes()));
+ if (pkt.target().equals(interfaceLinkLocalIP)) {
+ MacAddress routerMac = config.getDeviceMac(deviceId);
+ sendResponse(pkt, routerMac, hostService);
+ }
+ } catch (DeviceConfigNotFoundException e) {
+ log.warn(e.getMessage() + " Unable to handle NDP packet to {}. Aborting.", pkt.target());
+ return;
+ }
+
// NOTE: Ignore NDP packets except those target for the router
// We will reconsider enabling this when we have host learning support
/*
@@ -376,6 +414,7 @@
private boolean isNdpForGateway(NeighbourMessageContext pkt) {
DeviceId deviceId = pkt.inPort().deviceId();
Set<IpAddress> gatewayIpAddresses = null;
+
try {
if (pkt.target().equals(config.getRouterIpv6(deviceId))) {
return true;
@@ -383,14 +422,13 @@
gatewayIpAddresses = config.getPortIPs(deviceId);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting check for router IP in processing ndp");
+ return false;
}
-
return gatewayIpAddresses != null && gatewayIpAddresses.stream()
.filter(IpAddress::isIp6)
.anyMatch(gatewayIp -> gatewayIp.equals(pkt.target()) ||
Arrays.equals(IPv6.getSolicitNodeAddress(gatewayIp.toOctets()),
- pkt.target().toOctets())
- );
+ pkt.target().toOctets()));
}
/**
diff --git a/modules.defs b/modules.defs
index 389e91f..ffd756a 100644
--- a/modules.defs
+++ b/modules.defs
@@ -224,6 +224,7 @@
'//apps/p4-tutorial/pipeconf:onos-apps-p4-tutorial-pipeconf-oar',
'//apps/p4-tutorial/icmpdropper:onos-apps-p4-tutorial-icmpdropper-oar',
'//apps/cfm:onos-apps-cfm-oar',
+ '//apps/routeradvertisement:onos-apps-routeradvertisement-oar',
]
PROTOCOL_APPS = [