Jonathan Hart
Committed by Gerrit Code Review

ProxyArpManager: Factor out common logic for handling ARP and NDP packets.

Change-Id: I0709f9cda2506f01dbc912b8c3e12443ec217fed
...@@ -82,7 +82,7 @@ public class ProxyArp { ...@@ -82,7 +82,7 @@ public class ProxyArp {
82 82
83 packetService.addProcessor(processor, PacketProcessor.director(1)); 83 packetService.addProcessor(processor, PacketProcessor.director(1));
84 readComponentConfiguration(context); 84 readComponentConfiguration(context);
85 - requestPackests(); 85 + requestPackets();
86 86
87 log.info("Started with Application ID {}", appId.id()); 87 log.info("Started with Application ID {}", appId.id());
88 } 88 }
...@@ -99,13 +99,13 @@ public class ProxyArp { ...@@ -99,13 +99,13 @@ public class ProxyArp {
99 @Modified 99 @Modified
100 public void modified(ComponentContext context) { 100 public void modified(ComponentContext context) {
101 readComponentConfiguration(context); 101 readComponentConfiguration(context);
102 - requestPackests(); 102 + requestPackets();
103 } 103 }
104 104
105 /** 105 /**
106 * Request packet in via PacketService. 106 * Request packet in via PacketService.
107 */ 107 */
108 - private void requestPackests() { 108 + private void requestPackets() {
109 TrafficSelector.Builder selectorBuilder = 109 TrafficSelector.Builder selectorBuilder =
110 DefaultTrafficSelector.builder(); 110 DefaultTrafficSelector.builder();
111 selectorBuilder.matchEthType(TYPE_ARP); 111 selectorBuilder.matchEthType(TYPE_ARP);
......
...@@ -21,7 +21,7 @@ import org.onosproject.net.ConnectPoint; ...@@ -21,7 +21,7 @@ import org.onosproject.net.ConnectPoint;
21 import org.onosproject.net.packet.PacketContext; 21 import org.onosproject.net.packet.PacketContext;
22 22
23 /** 23 /**
24 - * Service for processing arp requests on behalf of applications. 24 + * Service for processing ARP or NDP requests on behalf of applications.
25 */ 25 */
26 // TODO: move to the peer host package 26 // TODO: move to the peer host package
27 public interface ProxyArpService { 27 public interface ProxyArpService {
......
...@@ -33,8 +33,6 @@ import org.onosproject.net.ConnectPoint; ...@@ -33,8 +33,6 @@ import org.onosproject.net.ConnectPoint;
33 import org.onosproject.net.Host; 33 import org.onosproject.net.Host;
34 import org.onosproject.net.flow.DefaultTrafficTreatment; 34 import org.onosproject.net.flow.DefaultTrafficTreatment;
35 import org.onosproject.net.flow.TrafficTreatment; 35 import org.onosproject.net.flow.TrafficTreatment;
36 -import org.onosproject.net.flow.instructions.Instruction;
37 -import org.onosproject.net.flow.instructions.Instructions;
38 import org.onosproject.net.host.HostProvider; 36 import org.onosproject.net.host.HostProvider;
39 import org.onosproject.net.host.InterfaceIpAddress; 37 import org.onosproject.net.host.InterfaceIpAddress;
40 import org.onosproject.net.packet.DefaultOutboundPacket; 38 import org.onosproject.net.packet.DefaultOutboundPacket;
...@@ -43,9 +41,7 @@ import org.onosproject.net.packet.PacketService; ...@@ -43,9 +41,7 @@ import org.onosproject.net.packet.PacketService;
43 import org.onosproject.net.provider.ProviderId; 41 import org.onosproject.net.provider.ProviderId;
44 42
45 import java.nio.ByteBuffer; 43 import java.nio.ByteBuffer;
46 -import java.util.ArrayList;
47 import java.util.Collections; 44 import java.util.Collections;
48 -import java.util.List;
49 import java.util.Set; 45 import java.util.Set;
50 import java.util.concurrent.ConcurrentHashMap; 46 import java.util.concurrent.ConcurrentHashMap;
51 import java.util.concurrent.ConcurrentMap; 47 import java.util.concurrent.ConcurrentMap;
...@@ -149,7 +145,7 @@ public class HostMonitor implements TimerTask { ...@@ -149,7 +145,7 @@ public class HostMonitor implements TimerTask {
149 Set<Host> hosts = hostManager.getHostsByIp(ip); 145 Set<Host> hosts = hostManager.getHostsByIp(ip);
150 146
151 if (hosts.isEmpty()) { 147 if (hosts.isEmpty()) {
152 - sendArpNdpRequest(ip); 148 + sendRequest(ip);
153 } else { 149 } else {
154 for (Host host : hosts) { 150 for (Host host : hosts) {
155 HostProvider provider = hostProviders.get(host.providerId()); 151 HostProvider provider = hostProviders.get(host.providerId());
...@@ -166,12 +162,11 @@ public class HostMonitor implements TimerTask { ...@@ -166,12 +162,11 @@ public class HostMonitor implements TimerTask {
166 } 162 }
167 163
168 /** 164 /**
169 - * Sends an ARP or Neighbor Discovery Protocol request for the given IP 165 + * Sends an ARP or NDP request for the given IP address.
170 - * address.
171 * 166 *
172 * @param targetIp IP address to send the request for 167 * @param targetIp IP address to send the request for
173 */ 168 */
174 - private void sendArpNdpRequest(IpAddress targetIp) { 169 + private void sendRequest(IpAddress targetIp) {
175 Interface intf = interfaceService.getMatchingInterface(targetIp); 170 Interface intf = interfaceService.getMatchingInterface(targetIp);
176 171
177 if (intf == null) { 172 if (intf == null) {
...@@ -180,13 +175,13 @@ public class HostMonitor implements TimerTask { ...@@ -180,13 +175,13 @@ public class HostMonitor implements TimerTask {
180 175
181 for (InterfaceIpAddress ia : intf.ipAddresses()) { 176 for (InterfaceIpAddress ia : intf.ipAddresses()) {
182 if (ia.subnetAddress().contains(targetIp)) { 177 if (ia.subnetAddress().contains(targetIp)) {
183 - sendArpNdpProbe(intf.connectPoint(), targetIp, ia.ipAddress(), 178 + sendProbe(intf.connectPoint(), targetIp, ia.ipAddress(),
184 intf.mac(), intf.vlan()); 179 intf.mac(), intf.vlan());
185 } 180 }
186 } 181 }
187 } 182 }
188 183
189 - private void sendArpNdpProbe(ConnectPoint connectPoint, 184 + private void sendProbe(ConnectPoint connectPoint,
190 IpAddress targetIp, 185 IpAddress targetIp,
191 IpAddress sourceIp, MacAddress sourceMac, 186 IpAddress sourceIp, MacAddress sourceMac,
192 VlanId vlan) { 187 VlanId vlan) {
...@@ -194,17 +189,12 @@ public class HostMonitor implements TimerTask { ...@@ -194,17 +189,12 @@ public class HostMonitor implements TimerTask {
194 189
195 if (targetIp.isIp4()) { 190 if (targetIp.isIp4()) {
196 // IPv4: Use ARP 191 // IPv4: Use ARP
197 - probePacket = buildArpRequest(targetIp, sourceIp, sourceMac, 192 + probePacket = buildArpRequest(targetIp, sourceIp, sourceMac, vlan);
198 - vlan);
199 } else { 193 } else {
200 // IPv6: Use Neighbor Discovery 194 // IPv6: Use Neighbor Discovery
201 - probePacket = buildNdpRequest(targetIp, sourceIp, sourceMac, 195 + probePacket = buildNdpRequest(targetIp, sourceIp, sourceMac, vlan);
202 - vlan);
203 } 196 }
204 197
205 - List<Instruction> instructions = new ArrayList<>();
206 - instructions.add(Instructions.createOutput(connectPoint.port()));
207 -
208 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 198 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
209 .setOutput(connectPoint.port()) 199 .setOutput(connectPoint.port())
210 .build(); 200 .build();
...@@ -273,7 +263,7 @@ public class HostMonitor implements TimerTask { ...@@ -273,7 +263,7 @@ public class HostMonitor implements TimerTask {
273 icmp6.setIcmpType(ICMP6.NEIGHBOR_SOLICITATION); 263 icmp6.setIcmpType(ICMP6.NEIGHBOR_SOLICITATION);
274 icmp6.setIcmpCode((byte) 0); 264 icmp6.setIcmpCode((byte) 0);
275 265
276 - // Create the Neighbor Solication packet 266 + // Create the Neighbor Solicitation packet
277 NeighborSolicitation ns = new NeighborSolicitation(); 267 NeighborSolicitation ns = new NeighborSolicitation();
278 ns.setTargetAddress(targetIp.toOctets()); 268 ns.setTargetAddress(targetIp.toOctets());
279 ns.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS, 269 ns.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS,
......
...@@ -69,11 +69,9 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -69,11 +69,9 @@ public class ProxyArpManager implements ProxyArpService {
69 69
70 private final Logger log = getLogger(getClass()); 70 private final Logger log = getLogger(getClass());
71 71
72 - private static final String MAC_ADDR_NULL = "Mac address cannot be null."; 72 + private static final String MAC_ADDR_NULL = "MAC address cannot be null.";
73 private static final String REQUEST_NULL = "ARP or NDP request cannot be null."; 73 private static final String REQUEST_NULL = "ARP or NDP request cannot be null.";
74 - private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request."; 74 + private static final String MSG_NOT_REQUEST = "Message is not an ARP or NDP request";
75 - private static final String NOT_ARP_REQUEST = "ARP is not a request.";
76 - private static final String NOT_ARP_REPLY = "ARP is not a reply.";
77 75
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected EdgePortService edgeService; 77 protected EdgePortService edgeService;
...@@ -96,6 +94,14 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -96,6 +94,14 @@ public class ProxyArpManager implements ProxyArpService {
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected InterfaceService interfaceService; 95 protected InterfaceService interfaceService;
98 96
97 + private enum Protocol {
98 + ARP, NDP
99 + }
100 +
101 + private enum MessageType {
102 + REQUEST, REPLY
103 + }
104 +
99 @Activate 105 @Activate
100 public void activate() { 106 public void activate() {
101 store.setDelegate(this::sendTo); 107 store.setDelegate(this::sendTo);
...@@ -123,46 +129,48 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -123,46 +129,48 @@ public class ProxyArpManager implements ProxyArpService {
123 129
124 checkNotNull(eth, REQUEST_NULL); 130 checkNotNull(eth, REQUEST_NULL);
125 131
126 - if (eth.getEtherType() == Ethernet.TYPE_ARP) { 132 + MessageContext context = createContext(eth, inPort);
127 - replyArp(eth, inPort); 133 + if (context != null) {
128 - } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) { 134 + replyInternal(context);
129 - replyNdp(eth, inPort);
130 } 135 }
131 } 136 }
132 137
133 - private void replyArp(Ethernet eth, ConnectPoint inPort) { 138 + /**
134 - ARP arp = (ARP) eth.getPayload(); 139 + * Handles a request message.
135 - checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST); 140 + *
136 - checkNotNull(inPort); 141 + * If the MAC address of the target is known, we can reply directly to the
137 - Ip4Address targetAddress = Ip4Address.valueOf(arp.getTargetProtocolAddress()); 142 + * requestor. Otherwise, we forward the request out other ports in an
138 - 143 + * attempt to find the correct host.
139 - VlanId vlan = vlanId(eth.getVlanID()); 144 + *
145 + * @param context request message context to process
146 + */
147 + private void replyInternal(MessageContext context) {
148 + checkNotNull(context);
149 + checkArgument(context.type() == MessageType.REQUEST, MSG_NOT_REQUEST);
140 150
141 - if (hasIpAddress(inPort)) { 151 + if (hasIpAddress(context.inPort())) {
142 // If the request came from outside the network, only reply if it was 152 // If the request came from outside the network, only reply if it was
143 // for one of our external addresses. 153 // for one of our external addresses.
144 154
145 - interfaceService.getInterfacesByPort(inPort) 155 + interfaceService.getInterfacesByPort(context.inPort())
146 .stream() 156 .stream()
147 .filter(intf -> intf.ipAddresses() 157 .filter(intf -> intf.ipAddresses()
148 .stream() 158 .stream()
149 - .anyMatch(ia -> ia.ipAddress().equals(targetAddress))) 159 + .anyMatch(ia -> ia.ipAddress().equals(context.target())))
150 - .forEach(intf -> buildAndSendArp(targetAddress, intf.mac(), eth, inPort)); 160 + .forEach(intf -> buildAndSendReply(context, intf.mac()));
151 161
152 // Stop here and don't proxy ARPs if the port has an IP address 162 // Stop here and don't proxy ARPs if the port has an IP address
153 return; 163 return;
154 } 164 }
155 165
156 // See if we have the target host in the host store 166 // See if we have the target host in the host store
157 - 167 + Set<Host> hosts = hostService.getHostsByIp(context.target());
158 - Set<Host> hosts = hostService.getHostsByIp(targetAddress);
159 168
160 Host dst = null; 169 Host dst = null;
161 - Host src = hostService.getHost(hostId(eth.getSourceMAC(), 170 + Host src = hostService.getHost(hostId(context.srcMac(), context.vlan()));
162 - vlanId(eth.getVlanID())));
163 171
164 for (Host host : hosts) { 172 for (Host host : hosts) {
165 - if (host.vlan().equals(vlan)) { 173 + if (host.vlan().equals(context.vlan())) {
166 dst = host; 174 dst = host;
167 break; 175 break;
168 } 176 }
...@@ -170,22 +178,19 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -170,22 +178,19 @@ public class ProxyArpManager implements ProxyArpService {
170 178
171 if (src != null && dst != null) { 179 if (src != null && dst != null) {
172 // We know the target host so we can respond 180 // We know the target host so we can respond
173 - buildAndSendArp(targetAddress, dst.mac(), eth, inPort); 181 + buildAndSendReply(context, dst.mac());
174 return; 182 return;
175 } 183 }
176 184
177 // If the source address matches one of our external addresses 185 // If the source address matches one of our external addresses
178 // it could be a request from an internal host to an external 186 // it could be a request from an internal host to an external
179 // address. Forward it over to the correct port. 187 // address. Forward it over to the correct port.
180 - Ip4Address source =
181 - Ip4Address.valueOf(arp.getSenderProtocolAddress());
182 -
183 boolean matched = false; 188 boolean matched = false;
184 - Set<Interface> interfaces = interfaceService.getInterfacesByIp(source); 189 + Set<Interface> interfaces = interfaceService.getInterfacesByIp(context.sender());
185 for (Interface intf : interfaces) { 190 for (Interface intf : interfaces) {
186 - if (intf.vlan().equals(vlan)) { 191 + if (intf.vlan().equals(context.vlan())) {
187 matched = true; 192 matched = true;
188 - sendTo(eth, intf.connectPoint()); 193 + sendTo(context.packet(), intf.connectPoint());
189 break; 194 break;
190 } 195 }
191 } 196 }
...@@ -196,89 +201,33 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -196,89 +201,33 @@ public class ProxyArpManager implements ProxyArpService {
196 201
197 // The request couldn't be resolved. 202 // The request couldn't be resolved.
198 // Flood the request on all ports except the incoming port. 203 // Flood the request on all ports except the incoming port.
199 - flood(eth, inPort); 204 + flood(context.packet(), context.inPort());
200 - }
201 -
202 - private void replyNdp(Ethernet eth, ConnectPoint inPort) {
203 - IPv6 ipv6 = (IPv6) eth.getPayload();
204 - ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
205 - NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload();
206 - Ip6Address targetAddress = Ip6Address.valueOf(nsol.getTargetAddress());
207 -
208 - VlanId vlan = vlanId(eth.getVlanID());
209 -
210 - // If the request came from outside the network, only reply if it was
211 - // for one of our external addresses.
212 - 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));
219 - return;
220 } 205 }
221 206
222 - // Continue with normal proxy ARP case 207 + /**
223 - 208 + * Builds and sends a reply message given a request context and the resolved
224 - Set<Host> hosts = hostService.getHostsByIp(targetAddress); 209 + * MAC address to answer with.
225 - 210 + *
226 - Host dst = null; 211 + * @param context message context of request
227 - Host src = hostService.getHost(hostId(eth.getSourceMAC(), 212 + * @param targetMac MAC address to be given in the response
228 - vlanId(eth.getVlanID()))); 213 + */
229 - 214 + private void buildAndSendReply(MessageContext context, MacAddress targetMac) {
230 - for (Host host : hosts) { 215 + switch (context.protocol()) {
231 - if (host.vlan().equals(vlan)) { 216 + case ARP:
232 - dst = host; 217 + sendTo(ARP.buildArpReply((Ip4Address) context.target(),
218 + targetMac, context.packet()), context.inPort());
233 break; 219 break;
234 - } 220 + case NDP:
235 - } 221 + sendTo(buildNdpReply((Ip6Address) context.target(), targetMac,
236 - 222 + context.packet()), context.inPort());
237 - if (src != null && dst != null) { 223 + break;
238 - // We know the target host so we can respond 224 + default:
239 - buildAndSendNdp(targetAddress, dst.mac(), eth, inPort);
240 - return;
241 - }
242 -
243 - // 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; 225 break;
257 } 226 }
258 } 227 }
259 228
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);
267 - }
268 - //TODO checkpoint
269 -
270 - 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 -
280 /** 229 /**
281 - * Outputs the given packet out the given port. 230 + * Outputs a packet out a specific port.
282 * 231 *
283 * @param packet the packet to send 232 * @param packet the packet to send
284 * @param outPort the port to send it out 233 * @param outPort the port to send it out
...@@ -287,6 +236,12 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -287,6 +236,12 @@ public class ProxyArpManager implements ProxyArpService {
287 sendTo(outPort, ByteBuffer.wrap(packet.serialize())); 236 sendTo(outPort, ByteBuffer.wrap(packet.serialize()));
288 } 237 }
289 238
239 + /**
240 + * Outputs a packet out a specific port.
241 + *
242 + * @param outPort port to send it out
243 + * @param packet packet to send
244 + */
290 private void sendTo(ConnectPoint outPort, ByteBuffer packet) { 245 private void sendTo(ConnectPoint outPort, ByteBuffer packet) {
291 if (!edgeService.isEdgePoint(outPort)) { 246 if (!edgeService.isEdgePoint(outPort)) {
292 // Sanity check to make sure we don't send the packet out an 247 // Sanity check to make sure we don't send the packet out an
...@@ -344,42 +299,24 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -344,42 +299,24 @@ public class ProxyArpManager implements ProxyArpService {
344 if (ethPkt == null) { 299 if (ethPkt == null) {
345 return false; 300 return false;
346 } 301 }
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);
351 - }
352 - return false;
353 - }
354 302
355 - private boolean handleArp(PacketContext context, Ethernet ethPkt) { 303 + MessageContext msgContext = createContext(ethPkt, pkt.receivedFrom());
356 - ARP arp = (ARP) ethPkt.getPayload();
357 304
358 - if (arp.getOpCode() == ARP.OP_REPLY) { 305 + if (msgContext == null) {
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; 306 return false;
364 } 307 }
365 - context.block();
366 - return true;
367 - }
368 -
369 - private boolean handleNdp(PacketContext context, Ethernet ethPkt) {
370 - IPv6 ipv6 = (IPv6) ethPkt.getPayload();
371 308
372 - if (ipv6.getNextHeader() != IPv6.PROTOCOL_ICMP6) { 309 + switch (msgContext.type()) {
373 - return false; 310 + case REPLY:
374 - } 311 + forward(msgContext.packet(), msgContext.inPort());
375 - ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); 312 + break;
376 - if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) { 313 + case REQUEST:
377 - forward(ethPkt, context.inPacket().receivedFrom()); 314 + replyInternal(msgContext);
378 - } else if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) { 315 + break;
379 - reply(ethPkt, context.inPacket().receivedFrom()); 316 + default:
380 - } else {
381 return false; 317 return false;
382 } 318 }
319 +
383 context.block(); 320 context.block();
384 return true; 321 return true;
385 } 322 }
...@@ -444,4 +381,148 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -444,4 +381,148 @@ public class ProxyArpManager implements ProxyArpService {
444 eth.setPayload(ipv6); 381 eth.setPayload(ipv6);
445 return eth; 382 return eth;
446 } 383 }
384 +
385 + /**
386 + * Attempts to create a MessageContext for the given Ethernet frame. If the
387 + * frame is a valid ARP or NDP request or response, a context will be
388 + * created.
389 + *
390 + * @param eth input Ethernet frame
391 + * @param inPort in port
392 + * @return MessageContext if the packet was ARP or NDP, otherwise null
393 + */
394 + private MessageContext createContext(Ethernet eth, ConnectPoint inPort) {
395 + if (eth.getEtherType() == Ethernet.TYPE_ARP) {
396 + return createArpContext(eth, inPort);
397 + } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
398 + return createNdpContext(eth, inPort);
399 + }
400 +
401 + return null;
402 + }
403 +
404 + /**
405 + * Extracts context information from ARP packets.
406 + *
407 + * @param eth input Ethernet frame that is thought to be ARP
408 + * @param inPort in port
409 + * @return MessageContext object if the packet was a valid ARP packet,
410 + * otherwise null
411 + */
412 + private MessageContext createArpContext(Ethernet eth, ConnectPoint inPort) {
413 + if (eth.getEtherType() != Ethernet.TYPE_ARP) {
414 + return null;
415 + }
416 +
417 + ARP arp = (ARP) eth.getPayload();
418 +
419 + IpAddress target = Ip4Address.valueOf(arp.getTargetProtocolAddress());
420 + IpAddress sender = Ip4Address.valueOf(arp.getSenderProtocolAddress());
421 +
422 + MessageType type;
423 + if (arp.getOpCode() == ARP.OP_REQUEST) {
424 + type = MessageType.REQUEST;
425 + } else if (arp.getOpCode() == ARP.OP_REPLY) {
426 + type = MessageType.REPLY;
427 + } else {
428 + return null;
429 + }
430 +
431 + return new MessageContext(eth, inPort, Protocol.ARP, type, target, sender);
432 + }
433 +
434 + /**
435 + * Extracts context information from NDP packets.
436 + *
437 + * @param eth input Ethernet frame that is thought to be NDP
438 + * @param inPort in port
439 + * @return MessageContext object if the packet was a valid NDP packet,
440 + * otherwise null
441 + */
442 + private MessageContext createNdpContext(Ethernet eth, ConnectPoint inPort) {
443 + if (eth.getEtherType() != Ethernet.TYPE_IPV6) {
444 + return null;
445 + }
446 + IPv6 ipv6 = (IPv6) eth.getPayload();
447 +
448 + if (ipv6.getNextHeader() != IPv6.PROTOCOL_ICMP6) {
449 + return null;
450 + }
451 + ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
452 +
453 + IpAddress sender = Ip6Address.valueOf(ipv6.getSourceAddress());
454 + IpAddress target = null;
455 +
456 + MessageType type;
457 + if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) {
458 + type = MessageType.REQUEST;
459 + NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload();
460 + target = Ip6Address.valueOf(nsol.getTargetAddress());
461 + } else if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) {
462 + type = MessageType.REPLY;
463 + } else {
464 + return null;
465 + }
466 +
467 + return new MessageContext(eth, inPort, Protocol.NDP, type, target, sender);
468 + }
469 +
470 + /**
471 + * Provides context information for a particular ARP or NDP message, with
472 + * a unified interface to access data regardless of protocol.
473 + */
474 + private class MessageContext {
475 + private Protocol protocol;
476 + private MessageType type;
477 +
478 + private IpAddress target;
479 + private IpAddress sender;
480 +
481 + private Ethernet eth;
482 + private ConnectPoint inPort;
483 +
484 +
485 + public MessageContext(Ethernet eth, ConnectPoint inPort,
486 + Protocol protocol, MessageType type,
487 + IpAddress target, IpAddress sender) {
488 + this.eth = eth;
489 + this.inPort = inPort;
490 + this.protocol = protocol;
491 + this.type = type;
492 + this.target = target;
493 + this.sender = sender;
494 + }
495 +
496 + public ConnectPoint inPort() {
497 + return inPort;
498 + }
499 +
500 + public Ethernet packet() {
501 + return eth;
502 + }
503 +
504 + public Protocol protocol() {
505 + return protocol;
506 + }
507 +
508 + public MessageType type() {
509 + return type;
510 + }
511 +
512 + public VlanId vlan() {
513 + return VlanId.vlanId(eth.getVlanID());
514 + }
515 +
516 + public MacAddress srcMac() {
517 + return MacAddress.valueOf(eth.getSourceMACAddress());
518 + }
519 +
520 + public IpAddress target() {
521 + return target;
522 + }
523 +
524 + public IpAddress sender() {
525 + return sender;
526 + }
527 + }
447 } 528 }
......