blob: f26aab38d0e958c32fbf9a0bc57b03f087762834 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Jonathan Hart335ef462014-10-16 08:20:46 -070016package org.onlab.onos.sdnip;
17
Pingping3855f312014-10-22 12:50:37 -070018import java.util.Collection;
Pingping3855f312014-10-22 12:50:37 -070019import java.util.HashSet;
20import java.util.Iterator;
21import java.util.LinkedList;
22import java.util.List;
Pingping3855f312014-10-22 12:50:37 -070023import java.util.Set;
24import java.util.concurrent.BlockingQueue;
Pingping3855f312014-10-22 12:50:37 -070025import java.util.concurrent.ExecutorService;
26import java.util.concurrent.Executors;
27import java.util.concurrent.LinkedBlockingQueue;
Pingping3855f312014-10-22 12:50:37 -070028
Thomas Vachuskae0f804a2014-10-27 23:40:48 -070029import org.onlab.onos.core.ApplicationId;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070030import org.onlab.onos.net.ConnectPoint;
31import org.onlab.onos.net.Host;
32import org.onlab.onos.net.flow.DefaultTrafficSelector;
33import org.onlab.onos.net.flow.DefaultTrafficTreatment;
34import org.onlab.onos.net.flow.TrafficSelector;
35import org.onlab.onos.net.flow.TrafficTreatment;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070036import org.onlab.onos.net.host.HostEvent;
37import org.onlab.onos.net.host.HostListener;
38import org.onlab.onos.net.host.HostService;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070039import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
40import org.onlab.onos.sdnip.config.BgpPeer;
41import org.onlab.onos.sdnip.config.Interface;
42import org.onlab.onos.sdnip.config.SdnIpConfigService;
43import org.onlab.packet.Ethernet;
44import org.onlab.packet.IpAddress;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080045import org.onlab.packet.Ip4Address;
46import org.onlab.packet.Ip4Prefix;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070047import org.onlab.packet.MacAddress;
48import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
Pingping3855f312014-10-22 12:50:37 -070051import com.google.common.collect.HashMultimap;
52import com.google.common.collect.Multimaps;
53import com.google.common.collect.SetMultimap;
54import com.google.common.util.concurrent.ThreadFactoryBuilder;
55import com.googlecode.concurrenttrees.common.KeyValuePair;
56import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
57import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
58import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart335ef462014-10-16 08:20:46 -070059
Jonathan Hart335ef462014-10-16 08:20:46 -070060/**
61 * This class processes BGP route update, translates each update into a intent
62 * and submits the intent.
Jonathan Hart335ef462014-10-16 08:20:46 -070063 */
64public class Router implements RouteListener {
65
66 private static final Logger log = LoggerFactory.getLogger(Router.class);
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080067 // For routes announced by local BGP daemon in SDN network,
68 // the next hop will be 0.0.0.0.
69 private static final Ip4Address LOCAL_NEXT_HOP =
70 Ip4Address.valueOf("0.0.0.0");
Jonathan Hart335ef462014-10-16 08:20:46 -070071
Jonathan Hart0b04bed2014-10-16 16:39:19 -070072 // Store all route updates in a radix tree.
73 // The key in this tree is the binary string of prefix of the route.
Jonathan Hart335ef462014-10-16 08:20:46 -070074 private InvertedRadixTree<RouteEntry> bgpRoutes;
75
76 // Stores all incoming route updates in a queue.
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080077 private final BlockingQueue<RouteUpdate> routeUpdates;
Jonathan Hart335ef462014-10-16 08:20:46 -070078
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080079 // The Ip4Address is the next hop address of each route update.
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080080 private final SetMultimap<Ip4Address, RouteEntry> routesWaitingOnArp;
Jonathan Hart335ef462014-10-16 08:20:46 -070081
Thomas Vachuskab97cf282014-10-20 23:31:12 -070082 private final ApplicationId appId;
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080083 private final IntentSynchronizer intentSynchronizer;
84 private final HostService hostService;
85 private final SdnIpConfigService configService;
86 private final InterfaceService interfaceService;
87 private final ExecutorService bgpUpdatesExecutor;
88 private final HostListener hostListener;
Jonathan Hart335ef462014-10-16 08:20:46 -070089
90 /**
91 * Class constructor.
92 *
Jonathan Hart31582d12014-10-22 13:52:41 -070093 * @param appId the application ID
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080094 * @param intentSynchronizer the intent synchronizer
Jonathan Hart31582d12014-10-22 13:52:41 -070095 * @param configService the configuration service
Thomas Vachuskab97cf282014-10-20 23:31:12 -070096 * @param interfaceService the interface service
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -080097 * @param hostService the host service
Jonathan Hart335ef462014-10-16 08:20:46 -070098 */
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080099 public Router(ApplicationId appId, IntentSynchronizer intentSynchronizer,
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800100 SdnIpConfigService configService,
101 InterfaceService interfaceService,
102 HostService hostService) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700103 this.appId = appId;
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800104 this.intentSynchronizer = intentSynchronizer;
Jonathan Hart31582d12014-10-22 13:52:41 -0700105 this.configService = configService;
Jonathan Hart335ef462014-10-16 08:20:46 -0700106 this.interfaceService = interfaceService;
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800107 this.hostService = hostService;
Jonathan Hart335ef462014-10-16 08:20:46 -0700108
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800109 this.hostListener = new InternalHostListener();
110
Jonathan Hart335ef462014-10-16 08:20:46 -0700111 bgpRoutes = new ConcurrentInvertedRadixTree<>(
112 new DefaultByteArrayNodeFactory());
113 routeUpdates = new LinkedBlockingQueue<>();
114 routesWaitingOnArp = Multimaps.synchronizedSetMultimap(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800115 HashMultimap.<Ip4Address, RouteEntry>create());
Jonathan Hart335ef462014-10-16 08:20:46 -0700116
117 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
Pavlin Radoslavov8b752442014-11-18 14:34:37 -0800118 new ThreadFactoryBuilder()
119 .setNameFormat("sdnip-bgp-updates-%d").build());
Jonathan Hart335ef462014-10-16 08:20:46 -0700120 }
121
122 /**
Jonathan Hart739c8352014-10-29 17:49:26 -0700123 * Starts the router.
Jonathan Hart335ef462014-10-16 08:20:46 -0700124 */
125 public void start() {
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800126 this.hostService.addListener(hostListener);
127
Jonathan Hart335ef462014-10-16 08:20:46 -0700128 bgpUpdatesExecutor.execute(new Runnable() {
129 @Override
130 public void run() {
131 doUpdatesThread();
132 }
133 });
Jonathan Hart335ef462014-10-16 08:20:46 -0700134 }
135
Jonathan Hart739c8352014-10-29 17:49:26 -0700136 /**
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800137 * Stops the router.
Jonathan Hart739c8352014-10-29 17:49:26 -0700138 */
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800139 public void stop() {
140 this.hostService.removeListener(hostListener);
141
142 // Stop the thread(s)
Jonathan Hart739c8352014-10-29 17:49:26 -0700143 bgpUpdatesExecutor.shutdownNow();
Pavlin Radoslavov7e190942014-11-13 18:50:59 -0800144
145 synchronized (this) {
146 // Cleanup all local state
147 bgpRoutes = new ConcurrentInvertedRadixTree<>(
148 new DefaultByteArrayNodeFactory());
149 routeUpdates.clear();
150 routesWaitingOnArp.clear();
Pavlin Radoslavov7e190942014-11-13 18:50:59 -0800151 }
Jonathan Hart739c8352014-10-29 17:49:26 -0700152 }
153
Jonathan Hart335ef462014-10-16 08:20:46 -0700154 @Override
155 public void update(RouteUpdate routeUpdate) {
Jonathan Hart31582d12014-10-22 13:52:41 -0700156 log.debug("Received new route update: {}", routeUpdate);
Jonathan Hart335ef462014-10-16 08:20:46 -0700157
158 try {
159 routeUpdates.put(routeUpdate);
160 } catch (InterruptedException e) {
161 log.debug("Interrupted while putting on routeUpdates queue", e);
162 Thread.currentThread().interrupt();
163 }
164 }
165
166 /**
Jonathan Hart335ef462014-10-16 08:20:46 -0700167 * Thread for handling route updates.
168 */
169 private void doUpdatesThread() {
170 boolean interrupted = false;
171 try {
172 while (!interrupted) {
173 try {
174 RouteUpdate update = routeUpdates.take();
175 switch (update.type()) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700176 case UPDATE:
177 processRouteAdd(update.routeEntry());
178 break;
179 case DELETE:
180 processRouteDelete(update.routeEntry());
181 break;
182 default:
183 log.error("Unknown update Type: {}", update.type());
184 break;
Jonathan Hart335ef462014-10-16 08:20:46 -0700185 }
186 } catch (InterruptedException e) {
187 log.debug("Interrupted while taking from updates queue", e);
188 interrupted = true;
189 } catch (Exception e) {
190 log.debug("exception", e);
191 }
192 }
193 } finally {
194 if (interrupted) {
195 Thread.currentThread().interrupt();
196 }
197 }
198 }
199
200 /**
Jonathan Hart335ef462014-10-16 08:20:46 -0700201 * Processes adding a route entry.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700202 * <p>
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700203 * Put new route entry into the radix tree. If there was an existing
204 * next hop for this prefix, but the next hop was different, then execute
Jonathan Hart335ef462014-10-16 08:20:46 -0700205 * deleting old route entry. If the next hop is the SDN domain, we do not
206 * handle it at the moment. Otherwise, execute adding a route.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700207 * </p>
Jonathan Hart335ef462014-10-16 08:20:46 -0700208 *
209 * @param routeEntry the route entry to add
210 */
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800211 void processRouteAdd(RouteEntry routeEntry) {
Jonathan Hart335ef462014-10-16 08:20:46 -0700212 synchronized (this) {
213 log.debug("Processing route add: {}", routeEntry);
214
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800215 Ip4Prefix prefix = routeEntry.prefix();
216 Ip4Address nextHop = null;
Jonathan Hart335ef462014-10-16 08:20:46 -0700217 RouteEntry foundRouteEntry =
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700218 bgpRoutes.put(RouteEntry.createBinaryString(prefix),
219 routeEntry);
Jonathan Hart335ef462014-10-16 08:20:46 -0700220 if (foundRouteEntry != null) {
221 nextHop = foundRouteEntry.nextHop();
222 }
223
224 if (nextHop != null && !nextHop.equals(routeEntry.nextHop())) {
225 // There was an existing nexthop for this prefix. This update
226 // supersedes that, so we need to remove the old flows for this
227 // prefix from the switches
228 executeRouteDelete(routeEntry);
229 }
230 if (nextHop != null && nextHop.equals(routeEntry.nextHop())) {
231 return;
232 }
233
234 if (routeEntry.nextHop().equals(LOCAL_NEXT_HOP)) {
235 // Route originated by SDN domain
236 // We don't handle these at the moment
237 log.debug("Own route {} to {}",
238 routeEntry.prefix(), routeEntry.nextHop());
239 return;
240 }
241
242 executeRouteAdd(routeEntry);
243 }
244 }
245
246 /**
247 * Executes adding a route entry.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700248 * <p>
Jonathan Hart335ef462014-10-16 08:20:46 -0700249 * Find out the egress Interface and MAC address of next hop router for
250 * this route entry. If the MAC address can not be found in ARP cache,
251 * then this prefix will be put in routesWaitingOnArp queue. Otherwise,
252 * new route intent will be created and installed.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700253 * </p>
Jonathan Hart335ef462014-10-16 08:20:46 -0700254 *
255 * @param routeEntry the route entry to add
256 */
257 private void executeRouteAdd(RouteEntry routeEntry) {
258 log.debug("Executing route add: {}", routeEntry);
259
Jonathan Hart31582d12014-10-22 13:52:41 -0700260 // Monitor the IP address so we'll get notified of updates to the MAC
261 // address.
262 hostService.startMonitoringIp(routeEntry.nextHop());
263
Jonathan Hart335ef462014-10-16 08:20:46 -0700264 // See if we know the MAC address of the next hop
Jonathan Hart335ef462014-10-16 08:20:46 -0700265 MacAddress nextHopMacAddress = null;
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700266 Set<Host> hosts = hostService.getHostsByIp(routeEntry.nextHop());
Jonathan Hart335ef462014-10-16 08:20:46 -0700267 if (!hosts.isEmpty()) {
268 // TODO how to handle if multiple hosts are returned?
269 nextHopMacAddress = hosts.iterator().next().mac();
270 }
271
272 if (nextHopMacAddress == null) {
273 routesWaitingOnArp.put(routeEntry.nextHop(), routeEntry);
Jonathan Hart335ef462014-10-16 08:20:46 -0700274 return;
275 }
276
277 addRouteIntentToNextHop(routeEntry.prefix(),
278 routeEntry.nextHop(),
279 nextHopMacAddress);
280 }
281
282 /**
283 * Adds a route intent given a prefix and a next hop IP address. This
284 * method will find the egress interface for the intent.
285 *
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700286 * @param prefix IP prefix of the route to add
287 * @param nextHopIpAddress IP address of the next hop
Jonathan Hart335ef462014-10-16 08:20:46 -0700288 * @param nextHopMacAddress MAC address of the next hop
289 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800290 private void addRouteIntentToNextHop(Ip4Prefix prefix,
291 Ip4Address nextHopIpAddress,
Jonathan Hart335ef462014-10-16 08:20:46 -0700292 MacAddress nextHopMacAddress) {
293
294 // Find the attachment point (egress interface) of the next hop
295 Interface egressInterface;
Jonathan Hart31582d12014-10-22 13:52:41 -0700296 if (configService.getBgpPeers().containsKey(nextHopIpAddress)) {
Jonathan Hart335ef462014-10-16 08:20:46 -0700297 // Route to a peer
298 log.debug("Route to peer {}", nextHopIpAddress);
299 BgpPeer peer =
Jonathan Hart31582d12014-10-22 13:52:41 -0700300 configService.getBgpPeers().get(nextHopIpAddress);
Jonathan Hart335ef462014-10-16 08:20:46 -0700301 egressInterface =
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700302 interfaceService.getInterface(peer.connectPoint());
Jonathan Hart335ef462014-10-16 08:20:46 -0700303 } else {
304 // Route to non-peer
305 log.debug("Route to non-peer {}", nextHopIpAddress);
306 egressInterface =
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700307 interfaceService.getMatchingInterface(nextHopIpAddress);
Jonathan Hart335ef462014-10-16 08:20:46 -0700308 if (egressInterface == null) {
309 log.warn("No outgoing interface found for {}",
310 nextHopIpAddress);
311 return;
312 }
313 }
314
315 doAddRouteIntent(prefix, egressInterface, nextHopMacAddress);
316 }
317
318 /**
319 * Installs a route intent for a prefix.
320 * <p/>
321 * Intent will match dst IP prefix and rewrite dst MAC address at all other
322 * border switches, then forward packets according to dst MAC address.
323 *
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700324 * @param prefix IP prefix from route
325 * @param egressInterface egress Interface connected to next hop router
Jonathan Hart335ef462014-10-16 08:20:46 -0700326 * @param nextHopMacAddress MAC address of next hop router
327 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800328 private void doAddRouteIntent(Ip4Prefix prefix, Interface egressInterface,
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700329 MacAddress nextHopMacAddress) {
Jonathan Hart335ef462014-10-16 08:20:46 -0700330 log.debug("Adding intent for prefix {}, next hop mac {}",
331 prefix, nextHopMacAddress);
332
Jonathan Hart335ef462014-10-16 08:20:46 -0700333 Set<ConnectPoint> ingressPorts = new HashSet<>();
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800334 ConnectPoint egressPort = egressInterface.connectPoint();
Jonathan Hart335ef462014-10-16 08:20:46 -0700335
336 for (Interface intf : interfaceService.getInterfaces()) {
Jonathan Hart2e3eef32014-11-12 11:05:40 -0800337 if (!intf.connectPoint().equals(egressInterface.connectPoint())) {
Jonathan Hart335ef462014-10-16 08:20:46 -0700338 ConnectPoint srcPort = intf.connectPoint();
339 ingressPorts.add(srcPort);
340 }
341 }
342
343 // Match the destination IP prefix at the first hop
Jonathan Hart335ef462014-10-16 08:20:46 -0700344 TrafficSelector selector = DefaultTrafficSelector.builder()
345 .matchEthType(Ethernet.TYPE_IPV4)
346 .matchIPDst(prefix)
347 .build();
348
349 // Rewrite the destination MAC address
Jonathan Hart335ef462014-10-16 08:20:46 -0700350 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
351 .setEthDst(nextHopMacAddress)
352 .build();
353
354 MultiPointToSinglePointIntent intent =
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700355 new MultiPointToSinglePointIntent(appId, selector, treatment,
356 ingressPorts, egressPort);
Jonathan Hart335ef462014-10-16 08:20:46 -0700357
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800358 intentSynchronizer.submitRouteIntent(prefix, intent);
Jonathan Hart335ef462014-10-16 08:20:46 -0700359 }
360
361 /**
362 * Executes deleting a route entry.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700363 * <p>
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700364 * Removes prefix from radix tree, and if successful, then try to delete
365 * the related intent.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700366 * </p>
Jonathan Hart335ef462014-10-16 08:20:46 -0700367 *
368 * @param routeEntry the route entry to delete
369 */
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800370 void processRouteDelete(RouteEntry routeEntry) {
Jonathan Hart335ef462014-10-16 08:20:46 -0700371 synchronized (this) {
372 log.debug("Processing route delete: {}", routeEntry);
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800373 Ip4Prefix prefix = routeEntry.prefix();
Jonathan Hart335ef462014-10-16 08:20:46 -0700374
Jonathan Hart335ef462014-10-16 08:20:46 -0700375 if (bgpRoutes.remove(RouteEntry.createBinaryString(prefix))) {
376 //
377 // Only delete flows if an entry was actually removed from the
378 // tree. If no entry was removed, the <prefix, nexthop> wasn't
379 // there so it's probably already been removed and we don't
380 // need to do anything.
381 //
382 executeRouteDelete(routeEntry);
383 }
384
385 routesWaitingOnArp.remove(routeEntry.nextHop(), routeEntry);
386 // TODO cancel the request in the ARP manager as well
387 }
388 }
389
390 /**
391 * Executed deleting a route entry.
392 *
393 * @param routeEntry the route entry to delete
394 */
395 private void executeRouteDelete(RouteEntry routeEntry) {
396 log.debug("Executing route delete: {}", routeEntry);
397
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800398 intentSynchronizer.withdrawRouteIntent(routeEntry.prefix());
Jonathan Hart335ef462014-10-16 08:20:46 -0700399 }
400
401 /**
Jonathan Hart31582d12014-10-22 13:52:41 -0700402 * Signals the Router that the MAC to IP mapping has potentially been
403 * updated. This has the effect of updating the MAC address for any
404 * installed prefixes if it has changed, as well as installing any pending
405 * prefixes that were waiting for MAC resolution.
Jonathan Hart335ef462014-10-16 08:20:46 -0700406 *
Jonathan Hart31582d12014-10-22 13:52:41 -0700407 * @param ipAddress the IP address that an event was received for
408 * @param macAddress the most recently known MAC address for the IP address
Jonathan Hart335ef462014-10-16 08:20:46 -0700409 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800410 private void updateMac(Ip4Address ipAddress, MacAddress macAddress) {
Jonathan Hart31582d12014-10-22 13:52:41 -0700411 log.debug("Received updated MAC info: {} => {}", ipAddress, macAddress);
412
413 // TODO here we should check whether the next hop for any of our
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800414 // installed prefixes has changed, not just prefixes pending
415 // installation.
Jonathan Hart335ef462014-10-16 08:20:46 -0700416
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700417 // We synchronize on this to prevent changes to the radix tree
418 // while we're pushing intents. If the tree changes, the
419 // tree and intents could get out of sync.
Jonathan Hart335ef462014-10-16 08:20:46 -0700420 synchronized (this) {
421
422 Set<RouteEntry> routesToPush =
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700423 routesWaitingOnArp.removeAll(ipAddress);
Jonathan Hart335ef462014-10-16 08:20:46 -0700424
425 for (RouteEntry routeEntry : routesToPush) {
426 // These will always be adds
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800427 Ip4Prefix prefix = routeEntry.prefix();
Jonathan Hart335ef462014-10-16 08:20:46 -0700428 String binaryString = RouteEntry.createBinaryString(prefix);
429 RouteEntry foundRouteEntry =
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700430 bgpRoutes.getValueForExactKey(binaryString);
Jonathan Hart335ef462014-10-16 08:20:46 -0700431 if (foundRouteEntry != null &&
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700432 foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
Jonathan Hart335ef462014-10-16 08:20:46 -0700433 // We only push prefix flows if the prefix is still in the
Jonathan Hart0b04bed2014-10-16 16:39:19 -0700434 // radix tree and the next hop is the same as our
Jonathan Hart335ef462014-10-16 08:20:46 -0700435 // update.
436 // The prefix could have been removed while we were waiting
437 // for the ARP, or the next hop could have changed.
438 addRouteIntentToNextHop(prefix, ipAddress, macAddress);
439 } else {
Jonathan Hart31582d12014-10-22 13:52:41 -0700440 log.debug("{} has been revoked before the MAC was resolved",
441 routeEntry);
Jonathan Hart335ef462014-10-16 08:20:46 -0700442 }
443 }
444 }
445 }
446
447 /**
448 * Gets the SDN-IP routes.
449 *
450 * @return the SDN-IP routes
451 */
452 public Collection<RouteEntry> getRoutes() {
453 Iterator<KeyValuePair<RouteEntry>> it =
454 bgpRoutes.getKeyValuePairsForKeysStartingWith("").iterator();
455
456 List<RouteEntry> routes = new LinkedList<>();
457
458 while (it.hasNext()) {
459 KeyValuePair<RouteEntry> entry = it.next();
460 routes.add(entry.getValue());
461 }
462
463 return routes;
464 }
465
466 /**
Jonathan Hart335ef462014-10-16 08:20:46 -0700467 * Listener for host events.
468 */
469 class InternalHostListener implements HostListener {
470 @Override
471 public void event(HostEvent event) {
472 if (event.type() == HostEvent.Type.HOST_ADDED ||
473 event.type() == HostEvent.Type.HOST_UPDATED) {
474 Host host = event.subject();
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700475 for (IpAddress ip : host.ipAddresses()) {
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800476 Ip4Address ip4Address = ip.getIp4Address();
477 if (ip4Address == null) {
478 // TODO: For now we support only IPv4
479 continue;
480 }
481 updateMac(ip4Address, host.mac());
Jonathan Hart335ef462014-10-16 08:20:46 -0700482 }
483 }
484 }
485 }
486}