Dusan Pajin
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
...@@ -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;
......