blob: 1a56d0e8c9825469516daa706a091b0ff080cab0 [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;
Changhoon Yoon541ef712015-05-23 17:18:34 +090036import org.onosproject.core.Permission;
Jonathan Hart4cb39882015-08-12 23:50:55 -040037import org.onosproject.incubator.net.intf.Interface;
38import org.onosproject.incubator.net.intf.InterfaceService;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.ConnectPoint;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.Host;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.device.DeviceService;
Aaron Kruglikovd8123832015-07-06 14:20:25 -070042import org.onosproject.net.edge.EdgePortService;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.TrafficTreatment;
45import org.onosproject.net.host.HostService;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.link.LinkService;
47import org.onosproject.net.packet.DefaultOutboundPacket;
48import org.onosproject.net.packet.InboundPacket;
49import org.onosproject.net.packet.PacketContext;
50import org.onosproject.net.packet.PacketService;
51import org.onosproject.net.proxyarp.ProxyArpService;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070052import org.onosproject.net.proxyarp.ProxyArpStore;
alshabibb5522ff2014-09-29 19:20:00 -070053import org.slf4j.Logger;
54
Jonathan Hart6cd2f352015-01-13 17:44:45 -080055import java.nio.ByteBuffer;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080056import java.util.Set;
57
58import static com.google.common.base.Preconditions.checkArgument;
59import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070060import static org.onlab.packet.VlanId.vlanId;
61import static org.onosproject.net.HostId.hostId;
Changhoon Yoon541ef712015-05-23 17:18:34 +090062import static org.onosproject.security.AppGuard.checkPermission;
Aaron Kruglikovd8123832015-07-06 14:20:25 -070063import static org.slf4j.LoggerFactory.getLogger;
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 Yoon541ef712015-05-23 17:18:34 +0900113 checkPermission(Permission.PACKET_READ);
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700114 checkNotNull(addr, MAC_ADDR_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700115 Set<Host> hosts = hostService.getHostsByIp(addr);
116 return !hosts.isEmpty();
117 }
118
119 @Override
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700120 public void reply(Ethernet eth, ConnectPoint inPort) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900121 checkPermission(Permission.PACKET_WRITE);
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700122 checkNotNull(eth, REQUEST_NULL);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800123
124 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
125 replyArp(eth, inPort);
126 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
127 replyNdp(eth, inPort);
128 }
129 }
130
131 private void replyArp(Ethernet eth, ConnectPoint inPort) {
alshabibb5522ff2014-09-29 19:20:00 -0700132 ARP arp = (ARP) eth.getPayload();
133 checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700134 checkNotNull(inPort);
Dusan Pajina22b9702015-02-12 16:25:23 +0100135 Ip4Address targetAddress = Ip4Address.valueOf(arp.getTargetProtocolAddress());
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700136
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700137 VlanId vlan = vlanId(eth.getVlanID());
Jonathan Hart6cd2f352015-01-13 17:44:45 -0800138
Jonathan Hart4cb39882015-08-12 23:50:55 -0400139 if (hasIpAddress(inPort)) {
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700140 // If the request came from outside the network, only reply if it was
141 // for one of our external addresses.
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700142
Jonathan Hart4cb39882015-08-12 23:50:55 -0400143 interfaceService.getInterfacesByPort(inPort)
144 .stream()
145 .filter(intf -> intf.ipAddresses()
146 .stream()
147 .anyMatch(ia -> ia.ipAddress().equals(targetAddress)))
148 .forEach(intf -> buildAndSendArp(targetAddress, intf.mac(), eth, inPort));
149
150 // Stop here and don't proxy ARPs if the port has an IP address
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700151 return;
152 }
153
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700154 // See if we have the target host in the host store
alshabibb5522ff2014-09-29 19:20:00 -0700155
Dusan Pajina22b9702015-02-12 16:25:23 +0100156 Set<Host> hosts = hostService.getHostsByIp(targetAddress);
alshabibb5522ff2014-09-29 19:20:00 -0700157
158 Host dst = null;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700159 Host src = hostService.getHost(hostId(eth.getSourceMAC(),
Jonathan Hart4cb39882015-08-12 23:50:55 -0400160 vlanId(eth.getVlanID())));
alshabibb5522ff2014-09-29 19:20:00 -0700161
162 for (Host host : hosts) {
163 if (host.vlan().equals(vlan)) {
164 dst = host;
165 break;
166 }
167 }
168
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700169 if (src != null && dst != null) {
170 // We know the target host so we can respond
Jonathan Hart4cb39882015-08-12 23:50:55 -0400171 buildAndSendArp(targetAddress, dst.mac(), eth, inPort);
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700172 return;
173 }
174
175 // If the source address matches one of our external addresses
176 // it could be a request from an internal host to an external
177 // address. Forward it over to the correct port.
178 Ip4Address source =
179 Ip4Address.valueOf(arp.getSenderProtocolAddress());
Jonathan Hart4cb39882015-08-12 23:50:55 -0400180
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700181 boolean matched = false;
Jonathan Hart4cb39882015-08-12 23:50:55 -0400182 Set<Interface> interfaces = interfaceService.getInterfacesByIp(source);
183 for (Interface intf : interfaces) {
184 if (intf.vlan().equals(vlan)) {
185 matched = true;
186 sendTo(eth, intf.connectPoint());
187 break;
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700188 }
189 }
190
191 if (matched) {
alshabibb5522ff2014-09-29 19:20:00 -0700192 return;
193 }
194
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700195 // The request couldn't be resolved.
196 // Flood the request on all ports except the incoming port.
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700197 flood(eth, inPort);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700198 }
199
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800200 private void replyNdp(Ethernet eth, ConnectPoint inPort) {
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800201 IPv6 ipv6 = (IPv6) eth.getPayload();
202 ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
203 NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload();
Dusan Pajina22b9702015-02-12 16:25:23 +0100204 Ip6Address targetAddress = Ip6Address.valueOf(nsol.getTargetAddress());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800205
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700206 VlanId vlan = vlanId(eth.getVlanID());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800207
208 // If the request came from outside the network, only reply if it was
209 // for one of our external addresses.
Jonathan Hart4cb39882015-08-12 23:50:55 -0400210 if (hasIpAddress(inPort)) {
211 interfaceService.getInterfacesByPort(inPort)
212 .stream()
213 .filter(intf -> intf.ipAddresses()
214 .stream()
215 .anyMatch(ia -> ia.ipAddress().equals(targetAddress)))
216 .forEach(intf -> buildAndSendNdp(targetAddress, intf.mac(), eth, inPort));
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800217 return;
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800218 }
219
220 // Continue with normal proxy ARP case
221
Dusan Pajina22b9702015-02-12 16:25:23 +0100222 Set<Host> hosts = hostService.getHostsByIp(targetAddress);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800223
224 Host dst = null;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700225 Host src = hostService.getHost(hostId(eth.getSourceMAC(),
226 vlanId(eth.getVlanID())));
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800227
228 for (Host host : hosts) {
229 if (host.vlan().equals(vlan)) {
230 dst = host;
231 break;
232 }
233 }
234
Jonathan Hart4cb39882015-08-12 23:50:55 -0400235 if (src != null || dst != null) {
236 // We know the target host so we can respond
237 buildAndSendNdp(targetAddress, dst.mac(), eth, inPort);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800238 return;
239 }
240
Jonathan Hart4cb39882015-08-12 23:50:55 -0400241 // If the source address matches one of our external addresses
242 // it could be a request from an internal host to an external
243 // address. Forward it over to the correct port.
244 Ip6Address source =
245 Ip6Address.valueOf(ipv6.getSourceAddress());
246
247 boolean matched = false;
248
249 Set<Interface> interfaces = interfaceService.getInterfacesByIp(source);
250 for (Interface intf : interfaces) {
251 if (intf.vlan().equals(vlan)) {
252 matched = true;
253 sendTo(eth, intf.connectPoint());
254 break;
255 }
256 }
257
258 if (matched) {
259 return;
260 }
261
262 // The request couldn't be resolved.
263 // Flood the request on all ports except the incoming ports.
264 flood(eth, inPort);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800265 }
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700266 //TODO checkpoint
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800267
Jonathan Hart4cb39882015-08-12 23:50:55 -0400268 private void buildAndSendArp(Ip4Address srcIp, MacAddress srcMac,
269 Ethernet request, ConnectPoint port) {
270 sendTo(ARP.buildArpReply(srcIp, srcMac, request), port);
271 }
272
273 private void buildAndSendNdp(Ip6Address srcIp, MacAddress srcMac,
274 Ethernet request, ConnectPoint port) {
275 sendTo(buildNdpReply(srcIp, srcMac, request), port);
276 }
277
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700278 /**
279 * Outputs the given packet out the given port.
280 *
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700281 * @param packet the packet to send
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700282 * @param outPort the port to send it out
283 */
284 private void sendTo(Ethernet packet, ConnectPoint outPort) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700285 sendTo(outPort, ByteBuffer.wrap(packet.serialize()));
286 }
287
288 private void sendTo(ConnectPoint outPort, ByteBuffer packet) {
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700289 if (!edgeService.isEdgePoint(outPort)) {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700290 // Sanity check to make sure we don't send the packet out an
291 // internal port and create a loop (could happen due to
292 // misconfiguration).
293 return;
294 }
295
tom9a693fd2014-10-03 11:32:19 -0700296 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700297 builder.setOutput(outPort.port());
298 packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700299 builder.build(), packet));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700300 }
301
302 /**
Jonathan Hart4cb39882015-08-12 23:50:55 -0400303 * Returns whether the given port has any IP addresses configured or not.
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700304 *
305 * @param port the port to check
Jonathan Hart4cb39882015-08-12 23:50:55 -0400306 * @return true if the port has at least one IP address configured,
307 * otherwise false
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700308 */
Jonathan Hart4cb39882015-08-12 23:50:55 -0400309 private boolean hasIpAddress(ConnectPoint port) {
310 return interfaceService.getInterfacesByPort(port)
311 .stream()
312 .map(intf -> intf.ipAddresses())
313 .findAny()
314 .isPresent();
alshabibb5522ff2014-09-29 19:20:00 -0700315 }
316
317 @Override
Jonathan Hartf84591d2015-01-16 14:33:43 -0800318 public void forward(Ethernet eth, ConnectPoint inPort) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900319 checkPermission(Permission.PACKET_WRITE);
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700320 checkNotNull(eth, REQUEST_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700321
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700322 Host h = hostService.getHost(hostId(eth.getDestinationMAC(),
323 vlanId(eth.getVlanID())));
alshabibb5522ff2014-09-29 19:20:00 -0700324
325 if (h == null) {
Jonathan Hartf84591d2015-01-16 14:33:43 -0800326 flood(eth, inPort);
alshabibb5522ff2014-09-29 19:20:00 -0700327 } else {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700328 Host subject = hostService.getHost(hostId(eth.getSourceMAC(),
329 vlanId(eth.getVlanID())));
330 store.forward(h.location(), subject, ByteBuffer.wrap(eth.serialize()));
alshabibb5522ff2014-09-29 19:20:00 -0700331 }
alshabibb5522ff2014-09-29 19:20:00 -0700332 }
333
alshabibc274c902014-10-03 14:58:27 -0700334 @Override
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800335 public boolean handlePacket(PacketContext context) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900336 checkPermission(Permission.PACKET_WRITE);
337
alshabibc274c902014-10-03 14:58:27 -0700338 InboundPacket pkt = context.inPacket();
339 Ethernet ethPkt = pkt.parsed();
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800340
341 if (ethPkt == null) {
342 return false;
343 }
344 if (ethPkt.getEtherType() == Ethernet.TYPE_ARP) {
345 return handleArp(context, ethPkt);
346 } else if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) {
347 return handleNdp(context, ethPkt);
alshabibc274c902014-10-03 14:58:27 -0700348 }
349 return false;
350 }
351
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800352 private boolean handleArp(PacketContext context, Ethernet ethPkt) {
353 ARP arp = (ARP) ethPkt.getPayload();
354
355 if (arp.getOpCode() == ARP.OP_REPLY) {
356 forward(ethPkt, context.inPacket().receivedFrom());
357 } else if (arp.getOpCode() == ARP.OP_REQUEST) {
358 reply(ethPkt, context.inPacket().receivedFrom());
359 } else {
360 return false;
361 }
362 context.block();
363 return true;
364 }
365
366 private boolean handleNdp(PacketContext context, Ethernet ethPkt) {
367 IPv6 ipv6 = (IPv6) ethPkt.getPayload();
368
369 if (ipv6.getNextHeader() != IPv6.PROTOCOL_ICMP6) {
370 return false;
371 }
372 ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
373 if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) {
374 forward(ethPkt, context.inPacket().receivedFrom());
375 } else if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) {
376 reply(ethPkt, context.inPacket().receivedFrom());
377 } else {
378 return false;
379 }
380 context.block();
381 return true;
382 }
383
alshabibb5522ff2014-09-29 19:20:00 -0700384 /**
385 * Flood the arp request at all edges in the network.
Dusan Pajina22b9702015-02-12 16:25:23 +0100386 *
387 * @param request the arp request
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700388 * @param inPort the connect point the arp request was received on
alshabibb5522ff2014-09-29 19:20:00 -0700389 */
Jonathan Hartf84591d2015-01-16 14:33:43 -0800390 private void flood(Ethernet request, ConnectPoint inPort) {
alshabibb5522ff2014-09-29 19:20:00 -0700391 TrafficTreatment.Builder builder = null;
392 ByteBuffer buf = ByteBuffer.wrap(request.serialize());
393
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700394 for (ConnectPoint connectPoint : edgeService.getEdgePoints()) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400395 if (hasIpAddress(connectPoint) || connectPoint.equals(inPort)) {
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700396 continue;
397 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700398
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700399 builder = DefaultTrafficTreatment.builder();
400 builder.setOutput(connectPoint.port());
401 packetService.emit(new DefaultOutboundPacket(connectPoint.deviceId(),
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700402 builder.build(), buf));
alshabibb5522ff2014-09-29 19:20:00 -0700403 }
alshabibb5522ff2014-09-29 19:20:00 -0700404 }
405
alshabibb5522ff2014-09-29 19:20:00 -0700406 /**
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800407 * Builds an Neighbor Discovery reply based on a request.
408 *
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700409 * @param srcIp the IP address to use as the reply source
410 * @param srcMac the MAC address to use as the reply source
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800411 * @param request the Neighbor Solicitation request we got
412 * @return an Ethernet frame containing the Neighbor Advertisement reply
413 */
414 private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac,
415 Ethernet request) {
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800416 Ethernet eth = new Ethernet();
417 eth.setDestinationMACAddress(request.getSourceMAC());
418 eth.setSourceMACAddress(srcMac);
419 eth.setEtherType(Ethernet.TYPE_IPV6);
420 eth.setVlanID(request.getVlanID());
421
422 IPv6 requestIp = (IPv6) request.getPayload();
423 IPv6 ipv6 = new IPv6();
424 ipv6.setSourceAddress(srcIp.toOctets());
425 ipv6.setDestinationAddress(requestIp.getSourceAddress());
426 ipv6.setHopLimit((byte) 255);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800427
428 ICMP6 icmp6 = new ICMP6();
429 icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT);
430 icmp6.setIcmpCode((byte) 0);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800431
432 NeighborAdvertisement nadv = new NeighborAdvertisement();
Dusan Pajina22b9702015-02-12 16:25:23 +0100433 nadv.setTargetAddress(srcIp.toOctets());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800434 nadv.setSolicitedFlag((byte) 1);
435 nadv.setOverrideFlag((byte) 1);
Pavlin Radoslavova2626ef2015-02-18 18:33:25 -0800436 nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS,
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700437 srcMac.toBytes());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800438
Pavlin Radoslavova2626ef2015-02-18 18:33:25 -0800439 icmp6.setPayload(nadv);
Dusan Pajina22b9702015-02-12 16:25:23 +0100440 ipv6.setPayload(icmp6);
441 eth.setPayload(ipv6);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800442 return eth;
443 }
alshabibb5522ff2014-09-29 19:20:00 -0700444}