Committed by
Ray Milkey
ProxyArpManager - fix IPv6 ND Adv issue with Option fields and ARP/NDP Reply
with first IP address from Host service This fixes ONOS-1010 Also, add protocol-related constants to class NeighborAdvertisement. Change-Id: Iacf9e48a8a03a86e1cc4e89e7e2b2b4ccc4a7e3a
Showing
2 changed files
with
51 additions
and
43 deletions
| ... | @@ -25,6 +25,7 @@ import org.apache.felix.scr.annotations.Reference; | ... | @@ -25,6 +25,7 @@ import org.apache.felix.scr.annotations.Reference; |
| 25 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 25 | 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.Data; | ||
| 28 | import org.onlab.packet.Ethernet; | 29 | import org.onlab.packet.Ethernet; |
| 29 | import org.onlab.packet.ICMP6; | 30 | import org.onlab.packet.ICMP6; |
| 30 | import org.onlab.packet.IPv6; | 31 | import org.onlab.packet.IPv6; |
| ... | @@ -141,22 +142,21 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -141,22 +142,21 @@ public class ProxyArpManager implements ProxyArpService { |
| 141 | ARP arp = (ARP) eth.getPayload(); | 142 | ARP arp = (ARP) eth.getPayload(); |
| 142 | checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST); | 143 | checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST); |
| 143 | checkNotNull(inPort); | 144 | checkNotNull(inPort); |
| 145 | + Ip4Address targetAddress = Ip4Address.valueOf(arp.getTargetProtocolAddress()); | ||
| 144 | 146 | ||
| 145 | VlanId vlan = VlanId.vlanId(eth.getVlanID()); | 147 | VlanId vlan = VlanId.vlanId(eth.getVlanID()); |
| 146 | 148 | ||
| 147 | // If the request came from outside the network, only reply if it was | 149 | // If the request came from outside the network, only reply if it was |
| 148 | // for one of our external addresses. | 150 | // for one of our external addresses. |
| 149 | if (isOutsidePort(inPort)) { | 151 | if (isOutsidePort(inPort)) { |
| 150 | - Ip4Address target = | ||
| 151 | - Ip4Address.valueOf(arp.getTargetProtocolAddress()); | ||
| 152 | Set<PortAddresses> addressSet = | 152 | Set<PortAddresses> addressSet = |
| 153 | hostService.getAddressBindingsForPort(inPort); | 153 | hostService.getAddressBindingsForPort(inPort); |
| 154 | 154 | ||
| 155 | for (PortAddresses addresses : addressSet) { | 155 | for (PortAddresses addresses : addressSet) { |
| 156 | for (InterfaceIpAddress ia : addresses.ipAddresses()) { | 156 | for (InterfaceIpAddress ia : addresses.ipAddresses()) { |
| 157 | - if (ia.ipAddress().equals(target)) { | 157 | + if (ia.ipAddress().equals(targetAddress)) { |
| 158 | Ethernet arpReply = | 158 | Ethernet arpReply = |
| 159 | - buildArpReply(target, addresses.mac(), eth); | 159 | + buildArpReply(targetAddress, addresses.mac(), eth); |
| 160 | sendTo(arpReply, inPort); | 160 | sendTo(arpReply, inPort); |
| 161 | } | 161 | } |
| 162 | } | 162 | } |
| ... | @@ -187,8 +187,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -187,8 +187,7 @@ public class ProxyArpManager implements ProxyArpService { |
| 187 | 187 | ||
| 188 | // Continue with normal proxy ARP case | 188 | // Continue with normal proxy ARP case |
| 189 | 189 | ||
| 190 | - Set<Host> hosts = hostService.getHostsByIp( | 190 | + Set<Host> hosts = hostService.getHostsByIp(targetAddress); |
| 191 | - Ip4Address.valueOf(arp.getTargetProtocolAddress())); | ||
| 192 | 191 | ||
| 193 | Host dst = null; | 192 | Host dst = null; |
| 194 | Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(), | 193 | Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(), |
| ... | @@ -202,23 +201,19 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -202,23 +201,19 @@ public class ProxyArpManager implements ProxyArpService { |
| 202 | } | 201 | } |
| 203 | 202 | ||
| 204 | if (src == null || dst == null) { | 203 | if (src == null || dst == null) { |
| 204 | + // | ||
| 205 | + // The request couldn't be resolved. | ||
| 206 | + // Flood the request on all ports except the incoming ports. | ||
| 207 | + // | ||
| 205 | flood(eth, inPort); | 208 | flood(eth, inPort); |
| 206 | return; | 209 | return; |
| 207 | } | 210 | } |
| 208 | 211 | ||
| 209 | // | 212 | // |
| 210 | - // TODO find the correct IP address. | 213 | + // Reply on the port the request was received on |
| 211 | - // Right now we use the first IPv4 address that is found. | ||
| 212 | // | 214 | // |
| 213 | - for (IpAddress ipAddress : dst.ipAddresses()) { | 215 | + Ethernet arpReply = buildArpReply(targetAddress, dst.mac(), eth); |
| 214 | - Ip4Address ip4Address = ipAddress.getIp4Address(); | 216 | + sendTo(arpReply, inPort); |
| 215 | - if (ip4Address != null) { | ||
| 216 | - Ethernet arpReply = buildArpReply(ip4Address, dst.mac(), eth); | ||
| 217 | - // TODO: check send status with host service. | ||
| 218 | - sendTo(arpReply, src.location()); | ||
| 219 | - break; | ||
| 220 | - } | ||
| 221 | - } | ||
| 222 | } | 217 | } |
| 223 | 218 | ||
| 224 | private void replyNdp(Ethernet eth, ConnectPoint inPort) { | 219 | private void replyNdp(Ethernet eth, ConnectPoint inPort) { |
| ... | @@ -226,22 +221,21 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -226,22 +221,21 @@ public class ProxyArpManager implements ProxyArpService { |
| 226 | IPv6 ipv6 = (IPv6) eth.getPayload(); | 221 | IPv6 ipv6 = (IPv6) eth.getPayload(); |
| 227 | ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); | 222 | ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); |
| 228 | NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload(); | 223 | NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload(); |
| 224 | + Ip6Address targetAddress = Ip6Address.valueOf(nsol.getTargetAddress()); | ||
| 229 | 225 | ||
| 230 | VlanId vlan = VlanId.vlanId(eth.getVlanID()); | 226 | VlanId vlan = VlanId.vlanId(eth.getVlanID()); |
| 231 | 227 | ||
| 232 | // If the request came from outside the network, only reply if it was | 228 | // If the request came from outside the network, only reply if it was |
| 233 | // for one of our external addresses. | 229 | // for one of our external addresses. |
| 234 | if (isOutsidePort(inPort)) { | 230 | if (isOutsidePort(inPort)) { |
| 235 | - Ip6Address target = | ||
| 236 | - Ip6Address.valueOf(nsol.getTargetAddress()); | ||
| 237 | Set<PortAddresses> addressSet = | 231 | Set<PortAddresses> addressSet = |
| 238 | hostService.getAddressBindingsForPort(inPort); | 232 | hostService.getAddressBindingsForPort(inPort); |
| 239 | 233 | ||
| 240 | for (PortAddresses addresses : addressSet) { | 234 | for (PortAddresses addresses : addressSet) { |
| 241 | for (InterfaceIpAddress ia : addresses.ipAddresses()) { | 235 | for (InterfaceIpAddress ia : addresses.ipAddresses()) { |
| 242 | - if (ia.ipAddress().equals(target)) { | 236 | + if (ia.ipAddress().equals(targetAddress)) { |
| 243 | Ethernet ndpReply = | 237 | Ethernet ndpReply = |
| 244 | - buildNdpReply(target, addresses.mac(), eth); | 238 | + buildNdpReply(targetAddress, addresses.mac(), eth); |
| 245 | sendTo(ndpReply, inPort); | 239 | sendTo(ndpReply, inPort); |
| 246 | } | 240 | } |
| 247 | } | 241 | } |
| ... | @@ -272,8 +266,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -272,8 +266,7 @@ public class ProxyArpManager implements ProxyArpService { |
| 272 | 266 | ||
| 273 | // Continue with normal proxy ARP case | 267 | // Continue with normal proxy ARP case |
| 274 | 268 | ||
| 275 | - Set<Host> hosts = hostService.getHostsByIp( | 269 | + Set<Host> hosts = hostService.getHostsByIp(targetAddress); |
| 276 | - Ip6Address.valueOf(nsol.getTargetAddress())); | ||
| 277 | 270 | ||
| 278 | Host dst = null; | 271 | Host dst = null; |
| 279 | Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(), | 272 | Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(), |
| ... | @@ -287,23 +280,19 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -287,23 +280,19 @@ public class ProxyArpManager implements ProxyArpService { |
| 287 | } | 280 | } |
| 288 | 281 | ||
| 289 | if (src == null || dst == null) { | 282 | if (src == null || dst == null) { |
| 283 | + // | ||
| 284 | + // The request couldn't be resolved. | ||
| 285 | + // Flood the request on all ports except the incoming ports. | ||
| 286 | + // | ||
| 290 | flood(eth, inPort); | 287 | flood(eth, inPort); |
| 291 | return; | 288 | return; |
| 292 | } | 289 | } |
| 293 | 290 | ||
| 294 | // | 291 | // |
| 295 | - // TODO find the correct IP address. | 292 | + // Reply on the port the request was received on |
| 296 | - // Right now we use the first IPv4 address that is found. | ||
| 297 | // | 293 | // |
| 298 | - for (IpAddress ipAddress : dst.ipAddresses()) { | 294 | + Ethernet ndpReply = buildNdpReply(targetAddress, dst.mac(), eth); |
| 299 | - Ip6Address ip6Address = ipAddress.getIp6Address(); | 295 | + sendTo(ndpReply, inPort); |
| 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 | } | 296 | } |
| 308 | 297 | ||
| 309 | 298 | ||
| ... | @@ -429,7 +418,9 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -429,7 +418,9 @@ public class ProxyArpManager implements ProxyArpService { |
| 429 | 418 | ||
| 430 | /** | 419 | /** |
| 431 | * Flood the arp request at all edges in the network. | 420 | * Flood the arp request at all edges in the network. |
| 432 | - * @param request the arp request. | 421 | + * |
| 422 | + * @param request the arp request | ||
| 423 | + * @param inPort the connect point the arp request was received on | ||
| 433 | */ | 424 | */ |
| 434 | private void flood(Ethernet request, ConnectPoint inPort) { | 425 | private void flood(Ethernet request, ConnectPoint inPort) { |
| 435 | TrafficTreatment.Builder builder = null; | 426 | TrafficTreatment.Builder builder = null; |
| ... | @@ -519,6 +510,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -519,6 +510,7 @@ public class ProxyArpManager implements ProxyArpService { |
| 519 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) | 510 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) |
| 520 | .getSenderProtocolAddress()); | 511 | .getSenderProtocolAddress()); |
| 521 | arp.setSenderProtocolAddress(srcIp.toInt()); | 512 | arp.setSenderProtocolAddress(srcIp.toInt()); |
| 513 | + | ||
| 522 | eth.setPayload(arp); | 514 | eth.setPayload(arp); |
| 523 | return eth; | 515 | return eth; |
| 524 | } | 516 | } |
| ... | @@ -545,19 +537,32 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -545,19 +537,32 @@ public class ProxyArpManager implements ProxyArpService { |
| 545 | ipv6.setSourceAddress(srcIp.toOctets()); | 537 | ipv6.setSourceAddress(srcIp.toOctets()); |
| 546 | ipv6.setDestinationAddress(requestIp.getSourceAddress()); | 538 | ipv6.setDestinationAddress(requestIp.getSourceAddress()); |
| 547 | ipv6.setHopLimit((byte) 255); | 539 | ipv6.setHopLimit((byte) 255); |
| 548 | - eth.setPayload(ipv6); | ||
| 549 | 540 | ||
| 550 | ICMP6 icmp6 = new ICMP6(); | 541 | ICMP6 icmp6 = new ICMP6(); |
| 551 | icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT); | 542 | icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT); |
| 552 | icmp6.setIcmpCode((byte) 0); | 543 | icmp6.setIcmpCode((byte) 0); |
| 553 | - ipv6.setPayload(icmp6); | ||
| 554 | 544 | ||
| 555 | NeighborAdvertisement nadv = new NeighborAdvertisement(); | 545 | NeighborAdvertisement nadv = new NeighborAdvertisement(); |
| 556 | - nadv.setTargetAddress(srcMac.toBytes()); | 546 | + nadv.setTargetAddress(srcIp.toOctets()); |
| 557 | nadv.setSolicitedFlag((byte) 1); | 547 | nadv.setSolicitedFlag((byte) 1); |
| 558 | nadv.setOverrideFlag((byte) 1); | 548 | nadv.setOverrideFlag((byte) 1); |
| 549 | + byte[] nadvData = | ||
| 550 | + new byte[NeighborAdvertisement.OPTION_LENGTH_IEEE802_ADDRESS]; | ||
| 551 | + ByteBuffer bbNadv = ByteBuffer.wrap(nadvData); | ||
| 552 | + byte nadvOptionType = | ||
| 553 | + NeighborAdvertisement.OPTION_TYPE_TARGET_LL_ADDRESS; | ||
| 554 | + // The Option length in 8-octets units | ||
| 555 | + byte nadvOptionLength = | ||
| 556 | + (NeighborAdvertisement.OPTION_LENGTH_IEEE802_ADDRESS + 7) / 8; | ||
| 557 | + bbNadv.put(nadvOptionType); | ||
| 558 | + bbNadv.put(nadvOptionLength); | ||
| 559 | + bbNadv.put(srcMac.toBytes()); | ||
| 560 | + Data nadvPayload = new Data(); | ||
| 561 | + nadv.setPayload(nadvPayload.deserialize(nadvData, 0, nadvData.length)); | ||
| 559 | icmp6.setPayload(nadv); | 562 | icmp6.setPayload(nadv); |
| 560 | 563 | ||
| 564 | + ipv6.setPayload(icmp6); | ||
| 565 | + eth.setPayload(ipv6); | ||
| 561 | return eth; | 566 | return eth; |
| 562 | } | 567 | } |
| 563 | 568 | ... | ... |
| 1 | /* | 1 | /* |
| 2 | - * Copyright 2014 Open Networking Laboratory | 2 | + * Copyright 2014-2015 Open Networking Laboratory |
| 3 | * | 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
| ... | @@ -13,9 +13,6 @@ | ... | @@ -13,9 +13,6 @@ |
| 13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | package org.onlab.packet.ndp; | 16 | package org.onlab.packet.ndp; |
| 20 | 17 | ||
| 21 | import org.onlab.packet.BasePacket; | 18 | import org.onlab.packet.BasePacket; |
| ... | @@ -27,10 +24,16 @@ import java.nio.ByteBuffer; | ... | @@ -27,10 +24,16 @@ import java.nio.ByteBuffer; |
| 27 | import java.util.Arrays; | 24 | import java.util.Arrays; |
| 28 | 25 | ||
| 29 | /** | 26 | /** |
| 30 | - * Implements ICMPv6 Neighbor Advertisement packet format. (RFC 4861) | 27 | + * Implements ICMPv6 Neighbor Advertisement packet format (RFC 4861). |
| 31 | */ | 28 | */ |
| 32 | public class NeighborAdvertisement extends BasePacket { | 29 | public class NeighborAdvertisement extends BasePacket { |
| 33 | public static final byte HEADER_LENGTH = 20; // bytes | 30 | public static final byte HEADER_LENGTH = 20; // bytes |
| 31 | + public static final byte OPTION_TYPE_SOURCE_LL_ADDRESS = 1; | ||
| 32 | + public static final byte OPTION_TYPE_TARGET_LL_ADDRESS = 2; | ||
| 33 | + public static final byte OPTION_TYPE_PREFIX_INFORMATION = 3; | ||
| 34 | + public static final byte OPTION_TYPE_REDIRECTED_HEADER = 4; | ||
| 35 | + public static final byte OPTION_TYPE_MTU = 5; | ||
| 36 | + public static final byte OPTION_LENGTH_IEEE802_ADDRESS = 8; | ||
| 34 | 37 | ||
| 35 | protected byte routerFlag; | 38 | protected byte routerFlag; |
| 36 | protected byte solicitedFlag; | 39 | protected byte solicitedFlag; | ... | ... |
-
Please register or login to post a comment