Committed by
Gerrit Code Review
WIP: proxy NDP for IPv6.
ONOS-924 Need to implement test cases. Change-Id: I86b0cb8c3c8d75f7276778e04c1a7166c9bb2f59
Showing
8 changed files
with
360 additions
and
25 deletions
| ... | @@ -37,6 +37,7 @@ | ... | @@ -37,6 +37,7 @@ |
| 37 | <module>ifwd</module> | 37 | <module>ifwd</module> |
| 38 | <module>mobility</module> | 38 | <module>mobility</module> |
| 39 | <module>proxyarp</module> | 39 | <module>proxyarp</module> |
| 40 | + <module>proxyndp</module> | ||
| 40 | <module>config</module> | 41 | <module>config</module> |
| 41 | <module>sdnip</module> | 42 | <module>sdnip</module> |
| 42 | <module>calendar</module> | 43 | <module>calendar</module> | ... | ... |
apps/proxyndp/pom.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!-- | ||
| 3 | + ~ Copyright 2014 Open Networking Laboratory | ||
| 4 | + ~ | ||
| 5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | + ~ you may not use this file except in compliance with the License. | ||
| 7 | + ~ You may obtain a copy of the License at | ||
| 8 | + ~ | ||
| 9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | + ~ | ||
| 11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
| 12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | + ~ See the License for the specific language governing permissions and | ||
| 15 | + ~ limitations under the License. | ||
| 16 | + --> | ||
| 17 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| 18 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 19 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
| 20 | + <modelVersion>4.0.0</modelVersion> | ||
| 21 | + | ||
| 22 | + <parent> | ||
| 23 | + <groupId>org.onosproject</groupId> | ||
| 24 | + <artifactId>onos-apps</artifactId> | ||
| 25 | + <version>1.1.0-SNAPSHOT</version> | ||
| 26 | + <relativePath>../pom.xml</relativePath> | ||
| 27 | + </parent> | ||
| 28 | + | ||
| 29 | + <artifactId>onos-app-proxyndp</artifactId> | ||
| 30 | + <packaging>bundle</packaging> | ||
| 31 | + | ||
| 32 | + <description>ONOS simple proxy neighbor discovery for IPv6 module</description> | ||
| 33 | + | ||
| 34 | +</project> |
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.proxyndp; | ||
| 17 | + | ||
| 18 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 19 | + | ||
| 20 | +import org.apache.felix.scr.annotations.Activate; | ||
| 21 | +import org.apache.felix.scr.annotations.Component; | ||
| 22 | +import org.apache.felix.scr.annotations.Deactivate; | ||
| 23 | +import org.apache.felix.scr.annotations.Reference; | ||
| 24 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
| 25 | +import org.onlab.packet.Ethernet; | ||
| 26 | +import org.onlab.packet.IPv6; | ||
| 27 | +import org.onlab.packet.ICMP6; | ||
| 28 | +import org.onosproject.core.ApplicationId; | ||
| 29 | +import org.onosproject.core.CoreService; | ||
| 30 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
| 31 | +import org.onosproject.net.flow.TrafficSelector; | ||
| 32 | +import org.onosproject.net.packet.PacketContext; | ||
| 33 | +import org.onosproject.net.packet.PacketPriority; | ||
| 34 | +import org.onosproject.net.packet.PacketProcessor; | ||
| 35 | +import org.onosproject.net.packet.PacketService; | ||
| 36 | +import org.onosproject.net.proxyarp.ProxyArpService; | ||
| 37 | +import org.slf4j.Logger; | ||
| 38 | + | ||
| 39 | +/** | ||
| 40 | + * Sample reactive proxy ndp application. | ||
| 41 | + */ | ||
| 42 | +@Component(immediate = true) | ||
| 43 | +public class ProxyNdp { | ||
| 44 | + | ||
| 45 | + private final Logger log = getLogger(getClass()); | ||
| 46 | + | ||
| 47 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 48 | + protected PacketService packetService; | ||
| 49 | + | ||
| 50 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 51 | + protected ProxyArpService proxyArpService; | ||
| 52 | + | ||
| 53 | + private ProxyNdpProcessor processor = new ProxyNdpProcessor(); | ||
| 54 | + | ||
| 55 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 56 | + protected CoreService coreService; | ||
| 57 | + | ||
| 58 | + private ApplicationId appId; | ||
| 59 | + | ||
| 60 | + @Activate | ||
| 61 | + public void activate() { | ||
| 62 | + appId = coreService.registerApplication("org.onosproject.proxyndp"); | ||
| 63 | + packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 1); | ||
| 64 | + | ||
| 65 | + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); | ||
| 66 | + selectorBuilder.matchEthType(Ethernet.TYPE_IPV6); | ||
| 67 | + selectorBuilder.matchIPProtocol(IPv6.PROTOCOL_ICMP6); | ||
| 68 | + selectorBuilder.matchIcmpv6Type(ICMP6.NEIGHBOR_SOLICITATION); | ||
| 69 | + packetService.requestPackets(selectorBuilder.build(), | ||
| 70 | + PacketPriority.CONTROL, appId); | ||
| 71 | + | ||
| 72 | + selectorBuilder = DefaultTrafficSelector.builder(); | ||
| 73 | + selectorBuilder.matchEthType(Ethernet.TYPE_IPV6); | ||
| 74 | + selectorBuilder.matchIPProtocol(IPv6.PROTOCOL_ICMP6); | ||
| 75 | + selectorBuilder.matchIcmpv6Type(ICMP6.NEIGHBOR_ADVERTISEMENT); | ||
| 76 | + packetService.requestPackets(selectorBuilder.build(), | ||
| 77 | + PacketPriority.CONTROL, appId); | ||
| 78 | + | ||
| 79 | + log.info("Started with Application ID {}", appId.id()); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + @Deactivate | ||
| 83 | + public void deactivate() { | ||
| 84 | + packetService.removeProcessor(processor); | ||
| 85 | + processor = null; | ||
| 86 | + log.info("Stopped"); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * Packet processor responsible for forwarding packets along their paths. | ||
| 92 | + */ | ||
| 93 | + private class ProxyNdpProcessor implements PacketProcessor { | ||
| 94 | + | ||
| 95 | + @Override | ||
| 96 | + public void process(PacketContext context) { | ||
| 97 | + // Stop processing if the packet has been handled, since we | ||
| 98 | + // can't do any more to it. | ||
| 99 | + if (context.isHandled()) { | ||
| 100 | + return; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + // Handle the neighbor discovery packet. | ||
| 104 | + proxyArpService.handlePacket(context); | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | + |
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * Proxy Ndp application that handles IPv6 neighbor resolution for you. | ||
| 19 | + */ | ||
| 20 | +package org.onosproject.proxyndp; |
| ... | @@ -16,7 +16,7 @@ | ... | @@ -16,7 +16,7 @@ |
| 16 | package org.onosproject.net.proxyarp; | 16 | package org.onosproject.net.proxyarp; |
| 17 | 17 | ||
| 18 | import org.onlab.packet.Ethernet; | 18 | import org.onlab.packet.Ethernet; |
| 19 | -import org.onlab.packet.Ip4Address; | 19 | +import org.onlab.packet.IpAddress; |
| 20 | import org.onosproject.net.ConnectPoint; | 20 | import org.onosproject.net.ConnectPoint; |
| 21 | import org.onosproject.net.packet.PacketContext; | 21 | import org.onosproject.net.packet.PacketContext; |
| 22 | 22 | ||
| ... | @@ -27,37 +27,39 @@ import org.onosproject.net.packet.PacketContext; | ... | @@ -27,37 +27,39 @@ import org.onosproject.net.packet.PacketContext; |
| 27 | public interface ProxyArpService { | 27 | public interface ProxyArpService { |
| 28 | 28 | ||
| 29 | /** | 29 | /** |
| 30 | - * Returns whether this particular IPv4 address is known to the system. | 30 | + * Returns whether this particular IP address is known to the system. |
| 31 | * | 31 | * |
| 32 | - * @param addr an IPv4 address | 32 | + * @param addr an IP address |
| 33 | * @return true if know, false otherwise | 33 | * @return true if know, false otherwise |
| 34 | */ | 34 | */ |
| 35 | - boolean isKnown(Ip4Address addr); | 35 | + boolean isKnown(IpAddress addr); |
| 36 | 36 | ||
| 37 | /** | 37 | /** |
| 38 | - * Sends a reply for a given request. If the host is not known then the arp | 38 | + * Sends a reply for a given request. If the host is not known then the |
| 39 | - * will be flooded at all edge ports. | 39 | + * arp or neighbor solicitation will be flooded at all edge ports. |
| 40 | * | 40 | * |
| 41 | - * @param eth an arp request | 41 | + * @param eth an arp or neighbor solicitation request |
| 42 | * @param inPort the port the request was received on | 42 | * @param inPort the port the request was received on |
| 43 | */ | 43 | */ |
| 44 | void reply(Ethernet eth, ConnectPoint inPort); | 44 | void reply(Ethernet eth, ConnectPoint inPort); |
| 45 | 45 | ||
| 46 | /** | 46 | /** |
| 47 | - * Forwards an ARP request to its destination. Floods at the edge the ARP request if the | 47 | + * Forwards an ARP or neighbor solicitation request to its destination. |
| 48 | - * destination is not known. | 48 | + * Floods at the edg the request if the destination is not known. |
| 49 | * | 49 | * |
| 50 | - * @param eth an ethernet frame containing an ARP request. | 50 | + * @param eth an ethernet frame containing an ARP or neighbor solicitation |
| 51 | + * request. | ||
| 51 | * @param inPort the port the request was received on | 52 | * @param inPort the port the request was received on |
| 52 | */ | 53 | */ |
| 53 | void forward(Ethernet eth, ConnectPoint inPort); | 54 | void forward(Ethernet eth, ConnectPoint inPort); |
| 54 | 55 | ||
| 55 | /** | 56 | /** |
| 56 | - * Handles a arp packet. | 57 | + * Handles a arp or neighbor solicitation packet. |
| 57 | - * Replies to arp requests and forwards request to the right place. | 58 | + * Replies to arp or neighbor solicitation requests and forwards request |
| 59 | + * to the right place. | ||
| 58 | * @param context the packet context to handle | 60 | * @param context the packet context to handle |
| 59 | * @return true if handled, false otherwise. | 61 | * @return true if handled, false otherwise. |
| 60 | */ | 62 | */ |
| 61 | - boolean handleArp(PacketContext context); | 63 | + boolean handlePacket(PacketContext context); |
| 62 | 64 | ||
| 63 | } | 65 | } | ... | ... |
| ... | @@ -26,10 +26,15 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; | ... | @@ -26,10 +26,15 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 26 | import org.apache.felix.scr.annotations.Service; | 26 | import org.apache.felix.scr.annotations.Service; |
| 27 | import org.onlab.packet.ARP; | 27 | import org.onlab.packet.ARP; |
| 28 | import org.onlab.packet.Ethernet; | 28 | import org.onlab.packet.Ethernet; |
| 29 | +import org.onlab.packet.ICMP6; | ||
| 30 | +import org.onlab.packet.IPv6; | ||
| 29 | import org.onlab.packet.Ip4Address; | 31 | import org.onlab.packet.Ip4Address; |
| 32 | +import org.onlab.packet.Ip6Address; | ||
| 30 | import org.onlab.packet.IpAddress; | 33 | import org.onlab.packet.IpAddress; |
| 31 | import org.onlab.packet.MacAddress; | 34 | import org.onlab.packet.MacAddress; |
| 32 | import org.onlab.packet.VlanId; | 35 | import org.onlab.packet.VlanId; |
| 36 | +import org.onlab.packet.ndp.NeighborAdvertisement; | ||
| 37 | +import org.onlab.packet.ndp.NeighborSolicitation; | ||
| 33 | import org.onosproject.net.ConnectPoint; | 38 | import org.onosproject.net.ConnectPoint; |
| 34 | import org.onosproject.net.Device; | 39 | import org.onosproject.net.Device; |
| 35 | import org.onosproject.net.Host; | 40 | import org.onosproject.net.Host; |
| ... | @@ -72,7 +77,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -72,7 +77,7 @@ public class ProxyArpManager implements ProxyArpService { |
| 72 | private final Logger log = getLogger(getClass()); | 77 | private final Logger log = getLogger(getClass()); |
| 73 | 78 | ||
| 74 | private static final String MAC_ADDR_NULL = "Mac address cannot be null."; | 79 | private static final String MAC_ADDR_NULL = "Mac address cannot be null."; |
| 75 | - private static final String REQUEST_NULL = "Arp request cannot be null."; | 80 | + private static final String REQUEST_NULL = "ARP or NDP request cannot be null."; |
| 76 | private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request."; | 81 | private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request."; |
| 77 | private static final String NOT_ARP_REQUEST = "ARP is not a request."; | 82 | private static final String NOT_ARP_REQUEST = "ARP is not a request."; |
| 78 | private static final String NOT_ARP_REPLY = "ARP is not a reply."; | 83 | private static final String NOT_ARP_REPLY = "ARP is not a reply."; |
| ... | @@ -115,7 +120,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -115,7 +120,7 @@ public class ProxyArpManager implements ProxyArpService { |
| 115 | } | 120 | } |
| 116 | 121 | ||
| 117 | @Override | 122 | @Override |
| 118 | - public boolean isKnown(Ip4Address addr) { | 123 | + public boolean isKnown(IpAddress addr) { |
| 119 | checkNotNull(addr, MAC_ADDR_NULL); | 124 | checkNotNull(addr, MAC_ADDR_NULL); |
| 120 | Set<Host> hosts = hostService.getHostsByIp(addr); | 125 | Set<Host> hosts = hostService.getHostsByIp(addr); |
| 121 | return !hosts.isEmpty(); | 126 | return !hosts.isEmpty(); |
| ... | @@ -124,8 +129,15 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -124,8 +129,15 @@ public class ProxyArpManager implements ProxyArpService { |
| 124 | @Override | 129 | @Override |
| 125 | public void reply(Ethernet eth, ConnectPoint inPort) { | 130 | public void reply(Ethernet eth, ConnectPoint inPort) { |
| 126 | checkNotNull(eth, REQUEST_NULL); | 131 | checkNotNull(eth, REQUEST_NULL); |
| 127 | - checkArgument(eth.getEtherType() == Ethernet.TYPE_ARP, | 132 | + |
| 128 | - REQUEST_NOT_ARP); | 133 | + if (eth.getEtherType() == Ethernet.TYPE_ARP) { |
| 134 | + replyArp(eth, inPort); | ||
| 135 | + } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) { | ||
| 136 | + replyNdp(eth, inPort); | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + private void replyArp(Ethernet eth, ConnectPoint inPort) { | ||
| 129 | ARP arp = (ARP) eth.getPayload(); | 141 | ARP arp = (ARP) eth.getPayload(); |
| 130 | checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST); | 142 | checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST); |
| 131 | checkNotNull(inPort); | 143 | checkNotNull(inPort); |
| ... | @@ -209,6 +221,92 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -209,6 +221,92 @@ public class ProxyArpManager implements ProxyArpService { |
| 209 | } | 221 | } |
| 210 | } | 222 | } |
| 211 | 223 | ||
| 224 | + private void replyNdp(Ethernet eth, ConnectPoint inPort) { | ||
| 225 | + | ||
| 226 | + IPv6 ipv6 = (IPv6) eth.getPayload(); | ||
| 227 | + ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); | ||
| 228 | + NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload(); | ||
| 229 | + | ||
| 230 | + VlanId vlan = VlanId.vlanId(eth.getVlanID()); | ||
| 231 | + | ||
| 232 | + // If the request came from outside the network, only reply if it was | ||
| 233 | + // for one of our external addresses. | ||
| 234 | + if (isOutsidePort(inPort)) { | ||
| 235 | + Ip6Address target = | ||
| 236 | + Ip6Address.valueOf(nsol.getTargetAddress()); | ||
| 237 | + Set<PortAddresses> addressSet = | ||
| 238 | + hostService.getAddressBindingsForPort(inPort); | ||
| 239 | + | ||
| 240 | + for (PortAddresses addresses : addressSet) { | ||
| 241 | + for (InterfaceIpAddress ia : addresses.ipAddresses()) { | ||
| 242 | + if (ia.ipAddress().equals(target)) { | ||
| 243 | + Ethernet ndpReply = | ||
| 244 | + buildNdpReply(target, addresses.mac(), eth); | ||
| 245 | + sendTo(ndpReply, inPort); | ||
| 246 | + } | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + return; | ||
| 250 | + } else { | ||
| 251 | + // If the source address matches one of our external addresses | ||
| 252 | + // it could be a request from an internal host to an external | ||
| 253 | + // address. Forward it over to the correct ports. | ||
| 254 | + Ip6Address source = | ||
| 255 | + Ip6Address.valueOf(nsol.getTargetAddress()); | ||
| 256 | + Set<PortAddresses> sourceAddresses = findPortsInSubnet(source); | ||
| 257 | + boolean matched = false; | ||
| 258 | + for (PortAddresses pa : sourceAddresses) { | ||
| 259 | + for (InterfaceIpAddress ia : pa.ipAddresses()) { | ||
| 260 | + if (ia.ipAddress().equals(source) && | ||
| 261 | + pa.vlan().equals(vlan)) { | ||
| 262 | + matched = true; | ||
| 263 | + sendTo(eth, pa.connectPoint()); | ||
| 264 | + } | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + if (matched) { | ||
| 269 | + return; | ||
| 270 | + } | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + // Continue with normal proxy ARP case | ||
| 274 | + | ||
| 275 | + Set<Host> hosts = hostService.getHostsByIp( | ||
| 276 | + Ip6Address.valueOf(nsol.getTargetAddress())); | ||
| 277 | + | ||
| 278 | + Host dst = null; | ||
| 279 | + Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(), | ||
| 280 | + VlanId.vlanId(eth.getVlanID()))); | ||
| 281 | + | ||
| 282 | + for (Host host : hosts) { | ||
| 283 | + if (host.vlan().equals(vlan)) { | ||
| 284 | + dst = host; | ||
| 285 | + break; | ||
| 286 | + } | ||
| 287 | + } | ||
| 288 | + | ||
| 289 | + if (src == null || dst == null) { | ||
| 290 | + flood(eth, inPort); | ||
| 291 | + return; | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + // | ||
| 295 | + // TODO find the correct IP address. | ||
| 296 | + // Right now we use the first IPv4 address that is found. | ||
| 297 | + // | ||
| 298 | + for (IpAddress ipAddress : dst.ipAddresses()) { | ||
| 299 | + Ip6Address ip6Address = ipAddress.getIp6Address(); | ||
| 300 | + if (ip6Address != null) { | ||
| 301 | + Ethernet arpReply = buildNdpReply(ip6Address, dst.mac(), eth); | ||
| 302 | + // TODO: check send status with host service. | ||
| 303 | + sendTo(arpReply, src.location()); | ||
| 304 | + break; | ||
| 305 | + } | ||
| 306 | + } | ||
| 307 | + } | ||
| 308 | + | ||
| 309 | + | ||
| 212 | /** | 310 | /** |
| 213 | * Outputs the given packet out the given port. | 311 | * Outputs the given packet out the given port. |
| 214 | * | 312 | * |
| ... | @@ -236,7 +334,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -236,7 +334,7 @@ public class ProxyArpManager implements ProxyArpService { |
| 236 | * @param target the target address to find a matching port for | 334 | * @param target the target address to find a matching port for |
| 237 | * @return a set of PortAddresses describing ports in the subnet | 335 | * @return a set of PortAddresses describing ports in the subnet |
| 238 | */ | 336 | */ |
| 239 | - private Set<PortAddresses> findPortsInSubnet(Ip4Address target) { | 337 | + private Set<PortAddresses> findPortsInSubnet(IpAddress target) { |
| 240 | Set<PortAddresses> result = new HashSet<PortAddresses>(); | 338 | Set<PortAddresses> result = new HashSet<PortAddresses>(); |
| 241 | for (PortAddresses addresses : hostService.getAddressBindings()) { | 339 | for (PortAddresses addresses : hostService.getAddressBindings()) { |
| 242 | for (InterfaceIpAddress ia : addresses.ipAddresses()) { | 340 | for (InterfaceIpAddress ia : addresses.ipAddresses()) { |
| ... | @@ -266,10 +364,6 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -266,10 +364,6 @@ public class ProxyArpManager implements ProxyArpService { |
| 266 | @Override | 364 | @Override |
| 267 | public void forward(Ethernet eth, ConnectPoint inPort) { | 365 | public void forward(Ethernet eth, ConnectPoint inPort) { |
| 268 | checkNotNull(eth, REQUEST_NULL); | 366 | checkNotNull(eth, REQUEST_NULL); |
| 269 | - checkArgument(eth.getEtherType() == Ethernet.TYPE_ARP, | ||
| 270 | - REQUEST_NOT_ARP); | ||
| 271 | - ARP arp = (ARP) eth.getPayload(); | ||
| 272 | - checkArgument(arp.getOpCode() == ARP.OP_REPLY, NOT_ARP_REPLY); | ||
| 273 | 367 | ||
| 274 | Host h = hostService.getHost(HostId.hostId(eth.getDestinationMAC(), | 368 | Host h = hostService.getHost(HostId.hostId(eth.getDestinationMAC(), |
| 275 | VlanId.vlanId(eth.getVlanID()))); | 369 | VlanId.vlanId(eth.getVlanID()))); |
| ... | @@ -286,21 +380,52 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -286,21 +380,52 @@ public class ProxyArpManager implements ProxyArpService { |
| 286 | } | 380 | } |
| 287 | 381 | ||
| 288 | @Override | 382 | @Override |
| 289 | - public boolean handleArp(PacketContext context) { | 383 | + public boolean handlePacket(PacketContext context) { |
| 290 | InboundPacket pkt = context.inPacket(); | 384 | InboundPacket pkt = context.inPacket(); |
| 291 | Ethernet ethPkt = pkt.parsed(); | 385 | Ethernet ethPkt = pkt.parsed(); |
| 292 | - if (ethPkt != null && ethPkt.getEtherType() == Ethernet.TYPE_ARP) { | 386 | + |
| 387 | + if (ethPkt == null) { | ||
| 388 | + return false; | ||
| 389 | + } | ||
| 390 | + if (ethPkt.getEtherType() == Ethernet.TYPE_ARP) { | ||
| 391 | + return handleArp(context, ethPkt); | ||
| 392 | + } else if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) { | ||
| 393 | + return handleNdp(context, ethPkt); | ||
| 394 | + } | ||
| 395 | + return false; | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + private boolean handleArp(PacketContext context, Ethernet ethPkt) { | ||
| 293 | ARP arp = (ARP) ethPkt.getPayload(); | 399 | ARP arp = (ARP) ethPkt.getPayload(); |
| 400 | + | ||
| 294 | if (arp.getOpCode() == ARP.OP_REPLY) { | 401 | if (arp.getOpCode() == ARP.OP_REPLY) { |
| 295 | forward(ethPkt, context.inPacket().receivedFrom()); | 402 | forward(ethPkt, context.inPacket().receivedFrom()); |
| 296 | } else if (arp.getOpCode() == ARP.OP_REQUEST) { | 403 | } else if (arp.getOpCode() == ARP.OP_REQUEST) { |
| 297 | reply(ethPkt, context.inPacket().receivedFrom()); | 404 | reply(ethPkt, context.inPacket().receivedFrom()); |
| 405 | + } else { | ||
| 406 | + return false; | ||
| 298 | } | 407 | } |
| 299 | context.block(); | 408 | context.block(); |
| 300 | return true; | 409 | return true; |
| 301 | } | 410 | } |
| 411 | + | ||
| 412 | + private boolean handleNdp(PacketContext context, Ethernet ethPkt) { | ||
| 413 | + IPv6 ipv6 = (IPv6) ethPkt.getPayload(); | ||
| 414 | + | ||
| 415 | + if (ipv6.getNextHeader() != IPv6.PROTOCOL_ICMP6) { | ||
| 416 | + return false; | ||
| 417 | + } | ||
| 418 | + ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); | ||
| 419 | + if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) { | ||
| 420 | + forward(ethPkt, context.inPacket().receivedFrom()); | ||
| 421 | + } else if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) { | ||
| 422 | + reply(ethPkt, context.inPacket().receivedFrom()); | ||
| 423 | + } else { | ||
| 302 | return false; | 424 | return false; |
| 303 | } | 425 | } |
| 426 | + context.block(); | ||
| 427 | + return true; | ||
| 428 | + } | ||
| 304 | 429 | ||
| 305 | /** | 430 | /** |
| 306 | * Flood the arp request at all edges in the network. | 431 | * Flood the arp request at all edges in the network. |
| ... | @@ -398,6 +523,44 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -398,6 +523,44 @@ public class ProxyArpManager implements ProxyArpService { |
| 398 | return eth; | 523 | return eth; |
| 399 | } | 524 | } |
| 400 | 525 | ||
| 526 | + /** | ||
| 527 | + * Builds an Neighbor Discovery reply based on a request. | ||
| 528 | + * | ||
| 529 | + * @param srcIp the IP address to use as the reply source | ||
| 530 | + * @param srcMac the MAC address to use as the reply source | ||
| 531 | + * @param request the Neighbor Solicitation request we got | ||
| 532 | + * @return an Ethernet frame containing the Neighbor Advertisement reply | ||
| 533 | + */ | ||
| 534 | + private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac, | ||
| 535 | + Ethernet request) { | ||
| 536 | + | ||
| 537 | + Ethernet eth = new Ethernet(); | ||
| 538 | + eth.setDestinationMACAddress(request.getSourceMAC()); | ||
| 539 | + eth.setSourceMACAddress(srcMac); | ||
| 540 | + eth.setEtherType(Ethernet.TYPE_IPV6); | ||
| 541 | + eth.setVlanID(request.getVlanID()); | ||
| 542 | + | ||
| 543 | + IPv6 requestIp = (IPv6) request.getPayload(); | ||
| 544 | + IPv6 ipv6 = new IPv6(); | ||
| 545 | + ipv6.setSourceAddress(srcIp.toOctets()); | ||
| 546 | + ipv6.setDestinationAddress(requestIp.getSourceAddress()); | ||
| 547 | + ipv6.setHopLimit((byte) 255); | ||
| 548 | + eth.setPayload(ipv6); | ||
| 549 | + | ||
| 550 | + ICMP6 icmp6 = new ICMP6(); | ||
| 551 | + icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT); | ||
| 552 | + icmp6.setIcmpCode((byte) 0); | ||
| 553 | + ipv6.setPayload(icmp6); | ||
| 554 | + | ||
| 555 | + NeighborAdvertisement nadv = new NeighborAdvertisement(); | ||
| 556 | + nadv.setTargetAddress(srcMac.toBytes()); | ||
| 557 | + nadv.setSolicitedFlag((byte) 1); | ||
| 558 | + nadv.setOverrideFlag((byte) 1); | ||
| 559 | + icmp6.setPayload(nadv); | ||
| 560 | + | ||
| 561 | + return eth; | ||
| 562 | + } | ||
| 563 | + | ||
| 401 | public class InternalLinkListener implements LinkListener { | 564 | public class InternalLinkListener implements LinkListener { |
| 402 | 565 | ||
| 403 | @Override | 566 | @Override | ... | ... |
| ... | @@ -184,6 +184,12 @@ | ... | @@ -184,6 +184,12 @@ |
| 184 | <bundle>mvn:org.onosproject/onos-app-proxyarp/@ONOS-VERSION</bundle> | 184 | <bundle>mvn:org.onosproject/onos-app-proxyarp/@ONOS-VERSION</bundle> |
| 185 | </feature> | 185 | </feature> |
| 186 | 186 | ||
| 187 | + <feature name="onos-app-proxyndp" version="@FEATURE-VERSION" | ||
| 188 | + description="ONOS sample proxyndp application"> | ||
| 189 | + <feature>onos-api</feature> | ||
| 190 | + <bundle>mvn:org.onosproject/onos-app-proxyndp/@ONOS-VERSION</bundle> | ||
| 191 | + </feature> | ||
| 192 | + | ||
| 187 | <feature name="onos-app-foo" version="@FEATURE-VERSION" | 193 | <feature name="onos-app-foo" version="@FEATURE-VERSION" |
| 188 | description="ONOS sample playground application"> | 194 | description="ONOS sample playground application"> |
| 189 | <feature>onos-api</feature> | 195 | <feature>onos-api</feature> | ... | ... |
-
Please register or login to post a comment