Committed by
Gerrit Code Review
ProxyArpManager: Factor out common logic for handling ARP and NDP packets.
Change-Id: I0709f9cda2506f01dbc912b8c3e12443ec217fed
Showing
4 changed files
with
228 additions
and
157 deletions
... | @@ -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 | } | ... | ... |
-
Please register or login to post a comment