Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 1 | /* |
Brian O'Connor | 5ab426f | 2016-04-09 01:19:45 -0700 | [diff] [blame] | 2 | * Copyright 2015-present Open Networking Laboratory |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 3 | * |
| 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 | */ |
| 16 | package org.onosproject.reactive.routing; |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 17 | |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 18 | import org.apache.felix.scr.annotations.Activate; |
| 19 | import org.apache.felix.scr.annotations.Component; |
| 20 | import org.apache.felix.scr.annotations.Deactivate; |
| 21 | import org.apache.felix.scr.annotations.Reference; |
| 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
Pingping Lin | c9e16bf | 2015-04-10 14:42:41 -0700 | [diff] [blame] | 23 | import org.onlab.packet.ARP; |
Jonathan Hart | 3217d1b | 2015-06-30 16:08:43 -0700 | [diff] [blame] | 24 | import org.onlab.packet.EthType; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 25 | import org.onlab.packet.Ethernet; |
| 26 | import org.onlab.packet.IPv4; |
Pingping Lin | c9e16bf | 2015-04-10 14:42:41 -0700 | [diff] [blame] | 27 | import org.onlab.packet.Ip4Address; |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 28 | import org.onlab.packet.Ip6Address; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 29 | import org.onlab.packet.IpAddress; |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 30 | import org.onlab.packet.IpPrefix; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 31 | import org.onlab.packet.MacAddress; |
| 32 | import org.onosproject.core.ApplicationId; |
| 33 | import org.onosproject.core.CoreService; |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 34 | import org.onosproject.incubator.net.intf.Interface; |
| 35 | import org.onosproject.incubator.net.intf.InterfaceService; |
Jonathan Hart | 92ca5d3 | 2016-04-14 18:05:52 -0700 | [diff] [blame] | 36 | import org.onosproject.incubator.net.routing.Route; |
| 37 | import org.onosproject.incubator.net.routing.RouteService; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 38 | import org.onosproject.net.ConnectPoint; |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 39 | import org.onosproject.net.Host; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 40 | import org.onosproject.net.flow.DefaultTrafficSelector; |
| 41 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
| 42 | import org.onosproject.net.flow.TrafficSelector; |
| 43 | import org.onosproject.net.flow.TrafficTreatment; |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 44 | import org.onosproject.net.host.HostService; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 45 | import org.onosproject.net.packet.DefaultOutboundPacket; |
| 46 | import org.onosproject.net.packet.InboundPacket; |
| 47 | import org.onosproject.net.packet.OutboundPacket; |
| 48 | import org.onosproject.net.packet.PacketContext; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 49 | import org.onosproject.net.packet.PacketProcessor; |
| 50 | import org.onosproject.net.packet.PacketService; |
Jonathan Hart | 470ed4f | 2017-01-31 16:52:28 -0800 | [diff] [blame] | 51 | import org.onosproject.intentsync.IntentSynchronizationService; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 52 | import org.slf4j.Logger; |
| 53 | |
Jonathan Hart | 92ca5d3 | 2016-04-14 18:05:52 -0700 | [diff] [blame] | 54 | import java.nio.ByteBuffer; |
| 55 | import java.util.Optional; |
| 56 | import java.util.Set; |
| 57 | |
| 58 | import static com.google.common.base.Preconditions.checkNotNull; |
| 59 | import static org.onlab.packet.Ethernet.TYPE_ARP; |
| 60 | import static org.onlab.packet.Ethernet.TYPE_IPV4; |
| 61 | import static org.onosproject.net.packet.PacketPriority.REACTIVE; |
| 62 | import static org.slf4j.LoggerFactory.getLogger; |
| 63 | |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 64 | /** |
| 65 | * This is reactive routing to handle 3 cases: |
| 66 | * (1) one host wants to talk to another host, both two hosts are in |
| 67 | * SDN network. |
| 68 | * (2) one host in SDN network wants to talk to another host in Internet. |
| 69 | * (3) one host from Internet wants to talk to another host in SDN network. |
| 70 | */ |
| 71 | @Component(immediate = true) |
| 72 | public class SdnIpReactiveRouting { |
| 73 | |
| 74 | private static final String APP_NAME = "org.onosproject.reactive.routing"; |
| 75 | private final Logger log = getLogger(getClass()); |
| 76 | |
| 77 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 78 | protected CoreService coreService; |
| 79 | |
| 80 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 81 | protected PacketService packetService; |
| 82 | |
| 83 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
Jonathan Hart | 92ca5d3 | 2016-04-14 18:05:52 -0700 | [diff] [blame] | 84 | protected RouteService routeService; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 85 | |
Pingping Lin | c9e16bf | 2015-04-10 14:42:41 -0700 | [diff] [blame] | 86 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
Jonathan Hart | 365335e | 2015-12-10 11:09:53 -0800 | [diff] [blame] | 87 | protected IntentSynchronizationService intentSynchronizer; |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 88 | |
| 89 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
Jonathan Hart | bb782be | 2017-02-09 17:45:49 -0800 | [diff] [blame] | 90 | protected ReactiveRoutingConfigurationService config; |
Pingping Lin | c9e16bf | 2015-04-10 14:42:41 -0700 | [diff] [blame] | 91 | |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 92 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 93 | protected InterfaceService interfaceService; |
| 94 | |
| 95 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 96 | protected HostService hostService; |
| 97 | |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 98 | private ApplicationId appId; |
| 99 | |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 100 | private IntentRequestListener intentRequestListener; |
| 101 | |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 102 | private ReactiveRoutingProcessor processor = |
| 103 | new ReactiveRoutingProcessor(); |
| 104 | |
| 105 | @Activate |
| 106 | public void activate() { |
| 107 | appId = coreService.registerApplication(APP_NAME); |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 108 | intentRequestListener = new ReactiveRoutingFib(appId, hostService, |
Pingping Lin | 9a445c8 | 2016-04-07 11:40:29 -0700 | [diff] [blame] | 109 | interfaceService, intentSynchronizer); |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 110 | |
Brian O'Connor | 3b78326 | 2015-07-29 17:49:24 -0700 | [diff] [blame] | 111 | packetService.addProcessor(processor, PacketProcessor.director(2)); |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 112 | requestIntercepts(); |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 113 | log.info("SDN-IP Reactive Routing Started"); |
| 114 | } |
| 115 | |
| 116 | @Deactivate |
| 117 | public void deactivate() { |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 118 | withdrawIntercepts(); |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 119 | packetService.removeProcessor(processor); |
| 120 | processor = null; |
| 121 | log.info("SDN-IP Reactive Routing Stopped"); |
| 122 | } |
| 123 | |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 124 | /** |
| 125 | * Request packet in via the PacketService. |
| 126 | */ |
| 127 | private void requestIntercepts() { |
| 128 | //TODO: to support IPv6 later |
| 129 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| 130 | selector.matchEthType(TYPE_IPV4); |
Thomas Vachuska | c19d829 | 2015-07-06 14:11:34 -0700 | [diff] [blame] | 131 | packetService.requestPackets(selector.build(), REACTIVE, appId); |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 132 | selector.matchEthType(TYPE_ARP); |
Thomas Vachuska | c19d829 | 2015-07-06 14:11:34 -0700 | [diff] [blame] | 133 | packetService.requestPackets(selector.build(), REACTIVE, appId); |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | /** |
| 137 | * Cancel request for packet in via PacketService. |
| 138 | */ |
| 139 | private void withdrawIntercepts() { |
| 140 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| 141 | selector.matchEthType(TYPE_IPV4); |
Thomas Vachuska | c19d829 | 2015-07-06 14:11:34 -0700 | [diff] [blame] | 142 | packetService.cancelPackets(selector.build(), REACTIVE, appId); |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 143 | selector = DefaultTrafficSelector.builder(); |
| 144 | selector.matchEthType(TYPE_ARP); |
Thomas Vachuska | c19d829 | 2015-07-06 14:11:34 -0700 | [diff] [blame] | 145 | packetService.cancelPackets(selector.build(), REACTIVE, appId); |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 146 | } |
| 147 | |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 148 | private class ReactiveRoutingProcessor implements PacketProcessor { |
| 149 | @Override |
| 150 | public void process(PacketContext context) { |
| 151 | |
| 152 | InboundPacket pkt = context.inPacket(); |
| 153 | Ethernet ethPkt = pkt.parsed(); |
| 154 | if (ethPkt == null) { |
| 155 | return; |
| 156 | } |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 157 | ConnectPoint srcConnectPoint = pkt.receivedFrom(); |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 158 | |
Jonathan Hart | 3217d1b | 2015-06-30 16:08:43 -0700 | [diff] [blame] | 159 | switch (EthType.EtherType.lookup(ethPkt.getEtherType())) { |
| 160 | case ARP: |
Pingping Lin | c9e16bf | 2015-04-10 14:42:41 -0700 | [diff] [blame] | 161 | ARP arpPacket = (ARP) ethPkt.getPayload(); |
| 162 | Ip4Address targetIpAddress = Ip4Address |
| 163 | .valueOf(arpPacket.getTargetProtocolAddress()); |
| 164 | // Only when it is an ARP request packet and the target IP |
| 165 | // address is a virtual gateway IP address, then it will be |
| 166 | // processed. |
| 167 | if (arpPacket.getOpCode() == ARP.OP_REQUEST |
| 168 | && config.isVirtualGatewayIpAddress(targetIpAddress)) { |
| 169 | MacAddress gatewayMacAddress = |
| 170 | config.getVirtualGatewayMacAddress(); |
| 171 | if (gatewayMacAddress == null) { |
| 172 | break; |
| 173 | } |
| 174 | Ethernet eth = ARP.buildArpReply(targetIpAddress, |
| 175 | gatewayMacAddress, |
| 176 | ethPkt); |
| 177 | |
| 178 | TrafficTreatment.Builder builder = |
| 179 | DefaultTrafficTreatment.builder(); |
| 180 | builder.setOutput(srcConnectPoint.port()); |
| 181 | packetService.emit(new DefaultOutboundPacket( |
| 182 | srcConnectPoint.deviceId(), |
| 183 | builder.build(), |
| 184 | ByteBuffer.wrap(eth.serialize()))); |
| 185 | } |
| 186 | break; |
Jonathan Hart | 3217d1b | 2015-06-30 16:08:43 -0700 | [diff] [blame] | 187 | case IPV4: |
Pingping Lin | c9e16bf | 2015-04-10 14:42:41 -0700 | [diff] [blame] | 188 | // Parse packet |
| 189 | IPv4 ipv4Packet = (IPv4) ethPkt.getPayload(); |
| 190 | IpAddress dstIp = |
| 191 | IpAddress.valueOf(ipv4Packet.getDestinationAddress()); |
| 192 | IpAddress srcIp = |
| 193 | IpAddress.valueOf(ipv4Packet.getSourceAddress()); |
| 194 | MacAddress srcMac = ethPkt.getSourceMAC(); |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 195 | packetReactiveProcessor(dstIp, srcIp, srcConnectPoint, srcMac); |
Pingping Lin | c9e16bf | 2015-04-10 14:42:41 -0700 | [diff] [blame] | 196 | |
| 197 | // TODO emit packet first or packetReactiveProcessor first |
| 198 | ConnectPoint egressConnectPoint = null; |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 199 | egressConnectPoint = getEgressConnectPoint(dstIp); |
Pingping Lin | c9e16bf | 2015-04-10 14:42:41 -0700 | [diff] [blame] | 200 | if (egressConnectPoint != null) { |
| 201 | forwardPacketToDst(context, egressConnectPoint); |
| 202 | } |
| 203 | break; |
| 204 | default: |
| 205 | break; |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 206 | } |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | /** |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 211 | * Routes packet reactively. |
| 212 | * |
| 213 | * @param dstIpAddress the destination IP address of a packet |
| 214 | * @param srcIpAddress the source IP address of a packet |
| 215 | * @param srcConnectPoint the connect point where a packet comes from |
| 216 | * @param srcMacAddress the source MAC address of a packet |
| 217 | */ |
| 218 | private void packetReactiveProcessor(IpAddress dstIpAddress, |
| 219 | IpAddress srcIpAddress, |
| 220 | ConnectPoint srcConnectPoint, |
| 221 | MacAddress srcMacAddress) { |
| 222 | checkNotNull(dstIpAddress); |
| 223 | checkNotNull(srcIpAddress); |
| 224 | checkNotNull(srcConnectPoint); |
| 225 | checkNotNull(srcMacAddress); |
| 226 | |
| 227 | // |
| 228 | // Step1: Try to update the existing intent first if it exists. |
| 229 | // |
| 230 | IpPrefix ipPrefix = null; |
Jonathan Hart | 92ca5d3 | 2016-04-14 18:05:52 -0700 | [diff] [blame] | 231 | Route route = null; |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 232 | if (config.isIpAddressLocal(dstIpAddress)) { |
| 233 | if (dstIpAddress.isIp4()) { |
| 234 | ipPrefix = IpPrefix.valueOf(dstIpAddress, |
| 235 | Ip4Address.BIT_LENGTH); |
| 236 | } else { |
| 237 | ipPrefix = IpPrefix.valueOf(dstIpAddress, |
| 238 | Ip6Address.BIT_LENGTH); |
| 239 | } |
| 240 | } else { |
| 241 | // Get IP prefix from BGP route table |
Jonathan Hart | 92ca5d3 | 2016-04-14 18:05:52 -0700 | [diff] [blame] | 242 | route = routeService.longestPrefixMatch(dstIpAddress); |
| 243 | if (route != null) { |
| 244 | ipPrefix = route.prefix(); |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 245 | } |
| 246 | } |
| 247 | if (ipPrefix != null |
| 248 | && intentRequestListener.mp2pIntentExists(ipPrefix)) { |
| 249 | intentRequestListener.updateExistingMp2pIntent(ipPrefix, |
| 250 | srcConnectPoint); |
| 251 | return; |
| 252 | } |
| 253 | |
| 254 | // |
| 255 | // Step2: There is no existing intent for the destination IP address. |
| 256 | // Check whether it is necessary to create a new one. If necessary then |
| 257 | // create a new one. |
| 258 | // |
| 259 | TrafficType trafficType = |
| 260 | trafficTypeClassifier(srcConnectPoint, dstIpAddress); |
| 261 | |
| 262 | switch (trafficType) { |
| 263 | case HOST_TO_INTERNET: |
| 264 | // If the destination IP address is outside the local SDN network. |
| 265 | // The Step 1 has already handled it. We do not need to do anything here. |
| 266 | intentRequestListener.setUpConnectivityHostToInternet(srcIpAddress, |
Jonathan Hart | 92ca5d3 | 2016-04-14 18:05:52 -0700 | [diff] [blame] | 267 | ipPrefix, route.nextHop()); |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 268 | break; |
| 269 | case INTERNET_TO_HOST: |
| 270 | intentRequestListener.setUpConnectivityInternetToHost(dstIpAddress); |
| 271 | break; |
| 272 | case HOST_TO_HOST: |
| 273 | intentRequestListener.setUpConnectivityHostToHost(dstIpAddress, |
| 274 | srcIpAddress, srcMacAddress, srcConnectPoint); |
| 275 | break; |
| 276 | case INTERNET_TO_INTERNET: |
| 277 | log.trace("This is transit traffic, " |
| 278 | + "the intent should be preinstalled already"); |
| 279 | break; |
| 280 | case DROP: |
| 281 | // TODO here should setUpDropPacketIntent(...); |
| 282 | // We need a new type of intent here. |
| 283 | break; |
| 284 | case UNKNOWN: |
| 285 | log.trace("This is unknown traffic, so we do nothing"); |
| 286 | break; |
| 287 | default: |
| 288 | break; |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | /** |
| 293 | * Classifies the traffic and return the traffic type. |
| 294 | * |
| 295 | * @param srcConnectPoint the connect point where the packet comes from |
| 296 | * @param dstIp the destination IP address in packet |
| 297 | * @return the traffic type which this packet belongs to |
| 298 | */ |
| 299 | private TrafficType trafficTypeClassifier(ConnectPoint srcConnectPoint, |
Pingping Lin | 9a445c8 | 2016-04-07 11:40:29 -0700 | [diff] [blame] | 300 | IpAddress dstIp) { |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 301 | LocationType dstIpLocationType = getLocationType(dstIp); |
| 302 | Optional<Interface> srcInterface = |
| 303 | interfaceService.getInterfacesByPort(srcConnectPoint).stream().findFirst(); |
Pingping Lin | 9a445c8 | 2016-04-07 11:40:29 -0700 | [diff] [blame] | 304 | |
| 305 | Set<ConnectPoint> bgpPeerConnectPoints = config.getBgpPeerConnectPoints(); |
| 306 | |
| 307 | |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 308 | |
| 309 | switch (dstIpLocationType) { |
| 310 | case INTERNET: |
Pingping Lin | 9b85c03 | 2015-10-05 18:16:27 -0700 | [diff] [blame] | 311 | if (srcInterface.isPresent() && |
Pingping Lin | 9a445c8 | 2016-04-07 11:40:29 -0700 | [diff] [blame] | 312 | (!bgpPeerConnectPoints.contains(srcConnectPoint))) { |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 313 | return TrafficType.HOST_TO_INTERNET; |
| 314 | } else { |
| 315 | return TrafficType.INTERNET_TO_INTERNET; |
| 316 | } |
| 317 | case LOCAL: |
Pingping Lin | 9b85c03 | 2015-10-05 18:16:27 -0700 | [diff] [blame] | 318 | if (srcInterface.isPresent() && |
Pingping Lin | 9a445c8 | 2016-04-07 11:40:29 -0700 | [diff] [blame] | 319 | (!bgpPeerConnectPoints.contains(srcConnectPoint))) { |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 320 | return TrafficType.HOST_TO_HOST; |
| 321 | } else { |
| 322 | // TODO Currently we only consider local public prefixes. |
| 323 | // In the future, we will consider the local private prefixes. |
| 324 | // If dstIpLocationType is a local private, we should return |
| 325 | // TrafficType.DROP. |
| 326 | return TrafficType.INTERNET_TO_HOST; |
| 327 | } |
| 328 | case NO_ROUTE: |
| 329 | return TrafficType.DROP; |
| 330 | default: |
| 331 | return TrafficType.UNKNOWN; |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /** |
| 336 | * Evaluates the location of an IP address and returns the location type. |
| 337 | * |
| 338 | * @param ipAddress the IP address to evaluate |
| 339 | * @return the IP address location type |
| 340 | */ |
| 341 | private LocationType getLocationType(IpAddress ipAddress) { |
| 342 | if (config.isIpAddressLocal(ipAddress)) { |
| 343 | return LocationType.LOCAL; |
Jonathan Hart | 92ca5d3 | 2016-04-14 18:05:52 -0700 | [diff] [blame] | 344 | } else if (routeService.longestPrefixMatch(ipAddress) != null) { |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 345 | return LocationType.INTERNET; |
| 346 | } else { |
| 347 | return LocationType.NO_ROUTE; |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress) { |
| 352 | LocationType type = getLocationType(dstIpAddress); |
| 353 | if (type == LocationType.LOCAL) { |
| 354 | Set<Host> hosts = hostService.getHostsByIp(dstIpAddress); |
| 355 | if (!hosts.isEmpty()) { |
| 356 | return hosts.iterator().next().location(); |
| 357 | } else { |
| 358 | hostService.startMonitoringIp(dstIpAddress); |
| 359 | return null; |
| 360 | } |
| 361 | } else if (type == LocationType.INTERNET) { |
| 362 | IpAddress nextHopIpAddress = null; |
Jonathan Hart | 92ca5d3 | 2016-04-14 18:05:52 -0700 | [diff] [blame] | 363 | Route route = routeService.longestPrefixMatch(dstIpAddress); |
| 364 | if (route != null) { |
| 365 | nextHopIpAddress = route.nextHop(); |
Jonathan Hart | 9a426f8 | 2015-09-03 15:43:13 +0200 | [diff] [blame] | 366 | Interface it = interfaceService.getMatchingInterface(nextHopIpAddress); |
| 367 | if (it != null) { |
| 368 | return it.connectPoint(); |
| 369 | } else { |
| 370 | return null; |
| 371 | } |
| 372 | } else { |
| 373 | return null; |
| 374 | } |
| 375 | } else { |
| 376 | return null; |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | /** |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 381 | * Emits the specified packet onto the network. |
| 382 | * |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 383 | * @param context the packet context |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 384 | * @param connectPoint the connect point where the packet should be |
Aaron Kruglikov | 07a923d | 2015-07-03 13:30:57 -0700 | [diff] [blame] | 385 | * sent out |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 386 | */ |
| 387 | private void forwardPacketToDst(PacketContext context, |
| 388 | ConnectPoint connectPoint) { |
| 389 | TrafficTreatment treatment = DefaultTrafficTreatment.builder() |
| 390 | .setOutput(connectPoint.port()).build(); |
| 391 | OutboundPacket packet = |
| 392 | new DefaultOutboundPacket(connectPoint.deviceId(), treatment, |
| 393 | context.inPacket().unparsed()); |
| 394 | packetService.emit(packet); |
| 395 | log.trace("sending packet: {}", packet); |
| 396 | } |
Pingping Lin | e28ae4c | 2015-03-13 11:37:03 -0700 | [diff] [blame] | 397 | } |
| 398 | |