blob: 398260ff2d6167c4481aa21a558b144ce648f48a [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.proxyarp.impl;
alshabibb5522ff2014-09-29 19:20:00 -070017
alshabibb5522ff2014-09-29 19:20:00 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
Jonathan Harte8600eb2015-01-12 10:30:45 -080024import org.onlab.packet.ARP;
25import org.onlab.packet.Ethernet;
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -080026import org.onlab.packet.ICMP6;
27import org.onlab.packet.IPv6;
Jonathan Harte8600eb2015-01-12 10:30:45 -080028import org.onlab.packet.Ip4Address;
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -080029import org.onlab.packet.Ip6Address;
Jonathan Harte8600eb2015-01-12 10:30:45 -080030import org.onlab.packet.IpAddress;
31import org.onlab.packet.MacAddress;
32import org.onlab.packet.VlanId;
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -080033import org.onlab.packet.ndp.NeighborAdvertisement;
Pavlin Radoslavova2626ef2015-02-18 18:33:25 -080034import org.onlab.packet.ndp.NeighborDiscoveryOptions;
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -080035import org.onlab.packet.ndp.NeighborSolicitation;
Jonathan Hart4cb39882015-08-12 23:50:55 -040036import org.onosproject.incubator.net.intf.Interface;
37import org.onosproject.incubator.net.intf.InterfaceService;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.ConnectPoint;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.Host;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.device.DeviceService;
Aaron Kruglikovd8123832015-07-06 14:20:25 -070041import org.onosproject.net.edge.EdgePortService;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.flow.DefaultTrafficTreatment;
43import org.onosproject.net.flow.TrafficTreatment;
44import org.onosproject.net.host.HostService;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.link.LinkService;
46import org.onosproject.net.packet.DefaultOutboundPacket;
47import org.onosproject.net.packet.InboundPacket;
48import org.onosproject.net.packet.PacketContext;
49import org.onosproject.net.packet.PacketService;
50import org.onosproject.net.proxyarp.ProxyArpService;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070051import org.onosproject.net.proxyarp.ProxyArpStore;
alshabibb5522ff2014-09-29 19:20:00 -070052import org.slf4j.Logger;
53
Jonathan Hart6cd2f352015-01-13 17:44:45 -080054import java.nio.ByteBuffer;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080055import java.util.Set;
56
57import static com.google.common.base.Preconditions.checkArgument;
58import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070059import static org.onlab.packet.VlanId.vlanId;
60import static org.onosproject.net.HostId.hostId;
Changhoon Yoon541ef712015-05-23 17:18:34 +090061import static org.onosproject.security.AppGuard.checkPermission;
Aaron Kruglikovd8123832015-07-06 14:20:25 -070062import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090063import static org.onosproject.security.AppPermission.Type.*;
Changhoon Yoon541ef712015-05-23 17:18:34 +090064
alshabibb5522ff2014-09-29 19:20:00 -070065
alshabibb5522ff2014-09-29 19:20:00 -070066@Component(immediate = true)
67@Service
68public class ProxyArpManager implements ProxyArpService {
69
70 private final Logger log = getLogger(getClass());
71
72 private static final String MAC_ADDR_NULL = "Mac address cannot be null.";
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -080073 private static final String REQUEST_NULL = "ARP or NDP request cannot be null.";
alshabibb5522ff2014-09-29 19:20:00 -070074 private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request.";
75 private static final String NOT_ARP_REQUEST = "ARP is not a request.";
Jonathan Hart704ca142014-10-09 09:34:39 -070076 private static final String NOT_ARP_REPLY = "ARP is not a reply.";
alshabibb5522ff2014-09-29 19:20:00 -070077
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Aaron Kruglikovd8123832015-07-06 14:20:25 -070079 protected EdgePortService edgeService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb5522ff2014-09-29 19:20:00 -070082 protected HostService hostService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected PacketService packetService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected LinkService linkService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected DeviceService deviceService;
92
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070093 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected ProxyArpStore store;
95
Jonathan Hart4cb39882015-08-12 23:50:55 -040096 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected InterfaceService interfaceService;
98
alshabibb5522ff2014-09-29 19:20:00 -070099 @Activate
100 public void activate() {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700101 store.setDelegate(this::sendTo);
alshabibb5522ff2014-09-29 19:20:00 -0700102 log.info("Started");
103 }
104
alshabibb5522ff2014-09-29 19:20:00 -0700105 @Deactivate
106 public void deactivate() {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700107 store.setDelegate(null);
alshabibb5522ff2014-09-29 19:20:00 -0700108 log.info("Stopped");
109 }
110
111 @Override
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800112 public boolean isKnown(IpAddress addr) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900113 checkPermission(PACKET_READ);
114
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700115 checkNotNull(addr, MAC_ADDR_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700116 Set<Host> hosts = hostService.getHostsByIp(addr);
117 return !hosts.isEmpty();
118 }
119
120 @Override
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700121 public void reply(Ethernet eth, ConnectPoint inPort) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900122 checkPermission(PACKET_WRITE);
123
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700124 checkNotNull(eth, REQUEST_NULL);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800125
126 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
127 replyArp(eth, inPort);
128 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
129 replyNdp(eth, inPort);
130 }
131 }
132
133 private void replyArp(Ethernet eth, ConnectPoint inPort) {
alshabibb5522ff2014-09-29 19:20:00 -0700134 ARP arp = (ARP) eth.getPayload();
135 checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700136 checkNotNull(inPort);
Dusan Pajina22b9702015-02-12 16:25:23 +0100137 Ip4Address targetAddress = Ip4Address.valueOf(arp.getTargetProtocolAddress());
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700138
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700139 VlanId vlan = vlanId(eth.getVlanID());
Jonathan Hart6cd2f352015-01-13 17:44:45 -0800140
Jonathan Hart4cb39882015-08-12 23:50:55 -0400141 if (hasIpAddress(inPort)) {
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700142 // If the request came from outside the network, only reply if it was
143 // for one of our external addresses.
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700144
Jonathan Hart4cb39882015-08-12 23:50:55 -0400145 interfaceService.getInterfacesByPort(inPort)
146 .stream()
147 .filter(intf -> intf.ipAddresses()
148 .stream()
149 .anyMatch(ia -> ia.ipAddress().equals(targetAddress)))
150 .forEach(intf -> buildAndSendArp(targetAddress, intf.mac(), eth, inPort));
151
152 // Stop here and don't proxy ARPs if the port has an IP address
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700153 return;
154 }
155
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700156 // See if we have the target host in the host store
alshabibb5522ff2014-09-29 19:20:00 -0700157
Dusan Pajina22b9702015-02-12 16:25:23 +0100158 Set<Host> hosts = hostService.getHostsByIp(targetAddress);
alshabibb5522ff2014-09-29 19:20:00 -0700159
160 Host dst = null;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700161 Host src = hostService.getHost(hostId(eth.getSourceMAC(),
Jonathan Hart4cb39882015-08-12 23:50:55 -0400162 vlanId(eth.getVlanID())));
alshabibb5522ff2014-09-29 19:20:00 -0700163
164 for (Host host : hosts) {
165 if (host.vlan().equals(vlan)) {
166 dst = host;
167 break;
168 }
169 }
170
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700171 if (src != null && dst != null) {
172 // We know the target host so we can respond
Jonathan Hart4cb39882015-08-12 23:50:55 -0400173 buildAndSendArp(targetAddress, dst.mac(), eth, inPort);
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700174 return;
175 }
176
177 // If the source address matches one of our external addresses
178 // it could be a request from an internal host to an external
179 // address. Forward it over to the correct port.
180 Ip4Address source =
181 Ip4Address.valueOf(arp.getSenderProtocolAddress());
Jonathan Hart4cb39882015-08-12 23:50:55 -0400182
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700183 boolean matched = false;
Jonathan Hart4cb39882015-08-12 23:50:55 -0400184 Set<Interface> interfaces = interfaceService.getInterfacesByIp(source);
185 for (Interface intf : interfaces) {
186 if (intf.vlan().equals(vlan)) {
187 matched = true;
188 sendTo(eth, intf.connectPoint());
189 break;
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700190 }
191 }
192
193 if (matched) {
alshabibb5522ff2014-09-29 19:20:00 -0700194 return;
195 }
196
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700197 // The request couldn't be resolved.
198 // Flood the request on all ports except the incoming port.
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700199 flood(eth, inPort);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700200 }
201
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800202 private void replyNdp(Ethernet eth, ConnectPoint inPort) {
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800203 IPv6 ipv6 = (IPv6) eth.getPayload();
204 ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
205 NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload();
Dusan Pajina22b9702015-02-12 16:25:23 +0100206 Ip6Address targetAddress = Ip6Address.valueOf(nsol.getTargetAddress());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800207
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700208 VlanId vlan = vlanId(eth.getVlanID());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800209
210 // If the request came from outside the network, only reply if it was
211 // for one of our external addresses.
Jonathan Hart4cb39882015-08-12 23:50:55 -0400212 if (hasIpAddress(inPort)) {
213 interfaceService.getInterfacesByPort(inPort)
214 .stream()
215 .filter(intf -> intf.ipAddresses()
216 .stream()
217 .anyMatch(ia -> ia.ipAddress().equals(targetAddress)))
218 .forEach(intf -> buildAndSendNdp(targetAddress, intf.mac(), eth, inPort));
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800219 return;
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800220 }
221
222 // Continue with normal proxy ARP case
223
Dusan Pajina22b9702015-02-12 16:25:23 +0100224 Set<Host> hosts = hostService.getHostsByIp(targetAddress);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800225
226 Host dst = null;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700227 Host src = hostService.getHost(hostId(eth.getSourceMAC(),
228 vlanId(eth.getVlanID())));
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800229
230 for (Host host : hosts) {
231 if (host.vlan().equals(vlan)) {
232 dst = host;
233 break;
234 }
235 }
236
Thomas Vachuska1d0019c2015-08-31 17:02:17 -0700237 if (src != null && dst != null) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400238 // We know the target host so we can respond
239 buildAndSendNdp(targetAddress, dst.mac(), eth, inPort);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800240 return;
241 }
242
Jonathan Hart4cb39882015-08-12 23:50:55 -0400243 // If the source address matches one of our external addresses
244 // it could be a request from an internal host to an external
245 // address. Forward it over to the correct port.
246 Ip6Address source =
247 Ip6Address.valueOf(ipv6.getSourceAddress());
248
249 boolean matched = false;
250
251 Set<Interface> interfaces = interfaceService.getInterfacesByIp(source);
252 for (Interface intf : interfaces) {
253 if (intf.vlan().equals(vlan)) {
254 matched = true;
255 sendTo(eth, intf.connectPoint());
256 break;
257 }
258 }
259
260 if (matched) {
261 return;
262 }
263
264 // The request couldn't be resolved.
265 // Flood the request on all ports except the incoming ports.
266 flood(eth, inPort);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800267 }
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700268 //TODO checkpoint
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800269
Jonathan Hart4cb39882015-08-12 23:50:55 -0400270 private void buildAndSendArp(Ip4Address srcIp, MacAddress srcMac,
271 Ethernet request, ConnectPoint port) {
272 sendTo(ARP.buildArpReply(srcIp, srcMac, request), port);
273 }
274
275 private void buildAndSendNdp(Ip6Address srcIp, MacAddress srcMac,
276 Ethernet request, ConnectPoint port) {
277 sendTo(buildNdpReply(srcIp, srcMac, request), port);
278 }
279
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700280 /**
281 * Outputs the given packet out the given port.
282 *
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700283 * @param packet the packet to send
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700284 * @param outPort the port to send it out
285 */
286 private void sendTo(Ethernet packet, ConnectPoint outPort) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700287 sendTo(outPort, ByteBuffer.wrap(packet.serialize()));
288 }
289
290 private void sendTo(ConnectPoint outPort, ByteBuffer packet) {
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700291 if (!edgeService.isEdgePoint(outPort)) {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700292 // Sanity check to make sure we don't send the packet out an
293 // internal port and create a loop (could happen due to
294 // misconfiguration).
295 return;
296 }
297
tom9a693fd2014-10-03 11:32:19 -0700298 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700299 builder.setOutput(outPort.port());
300 packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700301 builder.build(), packet));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700302 }
303
304 /**
Jonathan Hart4cb39882015-08-12 23:50:55 -0400305 * Returns whether the given port has any IP addresses configured or not.
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700306 *
307 * @param port the port to check
Jonathan Hart4cb39882015-08-12 23:50:55 -0400308 * @return true if the port has at least one IP address configured,
309 * otherwise false
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700310 */
Jonathan Hart4cb39882015-08-12 23:50:55 -0400311 private boolean hasIpAddress(ConnectPoint port) {
312 return interfaceService.getInterfacesByPort(port)
313 .stream()
314 .map(intf -> intf.ipAddresses())
315 .findAny()
316 .isPresent();
alshabibb5522ff2014-09-29 19:20:00 -0700317 }
318
319 @Override
Jonathan Hartf84591d2015-01-16 14:33:43 -0800320 public void forward(Ethernet eth, ConnectPoint inPort) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900321 checkPermission(PACKET_WRITE);
322
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700323 checkNotNull(eth, REQUEST_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700324
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700325 Host h = hostService.getHost(hostId(eth.getDestinationMAC(),
326 vlanId(eth.getVlanID())));
alshabibb5522ff2014-09-29 19:20:00 -0700327
328 if (h == null) {
Jonathan Hartf84591d2015-01-16 14:33:43 -0800329 flood(eth, inPort);
alshabibb5522ff2014-09-29 19:20:00 -0700330 } else {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700331 Host subject = hostService.getHost(hostId(eth.getSourceMAC(),
332 vlanId(eth.getVlanID())));
333 store.forward(h.location(), subject, ByteBuffer.wrap(eth.serialize()));
alshabibb5522ff2014-09-29 19:20:00 -0700334 }
alshabibb5522ff2014-09-29 19:20:00 -0700335 }
336
alshabibc274c902014-10-03 14:58:27 -0700337 @Override
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800338 public boolean handlePacket(PacketContext context) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900339 checkPermission(PACKET_WRITE);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900340
alshabibc274c902014-10-03 14:58:27 -0700341 InboundPacket pkt = context.inPacket();
342 Ethernet ethPkt = pkt.parsed();
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800343
344 if (ethPkt == null) {
345 return false;
346 }
347 if (ethPkt.getEtherType() == Ethernet.TYPE_ARP) {
348 return handleArp(context, ethPkt);
349 } else if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) {
350 return handleNdp(context, ethPkt);
alshabibc274c902014-10-03 14:58:27 -0700351 }
352 return false;
353 }
354
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800355 private boolean handleArp(PacketContext context, Ethernet ethPkt) {
356 ARP arp = (ARP) ethPkt.getPayload();
357
358 if (arp.getOpCode() == ARP.OP_REPLY) {
359 forward(ethPkt, context.inPacket().receivedFrom());
360 } else if (arp.getOpCode() == ARP.OP_REQUEST) {
361 reply(ethPkt, context.inPacket().receivedFrom());
362 } else {
363 return false;
364 }
365 context.block();
366 return true;
367 }
368
369 private boolean handleNdp(PacketContext context, Ethernet ethPkt) {
370 IPv6 ipv6 = (IPv6) ethPkt.getPayload();
371
372 if (ipv6.getNextHeader() != IPv6.PROTOCOL_ICMP6) {
373 return false;
374 }
375 ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
376 if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) {
377 forward(ethPkt, context.inPacket().receivedFrom());
378 } else if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) {
379 reply(ethPkt, context.inPacket().receivedFrom());
380 } else {
381 return false;
382 }
383 context.block();
384 return true;
385 }
386
alshabibb5522ff2014-09-29 19:20:00 -0700387 /**
388 * Flood the arp request at all edges in the network.
Dusan Pajina22b9702015-02-12 16:25:23 +0100389 *
390 * @param request the arp request
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700391 * @param inPort the connect point the arp request was received on
alshabibb5522ff2014-09-29 19:20:00 -0700392 */
Jonathan Hartf84591d2015-01-16 14:33:43 -0800393 private void flood(Ethernet request, ConnectPoint inPort) {
alshabibb5522ff2014-09-29 19:20:00 -0700394 TrafficTreatment.Builder builder = null;
395 ByteBuffer buf = ByteBuffer.wrap(request.serialize());
396
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700397 for (ConnectPoint connectPoint : edgeService.getEdgePoints()) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400398 if (hasIpAddress(connectPoint) || connectPoint.equals(inPort)) {
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700399 continue;
400 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700401
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700402 builder = DefaultTrafficTreatment.builder();
403 builder.setOutput(connectPoint.port());
404 packetService.emit(new DefaultOutboundPacket(connectPoint.deviceId(),
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700405 builder.build(), buf));
alshabibb5522ff2014-09-29 19:20:00 -0700406 }
alshabibb5522ff2014-09-29 19:20:00 -0700407 }
408
alshabibb5522ff2014-09-29 19:20:00 -0700409 /**
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800410 * Builds an Neighbor Discovery reply based on a request.
411 *
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700412 * @param srcIp the IP address to use as the reply source
413 * @param srcMac the MAC address to use as the reply source
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800414 * @param request the Neighbor Solicitation request we got
415 * @return an Ethernet frame containing the Neighbor Advertisement reply
416 */
417 private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac,
418 Ethernet request) {
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800419 Ethernet eth = new Ethernet();
420 eth.setDestinationMACAddress(request.getSourceMAC());
421 eth.setSourceMACAddress(srcMac);
422 eth.setEtherType(Ethernet.TYPE_IPV6);
423 eth.setVlanID(request.getVlanID());
424
425 IPv6 requestIp = (IPv6) request.getPayload();
426 IPv6 ipv6 = new IPv6();
427 ipv6.setSourceAddress(srcIp.toOctets());
428 ipv6.setDestinationAddress(requestIp.getSourceAddress());
429 ipv6.setHopLimit((byte) 255);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800430
431 ICMP6 icmp6 = new ICMP6();
432 icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT);
433 icmp6.setIcmpCode((byte) 0);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800434
435 NeighborAdvertisement nadv = new NeighborAdvertisement();
Dusan Pajina22b9702015-02-12 16:25:23 +0100436 nadv.setTargetAddress(srcIp.toOctets());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800437 nadv.setSolicitedFlag((byte) 1);
438 nadv.setOverrideFlag((byte) 1);
Pavlin Radoslavova2626ef2015-02-18 18:33:25 -0800439 nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS,
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700440 srcMac.toBytes());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800441
Pavlin Radoslavova2626ef2015-02-18 18:33:25 -0800442 icmp6.setPayload(nadv);
Dusan Pajina22b9702015-02-12 16:25:23 +0100443 ipv6.setPayload(icmp6);
444 eth.setPayload(ipv6);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800445 return eth;
446 }
alshabibb5522ff2014-09-29 19:20:00 -0700447}