blob: b5acde64772d7c7aa995791345a31563e35c0ba5 [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;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.ConnectPoint;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.Host;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.device.DeviceService;
Aaron Kruglikovd8123832015-07-06 14:20:25 -070040import org.onosproject.net.edge.EdgePortService;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficTreatment;
43import org.onosproject.net.host.HostService;
44import org.onosproject.net.host.InterfaceIpAddress;
45import org.onosproject.net.host.PortAddresses;
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;
56import java.util.HashSet;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080057import java.util.Set;
Aaron Kruglikovd8123832015-07-06 14:20:25 -070058import java.util.stream.Collectors;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080059
60import static com.google.common.base.Preconditions.checkArgument;
61import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070062import static org.onlab.packet.VlanId.vlanId;
63import static org.onosproject.net.HostId.hostId;
Changhoon Yoon541ef712015-05-23 17:18:34 +090064import static org.onosproject.security.AppGuard.checkPermission;
Aaron Kruglikovd8123832015-07-06 14:20:25 -070065import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoon541ef712015-05-23 17:18:34 +090066
alshabibb5522ff2014-09-29 19:20:00 -070067
alshabibb5522ff2014-09-29 19:20:00 -070068@Component(immediate = true)
69@Service
70public class ProxyArpManager implements ProxyArpService {
71
72 private final Logger log = getLogger(getClass());
73
74 private static final String MAC_ADDR_NULL = "Mac address cannot be null.";
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -080075 private static final String REQUEST_NULL = "ARP or NDP request cannot be null.";
alshabibb5522ff2014-09-29 19:20:00 -070076 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.";
Jonathan Hart704ca142014-10-09 09:34:39 -070078 private static final String NOT_ARP_REPLY = "ARP is not a reply.";
alshabibb5522ff2014-09-29 19:20:00 -070079
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Aaron Kruglikovd8123832015-07-06 14:20:25 -070081 protected EdgePortService edgeService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb5522ff2014-09-29 19:20:00 -070084 protected HostService hostService;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected PacketService packetService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected LinkService linkService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected DeviceService deviceService;
94
Thomas Vachuskab2c47a72015-08-05 14:22:54 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected ProxyArpStore store;
97
alshabibb5522ff2014-09-29 19:20:00 -070098 /**
99 * Listens to both device service and link service to determine
100 * whether a port is internal or external.
101 */
102 @Activate
103 public void activate() {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700104 store.setDelegate(this::sendTo);
alshabibb5522ff2014-09-29 19:20:00 -0700105 log.info("Started");
106 }
107
108
109 @Deactivate
110 public void deactivate() {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700111 store.setDelegate(null);
alshabibb5522ff2014-09-29 19:20:00 -0700112 log.info("Stopped");
113 }
114
115 @Override
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800116 public boolean isKnown(IpAddress addr) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900117 checkPermission(Permission.PACKET_READ);
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700118 checkNotNull(addr, MAC_ADDR_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700119 Set<Host> hosts = hostService.getHostsByIp(addr);
120 return !hosts.isEmpty();
121 }
122
123 @Override
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700124 public void reply(Ethernet eth, ConnectPoint inPort) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900125 checkPermission(Permission.PACKET_WRITE);
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700126 checkNotNull(eth, REQUEST_NULL);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800127
128 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
129 replyArp(eth, inPort);
130 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
131 replyNdp(eth, inPort);
132 }
133 }
134
135 private void replyArp(Ethernet eth, ConnectPoint inPort) {
alshabibb5522ff2014-09-29 19:20:00 -0700136 ARP arp = (ARP) eth.getPayload();
137 checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700138 checkNotNull(inPort);
Dusan Pajina22b9702015-02-12 16:25:23 +0100139 Ip4Address targetAddress = Ip4Address.valueOf(arp.getTargetProtocolAddress());
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700140
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700141 VlanId vlan = vlanId(eth.getVlanID());
Jonathan Hart6cd2f352015-01-13 17:44:45 -0800142
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700143 if (isOutsidePort(inPort)) {
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700144 // If the request came from outside the network, only reply if it was
145 // for one of our external addresses.
Jonathan Harta887ba82014-11-03 15:20:52 -0800146 Set<PortAddresses> addressSet =
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700147 hostService.getAddressBindingsForPort(inPort);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700148
Jonathan Harta887ba82014-11-03 15:20:52 -0800149 for (PortAddresses addresses : addressSet) {
150 for (InterfaceIpAddress ia : addresses.ipAddresses()) {
Dusan Pajina22b9702015-02-12 16:25:23 +0100151 if (ia.ipAddress().equals(targetAddress)) {
Jonathan Harta887ba82014-11-03 15:20:52 -0800152 Ethernet arpReply =
Pingping Linc9e16bf2015-04-10 14:42:41 -0700153 ARP.buildArpReply(targetAddress, addresses.mac(), eth);
Jonathan Harta887ba82014-11-03 15:20:52 -0800154 sendTo(arpReply, inPort);
155 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700156 }
157 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700158 return;
159 }
160
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700161 // See if we have the target host in the host store
alshabibb5522ff2014-09-29 19:20:00 -0700162
Dusan Pajina22b9702015-02-12 16:25:23 +0100163 Set<Host> hosts = hostService.getHostsByIp(targetAddress);
alshabibb5522ff2014-09-29 19:20:00 -0700164
165 Host dst = null;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700166 Host src = hostService.getHost(hostId(eth.getSourceMAC(),
167 vlanId(eth.getVlanID())));
alshabibb5522ff2014-09-29 19:20:00 -0700168
169 for (Host host : hosts) {
170 if (host.vlan().equals(vlan)) {
171 dst = host;
172 break;
173 }
174 }
175
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700176 if (src != null && dst != null) {
177 // We know the target host so we can respond
Pingping Linc9e16bf2015-04-10 14:42:41 -0700178 Ethernet arpReply = ARP.buildArpReply(targetAddress, dst.mac(), eth);
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700179 sendTo(arpReply, inPort);
180 return;
181 }
182
183 // If the source address matches one of our external addresses
184 // it could be a request from an internal host to an external
185 // address. Forward it over to the correct port.
186 Ip4Address source =
187 Ip4Address.valueOf(arp.getSenderProtocolAddress());
188 Set<PortAddresses> sourceAddresses = findPortsInSubnet(source);
189 boolean matched = false;
190 for (PortAddresses pa : sourceAddresses) {
191 for (InterfaceIpAddress ia : pa.ipAddresses()) {
192 if (ia.ipAddress().equals(source) &&
193 pa.vlan().equals(vlan)) {
194 matched = true;
195 sendTo(eth, pa.connectPoint());
196 break;
197 }
198 }
199 }
200
201 if (matched) {
alshabibb5522ff2014-09-29 19:20:00 -0700202 return;
203 }
204
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800205 //
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700206 // The request couldn't be resolved.
207 // Flood the request on all ports except the incoming port.
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800208 //
Jonathan Hart7d1496b2015-03-10 22:00:48 -0700209 flood(eth, inPort);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700210 }
211
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800212 private void replyNdp(Ethernet eth, ConnectPoint inPort) {
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800213 IPv6 ipv6 = (IPv6) eth.getPayload();
214 ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
215 NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload();
Dusan Pajina22b9702015-02-12 16:25:23 +0100216 Ip6Address targetAddress = Ip6Address.valueOf(nsol.getTargetAddress());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800217
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700218 VlanId vlan = vlanId(eth.getVlanID());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800219
220 // If the request came from outside the network, only reply if it was
221 // for one of our external addresses.
222 if (isOutsidePort(inPort)) {
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800223 Set<PortAddresses> addressSet =
224 hostService.getAddressBindingsForPort(inPort);
225
226 for (PortAddresses addresses : addressSet) {
227 for (InterfaceIpAddress ia : addresses.ipAddresses()) {
Dusan Pajina22b9702015-02-12 16:25:23 +0100228 if (ia.ipAddress().equals(targetAddress)) {
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800229 Ethernet ndpReply =
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700230 buildNdpReply(targetAddress, addresses.mac(), eth);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800231 sendTo(ndpReply, inPort);
232 }
233 }
234 }
235 return;
236 } else {
237 // If the source address matches one of our external addresses
238 // it could be a request from an internal host to an external
239 // address. Forward it over to the correct ports.
240 Ip6Address source =
Pavlin Radoslavovcef52062015-02-12 16:57:17 -0800241 Ip6Address.valueOf(ipv6.getSourceAddress());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800242 Set<PortAddresses> sourceAddresses = findPortsInSubnet(source);
243 boolean matched = false;
244 for (PortAddresses pa : sourceAddresses) {
245 for (InterfaceIpAddress ia : pa.ipAddresses()) {
246 if (ia.ipAddress().equals(source) &&
247 pa.vlan().equals(vlan)) {
248 matched = true;
249 sendTo(eth, pa.connectPoint());
Pavlin Radoslavovcef52062015-02-12 16:57:17 -0800250 break;
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800251 }
252 }
253 }
254
255 if (matched) {
256 return;
257 }
258 }
259
260 // Continue with normal proxy ARP case
261
Dusan Pajina22b9702015-02-12 16:25:23 +0100262 Set<Host> hosts = hostService.getHostsByIp(targetAddress);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800263
264 Host dst = null;
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700265 Host src = hostService.getHost(hostId(eth.getSourceMAC(),
266 vlanId(eth.getVlanID())));
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800267
268 for (Host host : hosts) {
269 if (host.vlan().equals(vlan)) {
270 dst = host;
271 break;
272 }
273 }
274
275 if (src == null || dst == null) {
Dusan Pajina22b9702015-02-12 16:25:23 +0100276 //
277 // The request couldn't be resolved.
278 // Flood the request on all ports except the incoming ports.
279 //
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800280 flood(eth, inPort);
281 return;
282 }
283
284 //
Dusan Pajina22b9702015-02-12 16:25:23 +0100285 // Reply on the port the request was received on
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800286 //
Dusan Pajina22b9702015-02-12 16:25:23 +0100287 Ethernet ndpReply = buildNdpReply(targetAddress, dst.mac(), eth);
288 sendTo(ndpReply, inPort);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800289 }
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700290 //TODO checkpoint
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800291
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700292 /**
293 * Outputs the given packet out the given port.
294 *
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700295 * @param packet the packet to send
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700296 * @param outPort the port to send it out
297 */
298 private void sendTo(Ethernet packet, ConnectPoint outPort) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700299 sendTo(outPort, ByteBuffer.wrap(packet.serialize()));
300 }
301
302 private void sendTo(ConnectPoint outPort, ByteBuffer packet) {
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700303 if (!edgeService.isEdgePoint(outPort)) {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700304 // Sanity check to make sure we don't send the packet out an
305 // internal port and create a loop (could happen due to
306 // misconfiguration).
307 return;
308 }
309
tom9a693fd2014-10-03 11:32:19 -0700310 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700311 builder.setOutput(outPort.port());
312 packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700313 builder.build(), packet));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700314 }
315
316 /**
Jonathan Hart1f793a72014-11-12 23:22:02 -0800317 * Finds ports with an address in the subnet of the target address.
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700318 *
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700319 * @param target the target address to find a matching port for
Jonathan Hart1f793a72014-11-12 23:22:02 -0800320 * @return a set of PortAddresses describing ports in the subnet
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700321 */
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800322 private Set<PortAddresses> findPortsInSubnet(IpAddress target) {
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700323 Set<PortAddresses> result = new HashSet<>();
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700324 for (PortAddresses addresses : hostService.getAddressBindings()) {
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700325 result.addAll(addresses.ipAddresses().stream().filter(ia -> ia.subnetAddress().contains(target)).
326 map(ia -> addresses).collect(Collectors.toList()));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700327 }
Jonathan Hart1f793a72014-11-12 23:22:02 -0800328 return result;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700329 }
330
331 /**
332 * Returns whether the given port is an outside-facing port with an IP
333 * address configured.
334 *
335 * @param port the port to check
336 * @return true if the port is an outside-facing port, otherwise false
337 */
338 private boolean isOutsidePort(ConnectPoint port) {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700339 // TODO: Is this sufficient to identify outside-facing ports: just having IP addresses on a port?
Jonathan Harta887ba82014-11-03 15:20:52 -0800340 return !hostService.getAddressBindingsForPort(port).isEmpty();
alshabibb5522ff2014-09-29 19:20:00 -0700341 }
342
343 @Override
Jonathan Hartf84591d2015-01-16 14:33:43 -0800344 public void forward(Ethernet eth, ConnectPoint inPort) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900345 checkPermission(Permission.PACKET_WRITE);
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700346 checkNotNull(eth, REQUEST_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700347
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700348 Host h = hostService.getHost(hostId(eth.getDestinationMAC(),
349 vlanId(eth.getVlanID())));
alshabibb5522ff2014-09-29 19:20:00 -0700350
351 if (h == null) {
Jonathan Hartf84591d2015-01-16 14:33:43 -0800352 flood(eth, inPort);
alshabibb5522ff2014-09-29 19:20:00 -0700353 } else {
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700354 Host subject = hostService.getHost(hostId(eth.getSourceMAC(),
355 vlanId(eth.getVlanID())));
356 store.forward(h.location(), subject, ByteBuffer.wrap(eth.serialize()));
alshabibb5522ff2014-09-29 19:20:00 -0700357 }
alshabibb5522ff2014-09-29 19:20:00 -0700358 }
359
alshabibc274c902014-10-03 14:58:27 -0700360 @Override
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800361 public boolean handlePacket(PacketContext context) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900362 checkPermission(Permission.PACKET_WRITE);
363
alshabibc274c902014-10-03 14:58:27 -0700364 InboundPacket pkt = context.inPacket();
365 Ethernet ethPkt = pkt.parsed();
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800366
367 if (ethPkt == null) {
368 return false;
369 }
370 if (ethPkt.getEtherType() == Ethernet.TYPE_ARP) {
371 return handleArp(context, ethPkt);
372 } else if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) {
373 return handleNdp(context, ethPkt);
alshabibc274c902014-10-03 14:58:27 -0700374 }
375 return false;
376 }
377
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800378 private boolean handleArp(PacketContext context, Ethernet ethPkt) {
379 ARP arp = (ARP) ethPkt.getPayload();
380
381 if (arp.getOpCode() == ARP.OP_REPLY) {
382 forward(ethPkt, context.inPacket().receivedFrom());
383 } else if (arp.getOpCode() == ARP.OP_REQUEST) {
384 reply(ethPkt, context.inPacket().receivedFrom());
385 } else {
386 return false;
387 }
388 context.block();
389 return true;
390 }
391
392 private boolean handleNdp(PacketContext context, Ethernet ethPkt) {
393 IPv6 ipv6 = (IPv6) ethPkt.getPayload();
394
395 if (ipv6.getNextHeader() != IPv6.PROTOCOL_ICMP6) {
396 return false;
397 }
398 ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
399 if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) {
400 forward(ethPkt, context.inPacket().receivedFrom());
401 } else if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) {
402 reply(ethPkt, context.inPacket().receivedFrom());
403 } else {
404 return false;
405 }
406 context.block();
407 return true;
408 }
409
alshabibb5522ff2014-09-29 19:20:00 -0700410 /**
411 * Flood the arp request at all edges in the network.
Dusan Pajina22b9702015-02-12 16:25:23 +0100412 *
413 * @param request the arp request
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700414 * @param inPort the connect point the arp request was received on
alshabibb5522ff2014-09-29 19:20:00 -0700415 */
Jonathan Hartf84591d2015-01-16 14:33:43 -0800416 private void flood(Ethernet request, ConnectPoint inPort) {
alshabibb5522ff2014-09-29 19:20:00 -0700417 TrafficTreatment.Builder builder = null;
418 ByteBuffer buf = ByteBuffer.wrap(request.serialize());
419
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700420 for (ConnectPoint connectPoint : edgeService.getEdgePoints()) {
421 if (isOutsidePort(connectPoint) || connectPoint.equals(inPort)) {
422 continue;
423 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700424
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700425 builder = DefaultTrafficTreatment.builder();
426 builder.setOutput(connectPoint.port());
427 packetService.emit(new DefaultOutboundPacket(connectPoint.deviceId(),
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700428 builder.build(), buf));
alshabibb5522ff2014-09-29 19:20:00 -0700429 }
430
431 }
432
alshabibb5522ff2014-09-29 19:20:00 -0700433 /**
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800434 * Builds an Neighbor Discovery reply based on a request.
435 *
Aaron Kruglikovd8123832015-07-06 14:20:25 -0700436 * @param srcIp the IP address to use as the reply source
437 * @param srcMac the MAC address to use as the reply source
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800438 * @param request the Neighbor Solicitation request we got
439 * @return an Ethernet frame containing the Neighbor Advertisement reply
440 */
441 private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac,
442 Ethernet request) {
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800443 Ethernet eth = new Ethernet();
444 eth.setDestinationMACAddress(request.getSourceMAC());
445 eth.setSourceMACAddress(srcMac);
446 eth.setEtherType(Ethernet.TYPE_IPV6);
447 eth.setVlanID(request.getVlanID());
448
449 IPv6 requestIp = (IPv6) request.getPayload();
450 IPv6 ipv6 = new IPv6();
451 ipv6.setSourceAddress(srcIp.toOctets());
452 ipv6.setDestinationAddress(requestIp.getSourceAddress());
453 ipv6.setHopLimit((byte) 255);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800454
455 ICMP6 icmp6 = new ICMP6();
456 icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT);
457 icmp6.setIcmpCode((byte) 0);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800458
459 NeighborAdvertisement nadv = new NeighborAdvertisement();
Dusan Pajina22b9702015-02-12 16:25:23 +0100460 nadv.setTargetAddress(srcIp.toOctets());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800461 nadv.setSolicitedFlag((byte) 1);
462 nadv.setOverrideFlag((byte) 1);
Pavlin Radoslavova2626ef2015-02-18 18:33:25 -0800463 nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS,
Thomas Vachuskab2c47a72015-08-05 14:22:54 -0700464 srcMac.toBytes());
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800465
Pavlin Radoslavova2626ef2015-02-18 18:33:25 -0800466 icmp6.setPayload(nadv);
Dusan Pajina22b9702015-02-12 16:25:23 +0100467 ipv6.setPayload(icmp6);
468 eth.setPayload(ipv6);
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800469 return eth;
470 }
alshabibb5522ff2014-09-29 19:20:00 -0700471}