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