IPv6 support for vRouter
Changes:
- Adds support to CPRM;
- Updates DHM;
- Fixes SingleSwitchFibInstaller;
- Updates the driver;
- IPv6 unit tests;
Change-Id: I0d9a143fbf5ee8d77ffe3ed3e180fede200d3cdd
diff --git a/apps/routing/src/main/java/org/onosproject/routing/impl/ControlPlaneRedirectManager.java b/apps/routing/src/main/java/org/onosproject/routing/impl/ControlPlaneRedirectManager.java
index 5cd78a9..9a16bfd 100644
--- a/apps/routing/src/main/java/org/onosproject/routing/impl/ControlPlaneRedirectManager.java
+++ b/apps/routing/src/main/java/org/onosproject/routing/impl/ControlPlaneRedirectManager.java
@@ -17,6 +17,7 @@
package org.onosproject.routing.impl;
import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@@ -24,9 +25,17 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.EthType;
+import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+
+import static org.onlab.packet.Ethernet.TYPE_ARP;
+import static org.onlab.packet.Ethernet.TYPE_IPV4;
+import static org.onlab.packet.Ethernet.TYPE_IPV6;
+import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
+import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
+import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
import org.onosproject.app.ApplicationService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
@@ -85,7 +94,7 @@
private static final int MIN_IP_PRIORITY = 10;
private static final int IPV4_PRIORITY = 2000;
private static final int IPV6_PRIORITY = 500;
- private static final int ACL_PRIORITY = 40001;
+ static final int ACL_PRIORITY = 40001;
private static final int OSPF_IP_PROTO = 0x59;
private static final String APP_NAME = "org.onosproject.vrouter";
@@ -228,59 +237,180 @@
intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
intf.vlan(), false, install);
}
-
- // IPv4 to router
- TrafficSelector toSelector = DefaultTrafficSelector.builder()
- .matchInPort(intf.connectPoint().port())
- .matchEthDst(intf.mac())
- .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
- .matchVlanId(intf.vlan())
- .matchIPDst(ip.ipAddress().toIpPrefix())
- .build();
-
- flowObjectiveService.forward(deviceId,
- buildForwardingObjective(toSelector, null, cpNextId, install));
-
- // IPv4 from router
- TrafficSelector fromSelector = DefaultTrafficSelector.builder()
- .matchInPort(controlPlanePort)
- .matchEthSrc(intf.mac())
- .matchVlanId(intf.vlan())
- .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
- .matchIPSrc(ip.ipAddress().toIpPrefix())
- .build();
-
- flowObjectiveService.forward(deviceId,
- buildForwardingObjective(fromSelector, null, intfNextId, install));
-
- // ARP to router
- toSelector = DefaultTrafficSelector.builder()
- .matchInPort(intf.connectPoint().port())
- .matchEthType(EthType.EtherType.ARP.ethType().toShort())
- .matchVlanId(intf.vlan())
- .build();
-
- TrafficTreatment puntTreatment = DefaultTrafficTreatment.builder()
+ List<ForwardingObjective> fwdToSend = Lists.newArrayList();
+ TrafficSelector selector;
+ // IP traffic toward the router.
+ selector = buildIPDstSelector(
+ ip.ipAddress().toIpPrefix(),
+ intf.connectPoint().port(),
+ null,
+ intf.mac(),
+ intf.vlan()
+ );
+ fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
+ // IP traffic from the router.
+ selector = buildIPSrcSelector(
+ ip.ipAddress().toIpPrefix(),
+ controlPlanePort,
+ intf.mac(),
+ null,
+ intf.vlan()
+ );
+ fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
+ // We build the punt treatment.
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.punt()
.build();
-
- flowObjectiveService.forward(deviceId,
- buildForwardingObjective(toSelector, puntTreatment, cpNextId, install));
-
- // ARP from router
- fromSelector = DefaultTrafficSelector.builder()
- .matchInPort(controlPlanePort)
- .matchEthSrc(intf.mac())
- .matchVlanId(intf.vlan())
- .matchEthType(EthType.EtherType.ARP.ethType().toShort())
- .matchArpSpa(ip.ipAddress().getIp4Address())
- .build();
-
- flowObjectiveService.forward(deviceId,
- buildForwardingObjective(fromSelector, puntTreatment, intfNextId, install));
+ // Handling of neighbour discovery protocols.
+ // IPv4 traffic - we have to deal with the ARP protocol.
+ // IPv6 traffic - we have to deal with the NDP protocol.
+ if (ip.ipAddress().isIp4()) {
+ // ARP traffic towards the router.
+ selector = buildArpSelector(
+ intf.connectPoint().port(),
+ intf.vlan(),
+ null,
+ null
+ );
+ fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
+ // ARP traffic from the router.
+ selector = buildArpSelector(
+ controlPlanePort,
+ intf.vlan(),
+ ip.ipAddress().getIp4Address(),
+ intf.mac()
+ );
+ fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
+ } else {
+ // Neighbour solicitation traffic towards the router.
+ selector = buildNdpSelector(
+ intf.connectPoint().port(),
+ intf.vlan(),
+ null,
+ NEIGHBOR_SOLICITATION,
+ null
+ );
+ fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
+ // Neighbour solicitation traffic from the router.
+ selector = buildNdpSelector(
+ controlPlanePort,
+ intf.vlan(),
+ ip.ipAddress().toIpPrefix(),
+ NEIGHBOR_SOLICITATION,
+ intf.mac()
+ );
+ fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
+ // Neighbour advertisement traffic towards the router.
+ selector = buildNdpSelector(
+ intf.connectPoint().port(),
+ intf.vlan(),
+ null,
+ NEIGHBOR_ADVERTISEMENT,
+ null
+ );
+ fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
+ // Neighbour advertisement traffic from the router.
+ selector = buildNdpSelector(
+ controlPlanePort,
+ intf.vlan(),
+ ip.ipAddress().toIpPrefix(),
+ NEIGHBOR_ADVERTISEMENT,
+ intf.mac()
+ );
+ fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
+ }
+ // Finally we push the fwd objectives through the flow objective service.
+ fwdToSend.stream().forEach(forwardingObjective ->
+ flowObjectiveService.forward(deviceId, forwardingObjective)
+ );
}
}
+ static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
+ MacAddress srcMac,
+ MacAddress dstMac,
+ VlanId vlanId) {
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+ if (inPort != null) {
+ selectorBuilder.matchInPort(inPort);
+ }
+ if (srcMac != null) {
+ selectorBuilder.matchEthSrc(srcMac);
+ }
+ if (dstMac != null) {
+ selectorBuilder.matchEthDst(dstMac);
+ }
+ if (vlanId != null) {
+ selectorBuilder.matchVlanId(vlanId);
+ }
+ return selectorBuilder;
+ }
+
+ static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
+ PortNumber inPort,
+ MacAddress srcMac,
+ MacAddress dstMac,
+ VlanId vlanId) {
+ TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
+ if (dstIp.isIp4()) {
+ selector.matchEthType(TYPE_IPV4);
+ selector.matchIPDst(dstIp);
+ } else {
+ selector.matchEthType(TYPE_IPV6);
+ selector.matchIPv6Dst(dstIp);
+ }
+ return selector.build();
+ }
+
+ static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
+ PortNumber inPort,
+ MacAddress srcMac,
+ MacAddress dstMac,
+ VlanId vlanId) {
+ TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
+ if (srcIp.isIp4()) {
+ selector.matchEthType(TYPE_IPV4);
+ selector.matchIPSrc(srcIp);
+ } else {
+ selector.matchEthType(TYPE_IPV6);
+ selector.matchIPv6Src(srcIp);
+ }
+ return selector.build();
+ }
+
+ static TrafficSelector buildArpSelector(PortNumber inPort,
+ VlanId vlanId,
+ Ip4Address arpSpa,
+ MacAddress srcMac) {
+ TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
+ selector.matchEthType(TYPE_ARP);
+ if (arpSpa != null) {
+ selector.matchArpSpa(arpSpa);
+ }
+ if (srcMac != null) {
+ selector.matchEthSrc(srcMac);
+ }
+ return selector.build();
+ }
+
+ static TrafficSelector buildNdpSelector(PortNumber inPort,
+ VlanId vlanId,
+ IpPrefix srcIp,
+ byte subProto,
+ MacAddress srcMac) {
+ TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
+ selector.matchEthType(TYPE_IPV6)
+ .matchIPProtocol(PROTOCOL_ICMP6)
+ .matchIcmpv6Type(subProto);
+ if (srcIp != null) {
+ selector.matchIPv6Src(srcIp);
+ }
+ if (srcMac != null) {
+ selector.matchEthSrc(srcMac);
+ }
+ return selector.build();
+ }
+
/**
* Installs or removes OSPF forwarding rules.
*
@@ -289,6 +419,7 @@
* objective
**/
private void updateOspfForwarding(Interface intf, boolean install) {
+ // FIXME IPv6 support has not been implemented yet
// OSPF to router
TrafficSelector toSelector = DefaultTrafficSelector.builder()
.matchInPort(intf.connectPoint().port())
@@ -311,7 +442,7 @@
}
log.debug("OSPF flows intf:{} nextid:{}", intf, cpNextId);
flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(),
- buildForwardingObjective(toSelector, null, cpNextId, install ? ospfEnabled : install));
+ buildForwardingObjective(toSelector, null, cpNextId, install ? ospfEnabled : install, ACL_PRIORITY));
}
/**
@@ -370,7 +501,8 @@
private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
TrafficTreatment treatment,
int nextId,
- boolean add) {
+ boolean add,
+ int priority) {
DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
fobBuilder.withSelector(selector);
if (treatment != null) {
@@ -380,7 +512,7 @@
fobBuilder.nextStep(nextId);
}
fobBuilder.fromApp(appId)
- .withPriority(ACL_PRIORITY)
+ .withPriority(priority)
.withFlag(ForwardingObjective.Flag.VERSATILE);
return add ? fobBuilder.add() : fobBuilder.remove();
@@ -425,22 +557,22 @@
public void event(NetworkConfigEvent event) {
if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
switch (event.type()) {
- case CONFIG_ADDED:
- case CONFIG_UPDATED:
- readConfig();
- if (event.prevConfig().isPresent()) {
+ case CONFIG_ADDED:
+ case CONFIG_UPDATED:
+ readConfig();
+ if (event.prevConfig().isPresent()) {
updateConfig(event);
}
- break;
- case CONFIG_REGISTERED:
- case CONFIG_UNREGISTERED:
- case CONFIG_REMOVED:
- removeConfig();
+ break;
+ case CONFIG_REGISTERED:
+ case CONFIG_UNREGISTERED:
+ case CONFIG_REMOVED:
+ removeConfig();
break;
- default:
- break;
+ default:
+ break;
}
}
}
@@ -520,12 +652,10 @@
private ForwardingObjective.Builder createPeerObjBuilder(
int nextId, IpPrefix ipAddresses) {
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
- sbuilder.matchIPDst(ipAddresses);
+ TrafficSelector selector = buildIPDstSelector(ipAddresses, null, null, null, null);
DefaultForwardingObjective.Builder builder =
DefaultForwardingObjective.builder()
- .withSelector(sbuilder.build())
+ .withSelector(selector)
.fromApp(appId)
.withPriority(getPriorityFromPrefix(ipAddresses))
.withFlag(ForwardingObjective.Flag.SPECIFIC);
@@ -577,7 +707,8 @@
peerRemoved(event);
break;
case HOST_UPDATED:
- //TODO We assume BGP peer does not change IP for now
+ //FIXME We assume BGP peer does not change IP for now
+ // but we can discover new address.
break;
default:
break;
@@ -628,11 +759,10 @@
}
private Set<Interface> filterInterfaces(List<String> interfaces) {
- Set<Interface> intfs = interfaceService.getInterfaces().stream()
+ return interfaceService.getInterfaces().stream()
.filter(intf -> intf.connectPoint().deviceId().equals(controlPlaneConnectPoint.deviceId()))
.filter(intf -> interfaces.contains(intf.name()))
.collect(Collectors.toSet());
- return intfs;
}
private void removeConfig() {
@@ -707,3 +837,4 @@
}
}
}
+
diff --git a/apps/routing/src/main/java/org/onosproject/routing/impl/DirectHostManager.java b/apps/routing/src/main/java/org/onosproject/routing/impl/DirectHostManager.java
index d5c0d27..a1a7d25 100644
--- a/apps/routing/src/main/java/org/onosproject/routing/impl/DirectHostManager.java
+++ b/apps/routing/src/main/java/org/onosproject/routing/impl/DirectHostManager.java
@@ -28,7 +28,8 @@
import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
-import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.IP;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
@@ -63,6 +64,7 @@
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.packet.IpAddress.Version.INET6;
/**
* Reactively handles sending packets to hosts that are directly connected to
@@ -104,8 +106,8 @@
private InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
private InternalHostListener hostListener = new InternalHostListener();
- private Cache<IpAddress, Queue<IPv4>> ipPacketCache = CacheBuilder.newBuilder()
- .weigher((IpAddress key, Queue<IPv4> value) -> value.size())
+ private Cache<IpAddress, Queue<IP>> ipPacketCache = CacheBuilder.newBuilder()
+ .weigher((IpAddress key, Queue<IP> value) -> value.size())
.maximumWeight(MAX_QUEUED_PACKETS)
.expireAfterAccess(MAX_QUEUE_DURATION, TimeUnit.SECONDS)
.build();
@@ -134,19 +136,27 @@
private void enable() {
hostService.addListener(hostListener);
packetService.addProcessor(packetProcessor, PacketProcessor.director(3));
-
+ // Requests packets for IPv4 traffic.
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(EthType.EtherType.IPV4.ethType().toShort()).build();
packetService.requestPackets(selector, PacketPriority.REACTIVE, appId, Optional.empty());
+ // Requests packets for IPv6 traffic.
+ selector = DefaultTrafficSelector.builder()
+ .matchEthType(EthType.EtherType.IPV6.ethType().toShort()).build();
+ packetService.requestPackets(selector, PacketPriority.REACTIVE, appId, Optional.empty());
}
private void disable() {
packetService.removeProcessor(packetProcessor);
hostService.removeListener(hostListener);
-
+ // Withdraws IPv4 request.
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(EthType.EtherType.IPV4.ethType().toShort()).build();
packetService.cancelPackets(selector, PacketPriority.REACTIVE, appId, Optional.empty());
+ // Withdraws IPv6 request.
+ selector = DefaultTrafficSelector.builder()
+ .matchEthType(EthType.EtherType.IPV6.ethType().toShort()).build();
+ packetService.cancelPackets(selector, PacketPriority.REACTIVE, appId, Optional.empty());
}
@Deactivate
@@ -158,57 +168,82 @@
componentConfigService.unregisterProperties(getClass(), false);
}
- private void handle(Ethernet eth) {
+ private boolean handle(Ethernet eth) {
checkNotNull(eth);
-
- if (!(eth.getEtherType() == EthType.EtherType.IPV4.ethType().toShort())) {
- return;
+ // If the DirectHostManager is not enabled and the
+ // packets are different from what we expect just
+ // skip them.
+ if (!enabled || (eth.getEtherType() != Ethernet.TYPE_IPV6
+ && eth.getEtherType() != Ethernet.TYPE_IPV4)) {
+ return false;
}
-
- IPv4 ipv4 = (IPv4) eth.getPayload().clone();
-
- Ip4Address dstIp = Ip4Address.valueOf(ipv4.getDestinationAddress());
-
+ // According to the type we set the destIp.
+ IpAddress dstIp;
+ if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
+ IPv4 ip = (IPv4) eth.getPayload();
+ dstIp = IpAddress.valueOf(ip.getDestinationAddress());
+ } else {
+ IPv6 ip = (IPv6) eth.getPayload();
+ dstIp = IpAddress.valueOf(INET6, ip.getDestinationAddress());
+ }
+ // Looking for a candidate output port.
Interface egressInterface = interfaceService.getMatchingInterface(dstIp);
if (egressInterface == null) {
log.info("No egress interface found for {}", dstIp);
- return;
+ return false;
}
-
+ // Looking for the destination mac.
Optional<Host> host = hostService.getHostsByIp(dstIp).stream()
.filter(h -> h.location().equals(egressInterface.connectPoint()))
.filter(h -> h.vlan().equals(egressInterface.vlan()))
.findAny();
-
+ // If we don't have a destination we start the monitoring
+ // and we queue the packets waiting for a destination.
if (host.isPresent()) {
- transformAndSend(ipv4, egressInterface, host.get().mac());
+ transformAndSend(
+ (IP) eth.getPayload(),
+ eth.getEtherType(),
+ egressInterface,
+ host.get().mac()
+ );
} else {
hostService.startMonitoringIp(dstIp);
ipPacketCache.asMap().compute(dstIp, (ip, queue) -> {
if (queue == null) {
- queue = new ConcurrentLinkedQueue();
+ queue = new ConcurrentLinkedQueue<>();
}
- queue.add(ipv4);
+ queue.add((IP) eth.getPayload());
return queue;
});
}
+
+ return true;
}
- private void transformAndSend(IPv4 ipv4, Interface egressInterface, MacAddress macAddress) {
-
+ private void transformAndSend(IP ip, short ethType,
+ Interface egressInterface,
+ MacAddress macAddress) {
+ // Base processing for IPv4
+ if (ethType == Ethernet.TYPE_IPV4) {
+ IPv4 ipv4 = (IPv4) ip;
+ ipv4.setTtl((byte) (ipv4.getTtl() - 1));
+ ipv4.setChecksum((short) 0);
+ // Base processing for IPv6.
+ } else {
+ IPv6 ipv6 = (IPv6) ip;
+ ipv6.setHopLimit((byte) (ipv6.getHopLimit() - 1));
+ ipv6.resetChecksum();
+ }
+ // Sends and serializes.
Ethernet eth = new Ethernet();
eth.setDestinationMACAddress(macAddress);
eth.setSourceMACAddress(egressInterface.mac());
- eth.setEtherType(EthType.EtherType.IPV4.ethType().toShort());
- eth.setPayload(ipv4);
+ eth.setEtherType(ethType);
+ eth.setPayload(ip);
if (!egressInterface.vlan().equals(VlanId.NONE)) {
eth.setVlanID(egressInterface.vlan().toShort());
}
-
- ipv4.setTtl((byte) (ipv4.getTtl() - 1));
- ipv4.setChecksum((short) 0);
-
send(eth, egressInterface.connectPoint());
}
@@ -221,7 +256,7 @@
private void sendQueued(IpAddress ipAddress, MacAddress macAddress) {
log.debug("Sending queued packets for {} ({})", ipAddress, macAddress);
ipPacketCache.asMap().computeIfPresent(ipAddress, (ip, packets) -> {
- packets.forEach(ipv4 -> {
+ packets.forEach(ipPackets -> {
Interface egressInterface = interfaceService.getMatchingInterface(ipAddress);
if (egressInterface == null) {
@@ -229,7 +264,14 @@
return;
}
- transformAndSend(ipv4, egressInterface, macAddress);
+ // According to the type of the address we set proper
+ // protocol.
+ transformAndSend(
+ ipPackets,
+ ipAddress.isIp4() ? Ethernet.TYPE_IPV4 : Ethernet.TYPE_IPV6,
+ egressInterface,
+ macAddress
+ );
});
return null;
});
@@ -253,7 +295,9 @@
return;
}
- handle(eth);
+ if (!handle(eth)) {
+ return;
+ }
context.block();
}
diff --git a/apps/routing/src/main/java/org/onosproject/routing/impl/SingleSwitchFibInstaller.java b/apps/routing/src/main/java/org/onosproject/routing/impl/SingleSwitchFibInstaller.java
index f0fe3fe..24dd468 100644
--- a/apps/routing/src/main/java/org/onosproject/routing/impl/SingleSwitchFibInstaller.java
+++ b/apps/routing/src/main/java/org/onosproject/routing/impl/SingleSwitchFibInstaller.java
@@ -126,7 +126,7 @@
protected ApplicationService applicationService;
@Property(name = "routeToNextHop", boolValue = false,
- label = "Install a /32 route to each next hop")
+ label = "Install a /32 or /128 route to each next hop")
private boolean routeToNextHop = false;
// Device id of data-plane switch - should be learned from config
@@ -333,11 +333,7 @@
private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
Integer nextId) {
- TrafficSelector selector = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(prefix)
- .build();
-
+ TrafficSelector selector = buildIpSelectorFromIpPrefix(prefix).build();
int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
@@ -357,11 +353,30 @@
return fwdBuilder;
}
+ /**
+ * Method to build IPv4 or IPv6 selector.
+ *
+ * @param prefixToMatch the prefix to match
+ * @return the traffic selector builder
+ */
+ private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+ // If the prefix is IPv4
+ if (prefixToMatch.isIp4()) {
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
+ selectorBuilder.matchIPDst(prefixToMatch);
+ return selectorBuilder;
+ }
+ // If the prefix is IPv6
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
+ selectorBuilder.matchIPv6Dst(prefixToMatch);
+ return selectorBuilder;
+ }
+
private synchronized void addNextHop(ResolvedRoute route) {
prefixToNextHop.put(route.prefix(), route.nextHop());
if (nextHopsCount.count(route.nextHop()) == 0) {
// There was no next hop in the multiset
-
Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
if (egressIntf == null) {
log.warn("no egress interface found for {}", route);
diff --git a/apps/routing/src/test/java/org/onosproject/routing/impl/ControlPlaneRedirectManagerTest.java b/apps/routing/src/test/java/org/onosproject/routing/impl/ControlPlaneRedirectManagerTest.java
index 08e89e7..5d07541 100644
--- a/apps/routing/src/test/java/org/onosproject/routing/impl/ControlPlaneRedirectManagerTest.java
+++ b/apps/routing/src/test/java/org/onosproject/routing/impl/ControlPlaneRedirectManagerTest.java
@@ -76,6 +76,9 @@
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
+import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
+import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
+import static org.onosproject.routing.impl.ControlPlaneRedirectManager.*;
/**
* UnitTests for ControlPlaneRedirectManager.
@@ -149,11 +152,15 @@
@Test
public void testAddDevice() {
ConnectPoint sw1eth4 = new ConnectPoint(DEVICE_ID, PortNumber.portNumber(4));
- List<InterfaceIpAddress> interfaceIpAddresses4 = new ArrayList<>();
- interfaceIpAddresses4
- .add(new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24")));
+ List<InterfaceIpAddress> interfaceIpAddresses = new ArrayList<>();
+ interfaceIpAddresses.add(
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24"))
+ );
+ interfaceIpAddresses.add(
+ new InterfaceIpAddress(IpAddress.valueOf("2000::ff"), IpPrefix.valueOf("2000::ff/120"))
+ );
- Interface sw1Eth4 = new Interface(sw1eth4.deviceId().toString(), sw1eth4, interfaceIpAddresses4,
+ Interface sw1Eth4 = new Interface(sw1eth4.deviceId().toString(), sw1eth4, interfaceIpAddresses,
MacAddress.valueOf("00:00:00:00:00:04"), VlanId.NONE);
interfaces.add(sw1Eth4);
EasyMock.reset(flowObjectiveService);
@@ -168,11 +175,15 @@
@Test
public void testUpdateNetworkConfig() {
ConnectPoint sw1eth4 = new ConnectPoint(DEVICE_ID, PortNumber.portNumber(4));
- List<InterfaceIpAddress> interfaceIpAddresses4 = new ArrayList<>();
- interfaceIpAddresses4
- .add(new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24")));
+ List<InterfaceIpAddress> interfaceIpAddresses = new ArrayList<>();
+ interfaceIpAddresses.add(
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24"))
+ );
+ interfaceIpAddresses.add(
+ new InterfaceIpAddress(IpAddress.valueOf("2000::ff"), IpPrefix.valueOf("2000::ff/120"))
+ );
- Interface sw1Eth4 = new Interface(sw1eth4.deviceId().toString(), sw1eth4, interfaceIpAddresses4,
+ Interface sw1Eth4 = new Interface(sw1eth4.deviceId().toString(), sw1eth4, interfaceIpAddresses,
MacAddress.valueOf("00:00:00:00:00:04"), VlanId.NONE);
interfaces.add(sw1Eth4);
EasyMock.reset(flowObjectiveService);
@@ -189,11 +200,15 @@
@Test
public void testAddInterface() {
ConnectPoint sw1eth4 = new ConnectPoint(DEVICE_ID, PortNumber.portNumber(4));
- List<InterfaceIpAddress> interfaceIpAddresses4 = new ArrayList<>();
- interfaceIpAddresses4
- .add(new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24")));
+ List<InterfaceIpAddress> interfaceIpAddresses = new ArrayList<>();
+ interfaceIpAddresses.add(
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24"))
+ );
+ interfaceIpAddresses.add(
+ new InterfaceIpAddress(IpAddress.valueOf("2000::ff"), IpPrefix.valueOf("2000::ff/120"))
+ );
- Interface sw1Eth4 = new Interface(sw1eth4.deviceId().toString(), sw1eth4, interfaceIpAddresses4,
+ Interface sw1Eth4 = new Interface(sw1eth4.deviceId().toString(), sw1eth4, interfaceIpAddresses,
MacAddress.valueOf("00:00:00:00:00:04"), VlanId.NONE);
interfaces.add(sw1Eth4);
@@ -209,11 +224,15 @@
@Test
public void testRemoveInterface() {
ConnectPoint sw1eth4 = new ConnectPoint(DEVICE_ID, PortNumber.portNumber(4));
- List<InterfaceIpAddress> interfaceIpAddresses4 = new ArrayList<>();
- interfaceIpAddresses4
- .add(new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24")));
+ List<InterfaceIpAddress> interfaceIpAddresses = new ArrayList<>();
+ interfaceIpAddresses.add(
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), IpPrefix.valueOf("192.168.40.0/24"))
+ );
+ interfaceIpAddresses.add(
+ new InterfaceIpAddress(IpAddress.valueOf("2000::ff"), IpPrefix.valueOf("2000::ff/120"))
+ );
- Interface sw1Eth4 = new Interface(sw1eth4.deviceId().toString(), sw1eth4, interfaceIpAddresses4,
+ Interface sw1Eth4 = new Interface(sw1eth4.deviceId().toString(), sw1eth4, interfaceIpAddresses,
MacAddress.valueOf("00:00:00:00:00:04"), VlanId.NONE);
EasyMock.reset(flowObjectiveService);
expect(flowObjectiveService.allocateNextId()).andReturn(1).anyTimes();
@@ -251,38 +270,110 @@
intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN), true, install);
- // IPv4 to router
- TrafficSelector toSelector = DefaultTrafficSelector.builder().matchInPort(intf.connectPoint().port())
- .matchEthDst(intf.mac()).matchEthType(EthType.EtherType.IPV4.ethType().toShort())
- .matchVlanId(intf.vlan()).matchIPDst(ip.ipAddress().toIpPrefix()).build();
+ // IP to router
+ TrafficSelector toSelector = buildIPDstSelector(
+ ip.ipAddress().toIpPrefix(),
+ intf.connectPoint().port(),
+ null,
+ intf.mac(),
+ intf.vlan());
- flowObjectiveService.forward(deviceId, buildForwardingObjective(toSelector, null, cpNextId, install));
+ flowObjectiveService.forward(deviceId, buildForwardingObjective(toSelector, null,
+ cpNextId, install, ACL_PRIORITY));
expectLastCall().once();
- // IPv4 from router
- TrafficSelector fromSelector = DefaultTrafficSelector.builder().matchInPort(controlPlanePort)
- .matchEthSrc(intf.mac()).matchVlanId(intf.vlan())
- .matchEthType(EthType.EtherType.IPV4.ethType().toShort()).matchIPSrc(ip.ipAddress().toIpPrefix())
- .build();
- flowObjectiveService.forward(deviceId, buildForwardingObjective(fromSelector, null, intfNextId, install));
+ // IP from router
+ TrafficSelector fromSelector = buildIPSrcSelector(
+ ip.ipAddress().toIpPrefix(),
+ controlPlanePort,
+ intf.mac(),
+ null,
+ intf.vlan()
+ );
+
+ flowObjectiveService.forward(deviceId, buildForwardingObjective(fromSelector, null,
+ intfNextId, install, ACL_PRIORITY));
expectLastCall().once();
- // ARP to router
- toSelector = DefaultTrafficSelector.builder().matchInPort(intf.connectPoint().port())
- .matchEthType(EthType.EtherType.ARP.ethType().toShort()).matchVlanId(intf.vlan()).build();
TrafficTreatment puntTreatment = DefaultTrafficTreatment.builder().punt().build();
+ if (ip.ipAddress().isIp4()) {
+ // ARP to router
+ toSelector = buildArpSelector(
+ intf.connectPoint().port(),
+ intf.vlan(),
+ null,
+ null
+ );
- flowObjectiveService.forward(deviceId,
- buildForwardingObjective(toSelector, puntTreatment, cpNextId, install));
- expectLastCall().once();
- // ARP from router
- fromSelector = DefaultTrafficSelector.builder().matchInPort(controlPlanePort).matchEthSrc(intf.mac())
- .matchVlanId(intf.vlan()).matchEthType(EthType.EtherType.ARP.ethType().toShort())
- .matchArpSpa(ip.ipAddress().getIp4Address()).build();
+ flowObjectiveService.forward(deviceId, buildForwardingObjective(toSelector, puntTreatment,
+ cpNextId, install, ACL_PRIORITY + 1));
+ expectLastCall().once();
- flowObjectiveService.forward(deviceId,
- buildForwardingObjective(fromSelector, puntTreatment, intfNextId, install));
- expectLastCall().once();
+ // ARP from router
+ fromSelector = buildArpSelector(
+ controlPlanePort,
+ intf.vlan(),
+ ip.ipAddress().getIp4Address(),
+ intf.mac()
+ );
+
+ flowObjectiveService.forward(deviceId,
+ buildForwardingObjective(fromSelector, puntTreatment,
+ intfNextId, install, ACL_PRIORITY + 1));
+ expectLastCall().once();
+ } else {
+ // NDP solicitation to router
+ toSelector = buildNdpSelector(
+ intf.connectPoint().port(),
+ intf.vlan(),
+ null,
+ NEIGHBOR_SOLICITATION,
+ null
+ );
+
+ flowObjectiveService.forward(deviceId, buildForwardingObjective(toSelector, puntTreatment,
+ cpNextId, install, ACL_PRIORITY + 1));
+ expectLastCall().once();
+
+ // NDP solicitation from router
+ fromSelector = buildNdpSelector(
+ controlPlanePort,
+ intf.vlan(),
+ ip.ipAddress().toIpPrefix(),
+ NEIGHBOR_SOLICITATION,
+ intf.mac()
+ );
+
+ flowObjectiveService.forward(deviceId,
+ buildForwardingObjective(fromSelector, puntTreatment,
+ intfNextId, install, ACL_PRIORITY + 1));
+
+ // NDP advertisement to router
+ toSelector = buildNdpSelector(
+ intf.connectPoint().port(),
+ intf.vlan(),
+ null,
+ NEIGHBOR_ADVERTISEMENT,
+ null
+ );
+
+ flowObjectiveService.forward(deviceId, buildForwardingObjective(toSelector, puntTreatment,
+ cpNextId, install, ACL_PRIORITY + 1));
+ expectLastCall().once();
+
+ // NDP advertisement from router
+ fromSelector = buildNdpSelector(
+ controlPlanePort,
+ intf.vlan(),
+ ip.ipAddress().toIpPrefix(),
+ NEIGHBOR_ADVERTISEMENT,
+ intf.mac()
+ );
+
+ flowObjectiveService.forward(deviceId,
+ buildForwardingObjective(fromSelector, puntTreatment,
+ intfNextId, install, ACL_PRIORITY + 1));
+ }
}
// setting expectations for ospf forwarding.
TrafficSelector toSelector = DefaultTrafficSelector.builder().matchInPort(intf.connectPoint().port())
@@ -291,7 +382,7 @@
modifyNextObjective(deviceId, controlPlanePort, VlanId.vlanId((short) 4094), true, install);
flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(),
- buildForwardingObjective(toSelector, null, 1, install));
+ buildForwardingObjective(toSelector, null, 1, install, 40001));
expectLastCall().once();
}
@@ -353,7 +444,7 @@
}
private ForwardingObjective buildForwardingObjective(TrafficSelector selector, TrafficTreatment treatment,
- int nextId, boolean add) {
+ int nextId, boolean add, int priority) {
DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
fobBuilder.withSelector(selector);
if (treatment != null) {
@@ -362,7 +453,7 @@
if (nextId != -1) {
fobBuilder.nextStep(nextId);
}
- fobBuilder.fromApp(APPID).withPriority(40001).withFlag(ForwardingObjective.Flag.VERSATILE);
+ fobBuilder.fromApp(APPID).withPriority(priority).withFlag(ForwardingObjective.Flag.VERSATILE);
return add ? fobBuilder.add() : fobBuilder.remove();
}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
index 66d0b53..ac9c38a 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
@@ -43,6 +43,8 @@
import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.IPProtocolCriterion;
+import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
@@ -62,6 +64,10 @@
import java.util.List;
import java.util.Objects;
+import static org.onlab.packet.Ethernet.TYPE_IPV4;
+import static org.onlab.packet.ICMP6.ECHO_REPLY;
+import static org.onlab.packet.ICMP6.ECHO_REQUEST;
+import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
import static org.onlab.util.Tools.delay;
import static org.slf4j.LoggerFactory.getLogger;
@@ -158,25 +164,25 @@
@Override
public void next(NextObjective nextObjective) {
switch (nextObjective.type()) {
- case SIMPLE:
- Collection<TrafficTreatment> treatments = nextObjective.next();
- if (treatments.size() != 1) {
- log.error("Next Objectives of type Simple should only have a "
- + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id());
- fail(nextObjective, ObjectiveError.BADPARAMS);
- return;
- }
- processSimpleNextObjective(nextObjective);
- break;
- case HASHED:
- case BROADCAST:
- case FAILOVER:
- fail(nextObjective, ObjectiveError.UNSUPPORTED);
- log.warn("Unsupported next objective type {}", nextObjective.type());
- break;
- default:
- fail(nextObjective, ObjectiveError.UNKNOWN);
- log.warn("Unknown next objective type {}", nextObjective.type());
+ case SIMPLE:
+ Collection<TrafficTreatment> treatments = nextObjective.next();
+ if (treatments.size() != 1) {
+ log.error("Next Objectives of type Simple should only have a "
+ + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id());
+ fail(nextObjective, ObjectiveError.BADPARAMS);
+ return;
+ }
+ processSimpleNextObjective(nextObjective);
+ break;
+ case HASHED:
+ case BROADCAST:
+ case FAILOVER:
+ fail(nextObjective, ObjectiveError.UNSUPPORTED);
+ log.warn("Unsupported next objective type {}", nextObjective.type());
+ break;
+ default:
+ fail(nextObjective, ObjectiveError.UNKNOWN);
+ log.warn("Unknown next objective type {}", nextObjective.type());
}
}
@@ -243,7 +249,7 @@
p = (PortCriterion) filt.key();
} else {
log.warn("No key defined in filtering objective from app: {}. Not"
- + "processing filtering objective", applicationId);
+ + "processing filtering objective", applicationId);
fail(filt, ObjectiveError.UNKNOWN);
return;
}
@@ -261,6 +267,7 @@
fail(filt, ObjectiveError.UNSUPPORTED);
return;
}
+
}
log.debug("Modifying Port/VLAN/MAC filtering rules in filter table: {}/{}/{}",
@@ -276,7 +283,7 @@
selector.matchEthDst(e.mac());
}
selector.matchVlanId(v.vlanId());
- selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchEthType(TYPE_IPV4);
if (!v.vlanId().equals(VlanId.NONE)) {
treatment.popVlan();
}
@@ -291,6 +298,29 @@
.forTable(FILTER_TABLE).build();
ops = install ? ops.add(rule) : ops.remove(rule);
+ // FIXME IPv6 in the multicast use case.
+ // Filtering rules for IPv6.
+ if (e.mask() == null) {
+ selector = DefaultTrafficSelector.builder();
+ selector.matchInPort(p.port());
+ selector.matchEthDst(e.mac());
+ selector.matchVlanId(v.vlanId());
+ selector.matchEthType(Ethernet.TYPE_IPV6);
+ if (!v.vlanId().equals(VlanId.NONE)) {
+ treatment.popVlan();
+ }
+ treatment.transition(FIB_TABLE);
+ rule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(selector.build())
+ .withTreatment(treatment.build())
+ .withPriority(DEFAULT_PRIORITY)
+ .fromApp(applicationId)
+ .makePermanent()
+ .forTable(FILTER_TABLE).build();
+
+ ops = install ? ops.add(rule) : ops.remove(rule);
+ }
// apply filtering flow rules
flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
@Override
@@ -309,13 +339,13 @@
private Collection<FlowRule> processForward(ForwardingObjective fwd) {
switch (fwd.flag()) {
- case SPECIFIC:
- return processSpecific(fwd);
- case VERSATILE:
- return processVersatile(fwd);
- default:
- fail(fwd, ObjectiveError.UNKNOWN);
- log.warn("Unknown forwarding flag {}", fwd.flag());
+ case SPECIFIC:
+ return processSpecific(fwd);
+ case VERSATILE:
+ return processVersatile(fwd);
+ default:
+ fail(fwd, ObjectiveError.UNKNOWN);
+ log.warn("Unknown forwarding flag {}", fwd.flag());
}
return Collections.emptySet();
}
@@ -335,7 +365,7 @@
Collection<FlowRule> flowrules = new ArrayList<>();
if (fwd.nextId() == null && fwd.treatment() == null) {
log.error("Forwarding objective {} from {} must contain "
- + "nextId or Treatment", fwd.selector(), fwd.appId());
+ + "nextId or Treatment", fwd.selector(), fwd.appId());
return Collections.emptySet();
}
@@ -344,7 +374,8 @@
// A punt rule for IP traffic should be directed to the FIB table
// so that it only takes effect if the packet misses the FIB rules
if (fwd.treatment() != null && containsPunt(fwd.treatment()) &&
- fwd.selector() != null && matchesIp(fwd.selector())) {
+ fwd.selector() != null && matchesIp(fwd.selector()) &&
+ !matchesControlTraffic(fwd.selector())) {
tableId = FIB_TABLE;
}
@@ -395,7 +426,24 @@
private boolean matchesIp(TrafficSelector selector) {
EthTypeCriterion c = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
- return c != null && c.ethType().equals(EthType.EtherType.IPV4.ethType());
+ return c != null && (c.ethType().equals(EthType.EtherType.IPV4.ethType()) ||
+ c.ethType().equals(EthType.EtherType.IPV6.ethType()));
+ }
+
+ private boolean matchesControlTraffic(TrafficSelector selector) {
+ EthTypeCriterion c = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
+ if (c != null && c.ethType().equals(EthType.EtherType.ARP.ethType())) {
+ return true;
+ } else if (c != null && c.ethType().equals(EthType.EtherType.IPV6.ethType())) {
+ IPProtocolCriterion i = (IPProtocolCriterion) selector.getCriterion(Criterion.Type.IP_PROTO);
+ if (i != null && i.protocol() == PROTOCOL_ICMP6) {
+ Icmpv6TypeCriterion ic = (Icmpv6TypeCriterion) selector.getCriterion(Criterion.Type.ICMPV6_TYPE);
+ if (ic.icmpv6Type() != ECHO_REQUEST && ic.icmpv6Type() != ECHO_REPLY) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/**
@@ -415,19 +463,34 @@
EthTypeCriterion ethType =
(EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
// XXX currently supporting only the L3 unicast table
- if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
+ if (ethType == null || (ethType.ethType().toShort() != TYPE_IPV4
+ && ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
fail(fwd, ObjectiveError.UNSUPPORTED);
return Collections.emptySet();
}
+ //We build the selector according the eth type.
+ IpPrefix ipPrefix;
+ TrafficSelector.Builder filteredSelector;
+ if (ethType.ethType().toShort() == TYPE_IPV4) {
+ ipPrefix = ((IPCriterion)
+ selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
- IpPrefix ipPrefix = ((IPCriterion)
- selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
+ filteredSelector = DefaultTrafficSelector.builder()
+ .matchEthType(TYPE_IPV4);
+ } else {
+ ipPrefix = ((IPCriterion)
+ selector.getCriterion(Criterion.Type.IPV6_DST)).ip();
- TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4);
-
+ filteredSelector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV6);
+ }
+ // If the prefix is different from the default via.
if (ipPrefix.prefixLength() != 0) {
- filteredSelector.matchIPDst(ipPrefix);
+ if (ethType.ethType().toShort() == TYPE_IPV4) {
+ filteredSelector.matchIPDst(ipPrefix);
+ } else {
+ filteredSelector.matchIPv6Dst(ipPrefix);
+ }
}
TrafficTreatment tt = null;