blob: 23bbf0734358632b71556c27c18b54c290210c7f [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
sanghob35a6192015-04-01 13:05:26 -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 */
16package org.onosproject.segmentrouting;
17
sanghob35a6192015-04-01 13:05:26 -070018import org.onlab.packet.Ethernet;
19import org.onlab.packet.ICMP;
Pier Ventre735b8c82016-12-02 08:16:05 -080020import org.onlab.packet.ICMP6;
sanghob35a6192015-04-01 13:05:26 -070021import org.onlab.packet.IPv4;
Pier Ventre735b8c82016-12-02 08:16:05 -080022import org.onlab.packet.IPv6;
sanghob35a6192015-04-01 13:05:26 -070023import org.onlab.packet.Ip4Address;
Pier Ventref4b5fce2016-11-28 16:48:06 -080024import org.onlab.packet.Ip6Address;
Pier Ventree0ae7a32016-11-23 09:57:42 -080025import org.onlab.packet.IpAddress;
sanghob35a6192015-04-01 13:05:26 -070026import org.onlab.packet.MPLS;
Pier Ventref4b5fce2016-11-28 16:48:06 -080027import org.onlab.packet.MacAddress;
28import org.onlab.packet.VlanId;
Pier Ventre735b8c82016-12-02 08:16:05 -080029import org.onlab.packet.ndp.NeighborSolicitation;
Ray Milkeyb65d7842017-08-03 16:28:24 -070030import org.onosproject.net.neighbour.NeighbourMessageContext;
31import org.onosproject.net.neighbour.NeighbourMessageType;
sanghob35a6192015-04-01 13:05:26 -070032import org.onosproject.net.ConnectPoint;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficTreatment;
Pier Ventref4b5fce2016-11-28 16:48:06 -080036import org.onosproject.net.host.HostService;
sanghob35a6192015-04-01 13:05:26 -070037import org.onosproject.net.packet.DefaultOutboundPacket;
sanghob35a6192015-04-01 13:05:26 -070038import org.onosproject.net.packet.OutboundPacket;
Charles Chan0b4e6182015-11-03 10:42:14 -080039import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
Pier Ventref4b5fce2016-11-28 16:48:06 -080040import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
sanghob35a6192015-04-01 13:05:26 -070041import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
Jonathan Hart2a655752015-04-07 16:46:33 -070044import java.nio.ByteBuffer;
Charles Chan0ed44fb2017-03-13 13:10:30 -070045import java.util.Arrays;
Charles Chan40abef42017-06-02 19:23:51 -070046import java.util.Optional;
Saurav Das837e0bb2015-10-30 17:45:38 -070047import java.util.Set;
Jonathan Hart2a655752015-04-07 16:46:33 -070048
Charles Chane849c192016-01-11 18:28:54 -080049/**
50 * Handler of ICMP packets that responses or forwards ICMP packets that
51 * are sent to the controller.
52 */
Pier Ventre735b8c82016-12-02 08:16:05 -080053public class IcmpHandler extends SegmentRoutingNeighbourHandler {
sanghob35a6192015-04-01 13:05:26 -070054
55 private static Logger log = LoggerFactory.getLogger(IcmpHandler.class);
sanghob35a6192015-04-01 13:05:26 -070056
57 /**
58 * Creates an IcmpHandler object.
59 *
60 * @param srManager SegmentRoutingManager object
61 */
62 public IcmpHandler(SegmentRoutingManager srManager) {
Pier Ventre735b8c82016-12-02 08:16:05 -080063 super(srManager);
64 }
65
66 /**
67 * Utility function to send packet out.
68 *
69 * @param outport the output port
70 * @param payload the packet to send
71 * @param sid the segment id
72 * @param destIpAddress the destination ip address
73 * @param allowedHops the hop limit/ttl
74 */
75 private void sendPacketOut(ConnectPoint outport,
76 Ethernet payload,
77 int sid,
78 IpAddress destIpAddress,
79 byte allowedHops) {
80 int destSid;
81 if (destIpAddress.isIp4()) {
82 destSid = config.getIPv4SegmentId(payload.getDestinationMAC());
83 } else {
84 destSid = config.getIPv6SegmentId(payload.getDestinationMAC());
85 }
86
87 if (sid == -1 || destSid == sid ||
88 config.inSameSubnet(outport.deviceId(), destIpAddress)) {
89 TrafficTreatment treatment = DefaultTrafficTreatment.builder().
90 setOutput(outport.port()).build();
91 OutboundPacket packet = new DefaultOutboundPacket(outport.deviceId(),
92 treatment, ByteBuffer.wrap(payload.serialize()));
93 srManager.packetService.emit(packet);
94 } else {
Saurav Dasceccf242017-08-03 18:30:35 -070095 log.trace("Send a MPLS packet as a ICMP response");
Pier Ventre735b8c82016-12-02 08:16:05 -080096 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
97 .setOutput(outport.port())
98 .build();
99
100 payload.setEtherType(Ethernet.MPLS_UNICAST);
101 MPLS mplsPkt = new MPLS();
102 mplsPkt.setLabel(sid);
103 mplsPkt.setTtl(allowedHops);
104 mplsPkt.setPayload(payload.getPayload());
105 payload.setPayload(mplsPkt);
106
107 OutboundPacket packet = new DefaultOutboundPacket(outport.deviceId(),
108 treatment, ByteBuffer.wrap(payload.serialize()));
109
110 srManager.packetService.emit(packet);
111 }
sanghob35a6192015-04-01 13:05:26 -0700112 }
113
Pier Ventref4b5fce2016-11-28 16:48:06 -0800114 //////////////////////////////////////
115 // ICMP Echo/Reply Protocol //
116 //////////////////////////////////////
117
sanghob35a6192015-04-01 13:05:26 -0700118 /**
119 * Process incoming ICMP packet.
Charles Chand4f3a622017-03-29 17:24:39 -0700120 * If it is an ICMP request to router, then sends an ICMP response.
121 * Otherwise ignore the packet.
sanghob35a6192015-04-01 13:05:26 -0700122 *
Pier Ventre735b8c82016-12-02 08:16:05 -0800123 * @param eth inbound ICMP packet
124 * @param inPort the input port
sanghob35a6192015-04-01 13:05:26 -0700125 */
Pier Ventre735b8c82016-12-02 08:16:05 -0800126 public void processIcmp(Ethernet eth, ConnectPoint inPort) {
127 DeviceId deviceId = inPort.deviceId();
128 IPv4 ipv4Packet = (IPv4) eth.getPayload();
129 Ip4Address destinationAddress = Ip4Address.valueOf(ipv4Packet.getDestinationAddress());
Pier Ventre10bd8d12016-11-26 21:05:22 -0800130 Set<IpAddress> gatewayIpAddresses = config.getPortIPs(deviceId);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800131 IpAddress routerIp;
Charles Chan0b4e6182015-11-03 10:42:14 -0800132 try {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800133 routerIp = config.getRouterIpv4(deviceId);
Charles Chan0b4e6182015-11-03 10:42:14 -0800134 } catch (DeviceConfigNotFoundException e) {
135 log.warn(e.getMessage() + " Aborting processPacketIn.");
136 return;
137 }
sanghob35a6192015-04-01 13:05:26 -0700138 // ICMP to the router IP or gateway IP
Pier Ventre735b8c82016-12-02 08:16:05 -0800139 if (((ICMP) ipv4Packet.getPayload()).getIcmpType() == ICMP.TYPE_ECHO_REQUEST &&
140 (destinationAddress.equals(routerIp.getIp4Address()) ||
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700141 gatewayIpAddresses.contains(destinationAddress))) {
Pier Ventre735b8c82016-12-02 08:16:05 -0800142 sendIcmpResponse(eth, inPort);
sanghob35a6192015-04-01 13:05:26 -0700143 } else {
Charles Chand4f3a622017-03-29 17:24:39 -0700144 log.trace("Ignore ICMP that targets for {}", destinationAddress);
sanghob35a6192015-04-01 13:05:26 -0700145 }
Charles Chand4f3a622017-03-29 17:24:39 -0700146 // We remove the packet from the queue
147 srManager.ipHandler.dequeuePacket(ipv4Packet, destinationAddress);
sanghob35a6192015-04-01 13:05:26 -0700148 }
149
Charles Chan68aa62d2015-11-09 16:37:23 -0800150 /**
151 * Sends an ICMP reply message.
152 *
Charles Chan68aa62d2015-11-09 16:37:23 -0800153 * @param icmpRequest the original ICMP request
154 * @param outport the output port where the ICMP reply should be sent to
155 */
Pier Ventree0ae7a32016-11-23 09:57:42 -0800156 private void sendIcmpResponse(Ethernet icmpRequest, ConnectPoint outport) {
Pier Ventre735b8c82016-12-02 08:16:05 -0800157 Ethernet icmpReplyEth = ICMP.buildIcmpReply(icmpRequest);
sanghob35a6192015-04-01 13:05:26 -0700158 IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload();
Pier Ventre735b8c82016-12-02 08:16:05 -0800159 IPv4 icmpReplyIpv4 = (IPv4) icmpReplyEth.getPayload();
160 Ip4Address destIpAddress = Ip4Address.valueOf(icmpRequestIpv4.getSourceAddress());
sangho666cd6d2015-04-14 16:27:13 -0700161 Ip4Address destRouterAddress = config.getRouterIpAddressForASubnetHost(destIpAddress);
Charles Chan40abef42017-06-02 19:23:51 -0700162
163 // Note: Source IP of the ICMP request doesn't belong to any configured subnet.
164 // The source might be an indirectly attached host (e.g. behind a router)
165 // Lookup the route store for the nexthop instead.
166 if (destRouterAddress == null) {
Charles Chanb15d0102017-08-23 13:55:39 -0700167 Optional<DeviceId> deviceId = srManager.routeService
168 .longestPrefixLookup(destIpAddress).map(srManager::nextHopLocations)
169 .flatMap(locations -> locations.stream().findFirst())
170 .map(ConnectPoint::deviceId);
171 if (deviceId.isPresent()) {
Charles Chan40abef42017-06-02 19:23:51 -0700172 try {
Charles Chanb15d0102017-08-23 13:55:39 -0700173 destRouterAddress = config.getRouterIpv4(deviceId.get());
Charles Chan40abef42017-06-02 19:23:51 -0700174 } catch (DeviceConfigNotFoundException e) {
Charles Chanb15d0102017-08-23 13:55:39 -0700175 log.warn("Device config for {} not found. Abort ICMP processing", deviceId);
Charles Chan40abef42017-06-02 19:23:51 -0700176 return;
177 }
178 }
179 }
180
Pier Ventree0ae7a32016-11-23 09:57:42 -0800181 int destSid = config.getIPv4SegmentId(destRouterAddress);
Charles Chan68aaad52016-12-09 12:54:49 -0800182 if (destSid < 0) {
Charles Chan40abef42017-06-02 19:23:51 -0700183 log.warn("Failed to lookup SID of the switch that {} attaches to. " +
184 "Unable to process ICMP request.", destIpAddress);
sanghob35a6192015-04-01 13:05:26 -0700185 return;
186 }
Pier Ventre735b8c82016-12-02 08:16:05 -0800187 sendPacketOut(outport, icmpReplyEth, destSid, destIpAddress, icmpReplyIpv4.getTtl());
sanghob35a6192015-04-01 13:05:26 -0700188 }
189
Pier Ventre735b8c82016-12-02 08:16:05 -0800190 ///////////////////////////////////////////
191 // ICMPv6 Echo/Reply Protocol //
192 ///////////////////////////////////////////
sanghob35a6192015-04-01 13:05:26 -0700193
Pier Ventre735b8c82016-12-02 08:16:05 -0800194 /**
195 * Process incoming ICMPv6 packet.
Charles Chand4f3a622017-03-29 17:24:39 -0700196 * If it is an ICMPv6 request to router, then sends an ICMPv6 response.
197 * Otherwise ignore the packet.
Pier Ventre735b8c82016-12-02 08:16:05 -0800198 *
199 * @param eth the incoming ICMPv6 packet
200 * @param inPort the input port
201 */
202 public void processIcmpv6(Ethernet eth, ConnectPoint inPort) {
203 DeviceId deviceId = inPort.deviceId();
204 IPv6 ipv6Packet = (IPv6) eth.getPayload();
205 Ip6Address destinationAddress = Ip6Address.valueOf(ipv6Packet.getDestinationAddress());
206 Set<IpAddress> gatewayIpAddresses = config.getPortIPs(deviceId);
207 IpAddress routerIp;
208 try {
209 routerIp = config.getRouterIpv6(deviceId);
210 } catch (DeviceConfigNotFoundException e) {
211 log.warn(e.getMessage() + " Aborting processPacketIn.");
212 return;
sanghob35a6192015-04-01 13:05:26 -0700213 }
Pier Ventre735b8c82016-12-02 08:16:05 -0800214 ICMP6 icmp6 = (ICMP6) ipv6Packet.getPayload();
215 // ICMP to the router IP or gateway IP
216 if (icmp6.getIcmpType() == ICMP6.ECHO_REQUEST &&
217 (destinationAddress.equals(routerIp.getIp6Address()) ||
218 gatewayIpAddresses.contains(destinationAddress))) {
219 sendIcmpv6Response(eth, inPort);
Pier Ventre735b8c82016-12-02 08:16:05 -0800220 } else {
Charles Chand4f3a622017-03-29 17:24:39 -0700221 log.trace("Ignore ICMPv6 that targets for {}", destinationAddress);
Pier Ventre735b8c82016-12-02 08:16:05 -0800222 }
223 }
224
225 /**
226 * Sends an ICMPv6 reply message.
227 *
228 * Note: we assume that packets sending from the edge switches to the hosts
229 * have untagged VLAN.
230 * @param ethRequest the original ICMP request
231 * @param outport the output port where the ICMP reply should be sent to
232 */
233 private void sendIcmpv6Response(Ethernet ethRequest, ConnectPoint outport) {
Charles Chan40abef42017-06-02 19:23:51 -0700234 // Note: We assume that packets arrive at the edge switches have untagged VLAN.
Pier Ventre735b8c82016-12-02 08:16:05 -0800235 Ethernet ethReply = ICMP6.buildIcmp6Reply(ethRequest);
236 IPv6 icmpRequestIpv6 = (IPv6) ethRequest.getPayload();
237 IPv6 icmpReplyIpv6 = (IPv6) ethRequest.getPayload();
238 Ip6Address destIpAddress = Ip6Address.valueOf(icmpRequestIpv6.getSourceAddress());
239 Ip6Address destRouterAddress = config.getRouterIpAddressForASubnetHost(destIpAddress);
Charles Chan40abef42017-06-02 19:23:51 -0700240
241 // Note: Source IP of the ICMP request doesn't belong to any configured subnet.
242 // The source might be an indirect host behind a router.
243 // Lookup the route store for the nexthop instead.
244 if (destRouterAddress == null) {
Charles Chanb15d0102017-08-23 13:55:39 -0700245 Optional<DeviceId> deviceId = srManager.routeService
246 .longestPrefixLookup(destIpAddress).map(srManager::nextHopLocations)
247 .flatMap(locations -> locations.stream().findFirst())
248 .map(ConnectPoint::deviceId);
249 if (deviceId.isPresent()) {
Charles Chan40abef42017-06-02 19:23:51 -0700250 try {
Charles Chanb15d0102017-08-23 13:55:39 -0700251 destRouterAddress = config.getRouterIpv6(deviceId.get());
Charles Chan40abef42017-06-02 19:23:51 -0700252 } catch (DeviceConfigNotFoundException e) {
Charles Chanb15d0102017-08-23 13:55:39 -0700253 log.warn("Device config for {} not found. Abort ICMPv6 processing", deviceId);
Charles Chan40abef42017-06-02 19:23:51 -0700254 return;
255 }
256 }
257 }
258
Pier Ventre735b8c82016-12-02 08:16:05 -0800259 int sid = config.getIPv6SegmentId(destRouterAddress);
260 if (sid < 0) {
Charles Chan40abef42017-06-02 19:23:51 -0700261 log.warn("Failed to lookup SID of the switch that {} attaches to. " +
262 "Unable to process ICMPv6 request.", destIpAddress);
Pier Ventre735b8c82016-12-02 08:16:05 -0800263 return;
264 }
265 sendPacketOut(outport, ethReply, sid, destIpAddress, icmpReplyIpv6.getHopLimit());
sanghob35a6192015-04-01 13:05:26 -0700266 }
sangho666cd6d2015-04-14 16:27:13 -0700267
Pier Ventref4b5fce2016-11-28 16:48:06 -0800268 ///////////////////////////////////////////
269 // ICMPv6 Neighbour Discovery Protocol //
270 ///////////////////////////////////////////
sangho666cd6d2015-04-14 16:27:13 -0700271
Pier Ventref4b5fce2016-11-28 16:48:06 -0800272 /**
273 * Process incoming NDP packet.
274 *
275 * If it is an NDP request for the router or for the gateway, then sends a NDP reply.
276 * If it is an NDP request to unknown host flood in the subnet.
277 * If it is an NDP packet to known host forward the packet to the host.
278 *
279 * FIXME If the NDP packets use link local addresses we fail.
280 *
281 * @param pkt inbound packet
282 * @param hostService the host service
283 */
284 public void processPacketIn(NeighbourMessageContext pkt, HostService hostService) {
Charles Chand4f3a622017-03-29 17:24:39 -0700285 // First we validate the ndp packet
Pier Ventref4b5fce2016-11-28 16:48:06 -0800286 SegmentRoutingAppConfig appConfig = srManager.cfgService
287 .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
288 if (appConfig != null && appConfig.suppressSubnet().contains(pkt.inPort())) {
289 // Ignore NDP packets come from suppressed ports
290 pkt.drop();
291 return;
292 }
Pier Ventref4b5fce2016-11-28 16:48:06 -0800293
294 if (pkt.type() == NeighbourMessageType.REQUEST) {
295 handleNdpRequest(pkt, hostService);
296 } else {
297 handleNdpReply(pkt, hostService);
298 }
299
300 }
301
302 /**
Pier Ventref4b5fce2016-11-28 16:48:06 -0800303 * Helper method to handle the ndp requests.
304 *
305 * @param pkt the ndp packet request and context information
306 * @param hostService the host service
307 */
308 private void handleNdpRequest(NeighbourMessageContext pkt, HostService hostService) {
Charles Chan563a7812017-02-27 15:50:43 -0800309 // ND request for the gateway. We have to reply on behalf of the gateway.
Pier Ventref4b5fce2016-11-28 16:48:06 -0800310 if (isNdpForGateway(pkt)) {
Saurav Das961beb22017-03-29 19:09:17 -0700311 log.trace("Sending NDP reply on behalf of gateway IP for pkt: {}", pkt);
Pier Ventre735b8c82016-12-02 08:16:05 -0800312 sendResponse(pkt, config.getRouterMacForAGatewayIp(pkt.target()), hostService);
Pier Ventref4b5fce2016-11-28 16:48:06 -0800313 } else {
Charles Chan563a7812017-02-27 15:50:43 -0800314 // NOTE: Ignore NDP packets except those target for the router
315 // We will reconsider enabling this when we have host learning support
Pier Ventref4b5fce2016-11-28 16:48:06 -0800316 /*
Charles Chan563a7812017-02-27 15:50:43 -0800317 // ND request for an host. We do a search by Ip.
Pier Ventref4b5fce2016-11-28 16:48:06 -0800318 Set<Host> hosts = hostService.getHostsByIp(pkt.target());
Charles Chan563a7812017-02-27 15:50:43 -0800319 // Possible misconfiguration ? In future this case
320 // should be handled we can have same hosts in different VLANs.
Pier Ventref4b5fce2016-11-28 16:48:06 -0800321 if (hosts.size() > 1) {
322 log.warn("More than one host with IP {}", pkt.target());
323 }
324 Host targetHost = hosts.stream().findFirst().orElse(null);
Charles Chan563a7812017-02-27 15:50:43 -0800325 // If we know the host forward to its attachment point.
Pier Ventref4b5fce2016-11-28 16:48:06 -0800326 if (targetHost != null) {
327 log.debug("Forward NDP request to the target host");
328 pkt.forward(targetHost.location());
329 } else {
Charles Chan563a7812017-02-27 15:50:43 -0800330 // Flood otherwise.
Pier Ventref4b5fce2016-11-28 16:48:06 -0800331 log.debug("Flood NDP request to the target subnet");
332 flood(pkt);
333 }
Charles Chan563a7812017-02-27 15:50:43 -0800334 */
Pier Ventref4b5fce2016-11-28 16:48:06 -0800335 }
336 }
337
338 /**
339 * Helper method to handle the ndp replies.
340 *
341 * @param pkt the ndp packet reply and context information
342 * @param hostService the host service
343 */
344 private void handleNdpReply(NeighbourMessageContext pkt, HostService hostService) {
345 if (isNdpForGateway(pkt)) {
346 log.debug("Forwarding all the ip packets we stored");
347 Ip6Address hostIpAddress = pkt.sender().getIp6Address();
348 srManager.ipHandler.forwardPackets(pkt.inPort().deviceId(), hostIpAddress);
349 } else {
Charles Chan563a7812017-02-27 15:50:43 -0800350 // NOTE: Ignore NDP packets except those target for the router
351 // We will reconsider enabling this when we have host learning support
352 /*
Pier Ventref4b5fce2016-11-28 16:48:06 -0800353 HostId hostId = HostId.hostId(pkt.dstMac(), pkt.vlan());
354 Host targetHost = hostService.getHost(hostId);
355 if (targetHost != null) {
356 log.debug("Forwarding the reply to the host");
357 pkt.forward(targetHost.location());
358 } else {
Charles Chan563a7812017-02-27 15:50:43 -0800359 // We don't have to flood towards spine facing ports.
Charles Chan59cc16d2017-02-02 16:20:42 -0800360 if (pkt.vlan().equals(SegmentRoutingManager.INTERNAL_VLAN)) {
Pier Ventref4b5fce2016-11-28 16:48:06 -0800361 return;
362 }
363 log.debug("Flooding the reply to the subnet");
364 flood(pkt);
365 }
Charles Chan563a7812017-02-27 15:50:43 -0800366 */
Pier Ventref4b5fce2016-11-28 16:48:06 -0800367 }
368 }
369
370 /**
371 * Utility to verify if the ND are for the gateway.
372 *
373 * @param pkt the ndp packet
374 * @return true if the ndp is for the gateway. False otherwise
375 */
376 private boolean isNdpForGateway(NeighbourMessageContext pkt) {
377 DeviceId deviceId = pkt.inPort().deviceId();
378 Set<IpAddress> gatewayIpAddresses = null;
379 try {
380 if (pkt.target().equals(config.getRouterIpv6(deviceId))) {
381 return true;
382 }
383 gatewayIpAddresses = config.getPortIPs(deviceId);
384 } catch (DeviceConfigNotFoundException e) {
385 log.warn(e.getMessage() + " Aborting check for router IP in processing ndp");
386 }
Charles Chan0ed44fb2017-03-13 13:10:30 -0700387
388 return gatewayIpAddresses != null && gatewayIpAddresses.stream()
389 .filter(IpAddress::isIp6)
390 .anyMatch(gatewayIp -> gatewayIp.equals(pkt.target()) ||
391 Arrays.equals(IPv6.getSolicitNodeAddress(gatewayIp.toOctets()),
392 pkt.target().toOctets())
393 );
Pier Ventref4b5fce2016-11-28 16:48:06 -0800394 }
395
396 /**
Pier Ventre735b8c82016-12-02 08:16:05 -0800397 * Sends a NDP request for the target IP address to all ports except in-port.
Pier Ventref4b5fce2016-11-28 16:48:06 -0800398 *
Pier Ventre735b8c82016-12-02 08:16:05 -0800399 * @param deviceId Switch device ID
400 * @param targetAddress target IP address for ARP
401 * @param inPort in-port
Pier Ventref4b5fce2016-11-28 16:48:06 -0800402 */
Pier Ventre735b8c82016-12-02 08:16:05 -0800403 public void sendNdpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
404 byte[] senderMacAddress = new byte[MacAddress.MAC_ADDRESS_LENGTH];
405 byte[] senderIpAddress = new byte[Ip6Address.BYTE_LENGTH];
Charles Chand4f3a622017-03-29 17:24:39 -0700406 // Retrieves device info.
Pier Luigia905c0c2017-01-29 12:38:48 -0800407 if (!getSenderInfo(senderMacAddress, senderIpAddress, deviceId, targetAddress)) {
408 log.warn("Aborting sendNdpRequest, we cannot get all the information needed");
409 return;
410 }
Charles Chand4f3a622017-03-29 17:24:39 -0700411 // We have to compute the dst mac address and dst ip address.
Pier Ventre735b8c82016-12-02 08:16:05 -0800412 byte[] dstIp = IPv6.getSolicitNodeAddress(targetAddress.toOctets());
413 byte[] dstMac = IPv6.getMCastMacAddress(dstIp);
Charles Chand4f3a622017-03-29 17:24:39 -0700414 // Creates the request.
Pier Ventre735b8c82016-12-02 08:16:05 -0800415 Ethernet ndpRequest = NeighborSolicitation.buildNdpSolicit(
416 targetAddress.toOctets(),
417 senderIpAddress,
418 dstIp,
419 senderMacAddress,
420 dstMac,
421 VlanId.NONE
422 );
423 flood(ndpRequest, inPort, targetAddress);
Pier Ventref4b5fce2016-11-28 16:48:06 -0800424 }
sanghob35a6192015-04-01 13:05:26 -0700425}