Jonathan Hart
Committed by Gerrit Code Review

Modified BGP and FPM route sources to push to new route service.

Also created an adapter to adapt the new interface to the old one for
backwards compatibilty with existing FIB components.

Change-Id: If8eb2220d9e4e69af135a8f9469ffda567ed4448
...@@ -18,6 +18,7 @@ package org.onosproject.routing; ...@@ -18,6 +18,7 @@ package org.onosproject.routing;
18 /** 18 /**
19 * A source of route updates. 19 * A source of route updates.
20 */ 20 */
21 +@Deprecated
21 public interface RouteSourceService { 22 public interface RouteSourceService {
22 23
23 /** 24 /**
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.routing.bgp; 16 package org.onosproject.routing.bgp;
17 17
18 import org.onlab.packet.IpPrefix; 18 import org.onlab.packet.IpPrefix;
19 +import org.onosproject.incubator.net.routing.Route;
19 import org.onosproject.routing.RouteUpdate; 20 import org.onosproject.routing.RouteUpdate;
20 import org.slf4j.Logger; 21 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory; 22 import org.slf4j.LoggerFactory;
...@@ -45,15 +46,16 @@ class BgpRouteSelector { ...@@ -45,15 +46,16 @@ class BgpRouteSelector {
45 * Processes route entry updates: added/updated and deleted route 46 * Processes route entry updates: added/updated and deleted route
46 * entries. 47 * entries.
47 * 48 *
48 - * @param bgpSession the BGP session the route entry updates were
49 - * received on
50 * @param addedBgpRouteEntries the added/updated route entries to process 49 * @param addedBgpRouteEntries the added/updated route entries to process
51 * @param deletedBgpRouteEntries the deleted route entries to process 50 * @param deletedBgpRouteEntries the deleted route entries to process
52 */ 51 */
53 - synchronized void routeUpdates(BgpSession bgpSession, 52 + synchronized void routeUpdates(
54 Collection<BgpRouteEntry> addedBgpRouteEntries, 53 Collection<BgpRouteEntry> addedBgpRouteEntries,
55 Collection<BgpRouteEntry> deletedBgpRouteEntries) { 54 Collection<BgpRouteEntry> deletedBgpRouteEntries) {
56 - Collection<RouteUpdate> routeUpdates = new LinkedList<>(); 55 +
56 + Collection<Route> updates = new LinkedList<>();
57 + Collection<Route> withdraws = new LinkedList<>();
58 +
57 RouteUpdate routeUpdate; 59 RouteUpdate routeUpdate;
58 60
59 if (bgpSessionManager.isShutdown()) { 61 if (bgpSessionManager.isShutdown()) {
...@@ -61,32 +63,42 @@ class BgpRouteSelector { ...@@ -61,32 +63,42 @@ class BgpRouteSelector {
61 } 63 }
62 // Process the deleted route entries 64 // Process the deleted route entries
63 for (BgpRouteEntry bgpRouteEntry : deletedBgpRouteEntries) { 65 for (BgpRouteEntry bgpRouteEntry : deletedBgpRouteEntries) {
64 - routeUpdate = processDeletedRoute(bgpSession, bgpRouteEntry); 66 + routeUpdate = processDeletedRoute(bgpRouteEntry);
65 - if (routeUpdate != null) { 67 + convertRouteUpdateToRoute(routeUpdate, updates, withdraws);
66 - routeUpdates.add(routeUpdate);
67 - }
68 } 68 }
69 69
70 // Process the added/updated route entries 70 // Process the added/updated route entries
71 for (BgpRouteEntry bgpRouteEntry : addedBgpRouteEntries) { 71 for (BgpRouteEntry bgpRouteEntry : addedBgpRouteEntries) {
72 - routeUpdate = processAddedRoute(bgpSession, bgpRouteEntry); 72 + routeUpdate = processAddedRoute(bgpRouteEntry);
73 - if (routeUpdate != null) { 73 + convertRouteUpdateToRoute(routeUpdate, updates, withdraws);
74 - routeUpdates.add(routeUpdate); 74 + }
75 +
76 + bgpSessionManager.withdraw(withdraws);
77 + bgpSessionManager.update(updates);
78 + }
79 +
80 + private void convertRouteUpdateToRoute(RouteUpdate routeUpdate,
81 + Collection<Route> updates,
82 + Collection<Route> withdraws) {
83 + if (routeUpdate != null) {
84 + Route route = new Route(Route.Source.BGP, routeUpdate.routeEntry().prefix(),
85 + routeUpdate.routeEntry().nextHop());
86 + if (routeUpdate.type().equals(RouteUpdate.Type.UPDATE)) {
87 + updates.add(route);
88 + } else if (routeUpdate.type().equals(RouteUpdate.Type.DELETE)) {
89 + withdraws.add(route);
75 } 90 }
76 } 91 }
77 - bgpSessionManager.getRouteListener().update(routeUpdates);
78 } 92 }
79 93
80 /** 94 /**
81 * Processes an added/updated route entry. 95 * Processes an added/updated route entry.
82 * 96 *
83 - * @param bgpSession the BGP session the route entry update was received on
84 * @param bgpRouteEntry the added/updated route entry 97 * @param bgpRouteEntry the added/updated route entry
85 * @return the result route update that should be forwarded to the 98 * @return the result route update that should be forwarded to the
86 * Route Listener, or null if no route update should be forwarded 99 * Route Listener, or null if no route update should be forwarded
87 */ 100 */
88 - private RouteUpdate processAddedRoute(BgpSession bgpSession, 101 + private RouteUpdate processAddedRoute(BgpRouteEntry bgpRouteEntry) {
89 - BgpRouteEntry bgpRouteEntry) {
90 RouteUpdate routeUpdate; 102 RouteUpdate routeUpdate;
91 BgpRouteEntry bestBgpRouteEntry = 103 BgpRouteEntry bestBgpRouteEntry =
92 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix()); 104 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
...@@ -136,13 +148,11 @@ class BgpRouteSelector { ...@@ -136,13 +148,11 @@ class BgpRouteSelector {
136 /** 148 /**
137 * Processes a deleted route entry. 149 * Processes a deleted route entry.
138 * 150 *
139 - * @param bgpSession the BGP session the route entry update was received on
140 * @param bgpRouteEntry the deleted route entry 151 * @param bgpRouteEntry the deleted route entry
141 * @return the result route update that should be forwarded to the 152 * @return the result route update that should be forwarded to the
142 * Route Listener, or null if no route update should be forwarded 153 * Route Listener, or null if no route update should be forwarded
143 */ 154 */
144 - private RouteUpdate processDeletedRoute(BgpSession bgpSession, 155 + private RouteUpdate processDeletedRoute(BgpRouteEntry bgpRouteEntry) {
145 - BgpRouteEntry bgpRouteEntry) {
146 RouteUpdate routeUpdate; 156 RouteUpdate routeUpdate;
147 BgpRouteEntry bestBgpRouteEntry = 157 BgpRouteEntry bestBgpRouteEntry =
148 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix()); 158 bgpSessionManager.findBgpRoute(bgpRouteEntry.prefix());
......
...@@ -327,6 +327,7 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -327,6 +327,7 @@ public class BgpSession extends SimpleChannelHandler {
327 ctx.getChannel().getRemoteAddress(), 327 ctx.getChannel().getRemoteAddress(),
328 ctx.getChannel().getLocalAddress(), 328 ctx.getChannel().getLocalAddress(),
329 e); 329 e);
330 + log.debug("Exception:", e.getCause());
330 processChannelDisconnected(); 331 processChannelDisconnected();
331 } 332 }
332 333
...@@ -350,8 +351,8 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -350,8 +351,8 @@ public class BgpSession extends SimpleChannelHandler {
350 BgpRouteSelector bgpRouteSelector = 351 BgpRouteSelector bgpRouteSelector =
351 bgpSessionManager.getBgpRouteSelector(); 352 bgpSessionManager.getBgpRouteSelector();
352 Collection<BgpRouteEntry> addedRoutes = Collections.emptyList(); 353 Collection<BgpRouteEntry> addedRoutes = Collections.emptyList();
353 - bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes4); 354 + bgpRouteSelector.routeUpdates(addedRoutes, deletedRoutes4);
354 - bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes6); 355 + bgpRouteSelector.routeUpdates(addedRoutes, deletedRoutes6);
355 356
356 bgpSessionManager.peerDisconnected(this); 357 bgpSessionManager.peerDisconnected(this);
357 } 358 }
......
...@@ -19,6 +19,8 @@ import org.apache.felix.scr.annotations.Activate; ...@@ -19,6 +19,8 @@ import org.apache.felix.scr.annotations.Activate;
19 import org.apache.felix.scr.annotations.Component; 19 import org.apache.felix.scr.annotations.Component;
20 import org.apache.felix.scr.annotations.Deactivate; 20 import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Modified; 21 import org.apache.felix.scr.annotations.Modified;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
22 import org.apache.felix.scr.annotations.Service; 24 import org.apache.felix.scr.annotations.Service;
23 import org.jboss.netty.bootstrap.ServerBootstrap; 25 import org.jboss.netty.bootstrap.ServerBootstrap;
24 import org.jboss.netty.channel.Channel; 26 import org.jboss.netty.channel.Channel;
...@@ -34,8 +36,8 @@ import org.onlab.packet.Ip4Address; ...@@ -34,8 +36,8 @@ import org.onlab.packet.Ip4Address;
34 import org.onlab.packet.Ip4Prefix; 36 import org.onlab.packet.Ip4Prefix;
35 import org.onlab.packet.Ip6Prefix; 37 import org.onlab.packet.Ip6Prefix;
36 import org.onlab.packet.IpPrefix; 38 import org.onlab.packet.IpPrefix;
37 -import org.onosproject.routing.RouteSourceService; 39 +import org.onosproject.incubator.net.routing.Route;
38 -import org.onosproject.routing.RouteListener; 40 +import org.onosproject.incubator.net.routing.RouteAdminService;
39 import org.osgi.service.component.ComponentContext; 41 import org.osgi.service.component.ComponentContext;
40 import org.slf4j.Logger; 42 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory; 43 import org.slf4j.LoggerFactory;
...@@ -48,7 +50,6 @@ import java.util.Dictionary; ...@@ -48,7 +50,6 @@ import java.util.Dictionary;
48 import java.util.concurrent.ConcurrentHashMap; 50 import java.util.concurrent.ConcurrentHashMap;
49 import java.util.concurrent.ConcurrentMap; 51 import java.util.concurrent.ConcurrentMap;
50 52
51 -import static com.google.common.base.Preconditions.checkNotNull;
52 import static java.util.concurrent.Executors.newCachedThreadPool; 53 import static java.util.concurrent.Executors.newCachedThreadPool;
53 import static org.onlab.util.Tools.groupedThreads; 54 import static org.onlab.util.Tools.groupedThreads;
54 55
...@@ -57,10 +58,13 @@ import static org.onlab.util.Tools.groupedThreads; ...@@ -57,10 +58,13 @@ import static org.onlab.util.Tools.groupedThreads;
57 */ 58 */
58 @Component(immediate = true, enabled = false) 59 @Component(immediate = true, enabled = false)
59 @Service 60 @Service
60 -public class BgpSessionManager implements BgpInfoService, RouteSourceService { 61 +public class BgpSessionManager implements BgpInfoService {
61 private static final Logger log = 62 private static final Logger log =
62 LoggerFactory.getLogger(BgpSessionManager.class); 63 LoggerFactory.getLogger(BgpSessionManager.class);
63 64
65 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 + protected RouteAdminService routeService;
67 +
64 boolean isShutdown = true; 68 boolean isShutdown = true;
65 private Channel serverChannel; // Listener for incoming BGP connections 69 private Channel serverChannel; // Listener for incoming BGP connections
66 private ServerBootstrap serverBootstrap; 70 private ServerBootstrap serverBootstrap;
...@@ -75,19 +79,19 @@ public class BgpSessionManager implements BgpInfoService, RouteSourceService { ...@@ -75,19 +79,19 @@ public class BgpSessionManager implements BgpInfoService, RouteSourceService {
75 private ConcurrentMap<Ip6Prefix, BgpRouteEntry> bgpRoutes6 = 79 private ConcurrentMap<Ip6Prefix, BgpRouteEntry> bgpRoutes6 =
76 new ConcurrentHashMap<>(); 80 new ConcurrentHashMap<>();
77 81
78 - private RouteListener routeListener;
79 -
80 private static final int DEFAULT_BGP_PORT = 2000; 82 private static final int DEFAULT_BGP_PORT = 2000;
81 private int bgpPort; 83 private int bgpPort;
82 84
83 @Activate 85 @Activate
84 protected void activate(ComponentContext context) { 86 protected void activate(ComponentContext context) {
85 readComponentConfiguration(context); 87 readComponentConfiguration(context);
88 + start();
86 log.info("BgpSessionManager started"); 89 log.info("BgpSessionManager started");
87 } 90 }
88 91
89 @Deactivate 92 @Deactivate
90 protected void deactivate() { 93 protected void deactivate() {
94 + stop();
91 log.info("BgpSessionManager stopped"); 95 log.info("BgpSessionManager stopped");
92 } 96 }
93 97
...@@ -128,15 +132,6 @@ public class BgpSessionManager implements BgpInfoService, RouteSourceService { ...@@ -128,15 +132,6 @@ public class BgpSessionManager implements BgpInfoService, RouteSourceService {
128 } 132 }
129 133
130 /** 134 /**
131 - * Gets the route listener.
132 - *
133 - * @return the route listener to use
134 - */
135 - RouteListener getRouteListener() {
136 - return routeListener;
137 - }
138 -
139 - /**
140 * Gets the BGP sessions. 135 * Gets the BGP sessions.
141 * 136 *
142 * @return the BGP sessions 137 * @return the BGP sessions
...@@ -290,13 +285,29 @@ public class BgpSessionManager implements BgpInfoService, RouteSourceService { ...@@ -290,13 +285,29 @@ public class BgpSessionManager implements BgpInfoService, RouteSourceService {
290 return bgpRouteSelector; 285 return bgpRouteSelector;
291 } 286 }
292 287
293 - @Override 288 + /**
294 - public void start(RouteListener routeListener) { 289 + * Sends updates routes to the route service.
290 + *
291 + * @param updates routes to update
292 + */
293 + void update(Collection<Route> updates) {
294 + routeService.update(updates);
295 + }
296 +
297 + /**
298 + * Sends withdrawn routes to the routes service.
299 + *
300 + * @param withdraws routes to withdraw
301 + */
302 + void withdraw(Collection<Route> withdraws) {
303 + routeService.withdraw(withdraws);
304 + }
305 +
306 +
307 + public void start() {
295 log.debug("BGP Session Manager start."); 308 log.debug("BGP Session Manager start.");
296 isShutdown = false; 309 isShutdown = false;
297 310
298 - this.routeListener = checkNotNull(routeListener);
299 -
300 ChannelFactory channelFactory = new NioServerSocketChannelFactory( 311 ChannelFactory channelFactory = new NioServerSocketChannelFactory(
301 newCachedThreadPool(groupedThreads("onos/bgp", "sm-boss-%d")), 312 newCachedThreadPool(groupedThreads("onos/bgp", "sm-boss-%d")),
302 newCachedThreadPool(groupedThreads("onos/bgp", "sm-worker-%d"))); 313 newCachedThreadPool(groupedThreads("onos/bgp", "sm-worker-%d")));
...@@ -330,7 +341,6 @@ public class BgpSessionManager implements BgpInfoService, RouteSourceService { ...@@ -330,7 +341,6 @@ public class BgpSessionManager implements BgpInfoService, RouteSourceService {
330 } 341 }
331 } 342 }
332 343
333 - @Override
334 public void stop() { 344 public void stop() {
335 isShutdown = true; 345 isShutdown = true;
336 allChannels.close().awaitUninterruptibly(); 346 allChannels.close().awaitUninterruptibly();
......
...@@ -154,10 +154,10 @@ final class BgpUpdate { ...@@ -154,10 +154,10 @@ final class BgpUpdate {
154 // 154 //
155 BgpRouteSelector bgpRouteSelector = 155 BgpRouteSelector bgpRouteSelector =
156 bgpSession.getBgpSessionManager().getBgpRouteSelector(); 156 bgpSession.getBgpSessionManager().getBgpRouteSelector();
157 - bgpRouteSelector.routeUpdates(bgpSession, 157 + bgpRouteSelector.routeUpdates(
158 decodedBgpRoutes.addedUnicastRoutes4.values(), 158 decodedBgpRoutes.addedUnicastRoutes4.values(),
159 decodedBgpRoutes.deletedUnicastRoutes4.values()); 159 decodedBgpRoutes.deletedUnicastRoutes4.values());
160 - bgpRouteSelector.routeUpdates(bgpSession, 160 + bgpRouteSelector.routeUpdates(
161 decodedBgpRoutes.addedUnicastRoutes6.values(), 161 decodedBgpRoutes.addedUnicastRoutes6.values(),
162 decodedBgpRoutes.deletedUnicastRoutes6.values()); 162 decodedBgpRoutes.deletedUnicastRoutes6.values());
163 163
......
...@@ -15,18 +15,10 @@ ...@@ -15,18 +15,10 @@
15 */ 15 */
16 package org.onosproject.routing.config.impl; 16 package org.onosproject.routing.config.impl;
17 17
18 -import static org.onosproject.routing.RouteEntry.createBinaryString;
19 -
20 import com.google.common.collect.ImmutableSet; 18 import com.google.common.collect.ImmutableSet;
21 import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory; 19 import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
22 import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; 20 import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
23 import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; 21 import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
24 -
25 -import java.util.HashSet;
26 -import java.util.Objects;
27 -import java.util.Set;
28 -import java.util.stream.Collectors;
29 -
30 import org.apache.felix.scr.annotations.Activate; 22 import org.apache.felix.scr.annotations.Activate;
31 import org.apache.felix.scr.annotations.Component; 23 import org.apache.felix.scr.annotations.Component;
32 import org.apache.felix.scr.annotations.Deactivate; 24 import org.apache.felix.scr.annotations.Deactivate;
...@@ -48,15 +40,22 @@ import org.onosproject.net.config.NetworkConfigListener; ...@@ -48,15 +40,22 @@ import org.onosproject.net.config.NetworkConfigListener;
48 import org.onosproject.net.config.NetworkConfigRegistry; 40 import org.onosproject.net.config.NetworkConfigRegistry;
49 import org.onosproject.net.config.NetworkConfigService; 41 import org.onosproject.net.config.NetworkConfigService;
50 import org.onosproject.net.config.basics.SubjectFactories; 42 import org.onosproject.net.config.basics.SubjectFactories;
43 +import org.onosproject.routing.RoutingService;
51 import org.onosproject.routing.config.BgpConfig; 44 import org.onosproject.routing.config.BgpConfig;
52 import org.onosproject.routing.config.LocalIpPrefixEntry; 45 import org.onosproject.routing.config.LocalIpPrefixEntry;
53 import org.onosproject.routing.config.ReactiveRoutingConfig; 46 import org.onosproject.routing.config.ReactiveRoutingConfig;
54 import org.onosproject.routing.config.RouterConfig; 47 import org.onosproject.routing.config.RouterConfig;
55 import org.onosproject.routing.config.RoutingConfigurationService; 48 import org.onosproject.routing.config.RoutingConfigurationService;
56 -import org.onosproject.routing.impl.Router;
57 import org.slf4j.Logger; 49 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory; 50 import org.slf4j.LoggerFactory;
59 51
52 +import java.util.HashSet;
53 +import java.util.Objects;
54 +import java.util.Set;
55 +import java.util.stream.Collectors;
56 +
57 +import static org.onosproject.routing.RouteEntry.createBinaryString;
58 +
60 /** 59 /**
61 * Implementation of RoutingConfigurationService which reads routing 60 * Implementation of RoutingConfigurationService which reads routing
62 * configuration from a file. 61 * configuration from a file.
...@@ -165,7 +164,7 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService { ...@@ -165,7 +164,7 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
165 virtualGatewayMacAddress = config.virtualGatewayMacAddress(); 164 virtualGatewayMacAddress = config.virtualGatewayMacAddress();
166 165
167 // Setup BGP peer connect points 166 // Setup BGP peer connect points
168 - ApplicationId routerAppId = coreService.getAppId(Router.ROUTER_APP_ID); 167 + ApplicationId routerAppId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
169 if (routerAppId == null) { 168 if (routerAppId == null) {
170 log.info("Router application ID is null!"); 169 log.info("Router application ID is null!");
171 return; 170 return;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
15 */ 15 */
16 package org.onosproject.routing.fpm; 16 package org.onosproject.routing.fpm;
17 17
18 +import com.google.common.collect.ImmutableList;
18 import com.google.common.collect.ImmutableMap; 19 import com.google.common.collect.ImmutableMap;
19 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
...@@ -38,10 +39,8 @@ import org.onlab.packet.IpAddress; ...@@ -38,10 +39,8 @@ import org.onlab.packet.IpAddress;
38 import org.onlab.packet.IpPrefix; 39 import org.onlab.packet.IpPrefix;
39 import org.onlab.util.Tools; 40 import org.onlab.util.Tools;
40 import org.onosproject.cfg.ComponentConfigService; 41 import org.onosproject.cfg.ComponentConfigService;
41 -import org.onosproject.routing.RouteEntry; 42 +import org.onosproject.incubator.net.routing.Route;
42 -import org.onosproject.routing.RouteListener; 43 +import org.onosproject.incubator.net.routing.RouteAdminService;
43 -import org.onosproject.routing.RouteSourceService;
44 -import org.onosproject.routing.RouteUpdate;
45 import org.onosproject.routing.fpm.protocol.FpmHeader; 44 import org.onosproject.routing.fpm.protocol.FpmHeader;
46 import org.onosproject.routing.fpm.protocol.Netlink; 45 import org.onosproject.routing.fpm.protocol.Netlink;
47 import org.onosproject.routing.fpm.protocol.RouteAttribute; 46 import org.onosproject.routing.fpm.protocol.RouteAttribute;
...@@ -55,12 +54,11 @@ import org.slf4j.LoggerFactory; ...@@ -55,12 +54,11 @@ import org.slf4j.LoggerFactory;
55 54
56 import java.net.InetSocketAddress; 55 import java.net.InetSocketAddress;
57 import java.net.SocketAddress; 56 import java.net.SocketAddress;
58 -import java.util.Collections;
59 import java.util.Dictionary; 57 import java.util.Dictionary;
58 +import java.util.LinkedList;
60 import java.util.List; 59 import java.util.List;
61 import java.util.Map; 60 import java.util.Map;
62 import java.util.concurrent.ConcurrentHashMap; 61 import java.util.concurrent.ConcurrentHashMap;
63 -import java.util.stream.Collectors;
64 62
65 import static java.util.concurrent.Executors.newCachedThreadPool; 63 import static java.util.concurrent.Executors.newCachedThreadPool;
66 import static org.onlab.util.Tools.groupedThreads; 64 import static org.onlab.util.Tools.groupedThreads;
...@@ -70,7 +68,7 @@ import static org.onlab.util.Tools.groupedThreads; ...@@ -70,7 +68,7 @@ import static org.onlab.util.Tools.groupedThreads;
70 */ 68 */
71 @Service 69 @Service
72 @Component(immediate = true, enabled = false) 70 @Component(immediate = true, enabled = false)
73 -public class FpmManager implements RouteSourceService, FpmInfoService { 71 +public class FpmManager implements FpmInfoService {
74 private final Logger log = LoggerFactory.getLogger(getClass()); 72 private final Logger log = LoggerFactory.getLogger(getClass());
75 73
76 private static final int FPM_PORT = 2620; 74 private static final int FPM_PORT = 2620;
...@@ -78,15 +76,16 @@ public class FpmManager implements RouteSourceService, FpmInfoService { ...@@ -78,15 +76,16 @@ public class FpmManager implements RouteSourceService, FpmInfoService {
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected ComponentConfigService componentConfigService; 77 protected ComponentConfigService componentConfigService;
80 78
79 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 + protected RouteAdminService routeService;
81 +
81 private ServerBootstrap serverBootstrap; 82 private ServerBootstrap serverBootstrap;
82 private Channel serverChannel; 83 private Channel serverChannel;
83 private ChannelGroup allChannels = new DefaultChannelGroup(); 84 private ChannelGroup allChannels = new DefaultChannelGroup();
84 85
85 private Map<SocketAddress, Long> peers = new ConcurrentHashMap<>(); 86 private Map<SocketAddress, Long> peers = new ConcurrentHashMap<>();
86 87
87 - private Map<IpPrefix, RouteEntry> fpmRoutes = new ConcurrentHashMap<>(); 88 + private Map<IpPrefix, Route> fpmRoutes = new ConcurrentHashMap<>();
88 -
89 - private RouteListener routeListener;
90 89
91 @Property(name = "clearRoutes", boolValue = true, 90 @Property(name = "clearRoutes", boolValue = true,
92 label = "Whether to clear routes when the FPM connection goes down") 91 label = "Whether to clear routes when the FPM connection goes down")
...@@ -96,12 +95,14 @@ public class FpmManager implements RouteSourceService, FpmInfoService { ...@@ -96,12 +95,14 @@ public class FpmManager implements RouteSourceService, FpmInfoService {
96 protected void activate(ComponentContext context) { 95 protected void activate(ComponentContext context) {
97 componentConfigService.registerProperties(getClass()); 96 componentConfigService.registerProperties(getClass());
98 modified(context); 97 modified(context);
98 + startServer();
99 log.info("Started"); 99 log.info("Started");
100 } 100 }
101 101
102 @Deactivate 102 @Deactivate
103 protected void deactivate() { 103 protected void deactivate() {
104 stopServer(); 104 stopServer();
105 + fpmRoutes.clear();
105 componentConfigService.unregisterProperties(getClass(), false); 106 componentConfigService.unregisterProperties(getClass(), false);
106 log.info("Stopped"); 107 log.info("Stopped");
107 } 108 }
...@@ -165,19 +166,6 @@ public class FpmManager implements RouteSourceService, FpmInfoService { ...@@ -165,19 +166,6 @@ public class FpmManager implements RouteSourceService, FpmInfoService {
165 } 166 }
166 } 167 }
167 168
168 - @Override
169 - public void start(RouteListener routeListener) {
170 - this.routeListener = routeListener;
171 -
172 - startServer();
173 - }
174 -
175 - @Override
176 - public void stop() {
177 - fpmRoutes.clear();
178 - stopServer();
179 - }
180 -
181 private void fpmMessage(FpmHeader fpmMessage) { 169 private void fpmMessage(FpmHeader fpmMessage) {
182 Netlink netlink = fpmMessage.netlink(); 170 Netlink netlink = fpmMessage.netlink();
183 RtNetlink rtNetlink = netlink.rtNetlink(); 171 RtNetlink rtNetlink = netlink.rtNetlink();
...@@ -212,51 +200,46 @@ public class FpmManager implements RouteSourceService, FpmInfoService { ...@@ -212,51 +200,46 @@ public class FpmManager implements RouteSourceService, FpmInfoService {
212 200
213 IpPrefix prefix = IpPrefix.valueOf(dstAddress, rtNetlink.dstLength()); 201 IpPrefix prefix = IpPrefix.valueOf(dstAddress, rtNetlink.dstLength());
214 202
215 - RouteUpdate routeUpdate = null; 203 + List<Route> updates = new LinkedList<>();
216 - RouteEntry entry; 204 + List<Route> withdraws = new LinkedList<>();
205 +
206 + Route route;
217 switch (netlink.type()) { 207 switch (netlink.type()) {
218 case RTM_NEWROUTE: 208 case RTM_NEWROUTE:
219 if (gateway == null) { 209 if (gateway == null) {
220 // We ignore interface routes with no gateway for now. 210 // We ignore interface routes with no gateway for now.
221 return; 211 return;
222 } 212 }
223 - entry = new RouteEntry(prefix, gateway); 213 + route = new Route(Route.Source.FPM, prefix, gateway);
224 214
225 - fpmRoutes.put(entry.prefix(), entry); 215 + fpmRoutes.put(prefix, route);
226 216
227 - routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE, entry); 217 + updates.add(route);
228 break; 218 break;
229 case RTM_DELROUTE: 219 case RTM_DELROUTE:
230 - RouteEntry existing = fpmRoutes.remove(prefix); 220 + Route existing = fpmRoutes.remove(prefix);
231 if (existing == null) { 221 if (existing == null) {
232 log.warn("Got delete for non-existent prefix"); 222 log.warn("Got delete for non-existent prefix");
233 return; 223 return;
234 } 224 }
235 225
236 - entry = new RouteEntry(prefix, existing.nextHop()); 226 + route = new Route(Route.Source.FPM, prefix, existing.nextHop());
237 227
238 - routeUpdate = new RouteUpdate(RouteUpdate.Type.DELETE, entry); 228 + withdraws.add(route);
239 break; 229 break;
240 case RTM_GETROUTE: 230 case RTM_GETROUTE:
241 default: 231 default:
242 break; 232 break;
243 } 233 }
244 234
245 - if (routeUpdate == null) { 235 + routeService.withdraw(withdraws);
246 - log.warn("Unsupported FPM message: {}", fpmMessage); 236 + routeService.update(updates);
247 - return;
248 - }
249 -
250 - routeListener.update(Collections.singletonList(routeUpdate));
251 } 237 }
252 238
253 239
254 private void clearRoutes() { 240 private void clearRoutes() {
255 log.info("Clearing all routes"); 241 log.info("Clearing all routes");
256 - List<RouteUpdate> routeUpdates = fpmRoutes.values().stream() 242 + routeService.withdraw(ImmutableList.copyOf(fpmRoutes.values()));
257 - .map(routeEntry -> new RouteUpdate(RouteUpdate.Type.DELETE, routeEntry))
258 - .collect(Collectors.toList());
259 - routeListener.update(routeUpdates);
260 } 243 }
261 244
262 @Override 245 @Override
......
1 +/*
2 + * Copyright 2014-2015 Open Networking Laboratory
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.routing.impl;
17 +
18 +import com.google.common.collect.HashMultimap;
19 +import com.google.common.collect.Multimaps;
20 +import com.google.common.collect.SetMultimap;
21 +import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 +import com.googlecode.concurrenttrees.common.KeyValuePair;
23 +import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
24 +import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
25 +import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
26 +import org.apache.felix.scr.annotations.Activate;
27 +import org.apache.felix.scr.annotations.Component;
28 +import org.apache.felix.scr.annotations.Deactivate;
29 +import org.apache.felix.scr.annotations.Reference;
30 +import org.apache.felix.scr.annotations.ReferenceCardinality;
31 +import org.apache.felix.scr.annotations.Service;
32 +import org.onlab.packet.Ip4Address;
33 +import org.onlab.packet.Ip6Address;
34 +import org.onlab.packet.IpAddress;
35 +import org.onlab.packet.IpPrefix;
36 +import org.onlab.packet.MacAddress;
37 +import org.onosproject.core.CoreService;
38 +import org.onosproject.net.Host;
39 +import org.onosproject.net.host.HostEvent;
40 +import org.onosproject.net.host.HostListener;
41 +import org.onosproject.net.host.HostService;
42 +import org.onosproject.routing.RouteSourceService;
43 +import org.onosproject.routing.FibEntry;
44 +import org.onosproject.routing.FibListener;
45 +import org.onosproject.routing.FibUpdate;
46 +import org.onosproject.routing.RouteEntry;
47 +import org.onosproject.routing.RouteListener;
48 +import org.onosproject.routing.RouteUpdate;
49 +import org.onosproject.routing.RoutingService;
50 +import org.onosproject.routing.config.RoutingConfigurationService;
51 +import org.slf4j.Logger;
52 +import org.slf4j.LoggerFactory;
53 +
54 +import java.util.Collection;
55 +import java.util.Collections;
56 +import java.util.Iterator;
57 +import java.util.LinkedList;
58 +import java.util.List;
59 +import java.util.Map;
60 +import java.util.Set;
61 +import java.util.concurrent.BlockingQueue;
62 +import java.util.concurrent.ConcurrentHashMap;
63 +import java.util.concurrent.ExecutorService;
64 +import java.util.concurrent.Executors;
65 +import java.util.concurrent.LinkedBlockingQueue;
66 +
67 +import static com.google.common.base.Preconditions.checkNotNull;
68 +import static org.onosproject.routing.RouteEntry.createBinaryString;
69 +
70 +/**
71 + * This class processes route updates and maintains a Routing Information Base
72 + * (RIB). After route updates have been processed and next hops have been
73 + * resolved, FIB updates are sent to any listening FIB components.
74 + * <p>
75 + * This implementation has been superseded by the RouteService and will be
76 + * removed soon.
77 + * </p>
78 + */
79 +@Deprecated
80 +@Component(immediate = true, enabled = false)
81 +@Service
82 +public class DefaultRouter implements RoutingService {
83 +
84 + private static final Logger log = LoggerFactory.getLogger(DefaultRouter.class);
85 +
86 + // Route entries are stored in a radix tree.
87 + // The key in this tree is the binary string of prefix of the route.
88 + private InvertedRadixTree<RouteEntry> ribTable4;
89 + private InvertedRadixTree<RouteEntry> ribTable6;
90 +
91 + // Stores all incoming route updates in a queue.
92 + private final BlockingQueue<Collection<RouteUpdate>> routeUpdatesQueue =
93 + new LinkedBlockingQueue<>();
94 +
95 + // Next-hop IP address to route entry mapping for next hops pending MAC
96 + // resolution
97 + private SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp;
98 +
99 + // The IPv4 address to MAC address mapping
100 + private final Map<IpAddress, MacAddress> ip2Mac = new ConcurrentHashMap<>();
101 +
102 + private FibListener fibComponent;
103 +
104 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 + protected CoreService coreService;
106 +
107 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 + protected HostService hostService;
109 +
110 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 + protected RouteSourceService routeSourceService;
112 +
113 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 + protected RoutingConfigurationService routingConfigurationService;
115 +
116 + private ExecutorService bgpUpdatesExecutor;
117 + private final HostListener hostListener = new InternalHostListener();
118 +
119 + @Activate
120 + public void activate() {
121 + ribTable4 = new ConcurrentInvertedRadixTree<>(
122 + new DefaultByteArrayNodeFactory());
123 + ribTable6 = new ConcurrentInvertedRadixTree<>(
124 + new DefaultByteArrayNodeFactory());
125 +
126 + routesWaitingOnArp = Multimaps.synchronizedSetMultimap(
127 + HashMultimap.create());
128 +
129 + coreService.registerApplication(ROUTER_APP_ID);
130 +
131 + bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
132 + new ThreadFactoryBuilder()
133 + .setNameFormat("rib-updates-%d").build());
134 + }
135 +
136 + @Deactivate
137 + public void deactivate() {
138 + log.debug("Stopped");
139 + }
140 +
141 + @Override
142 + public void addFibListener(FibListener fibListener) {
143 + this.fibComponent = checkNotNull(fibListener);
144 + }
145 +
146 + @Override
147 + public void start() {
148 + this.hostService.addListener(hostListener);
149 +
150 + routeSourceService.start(new InternalRouteListener());
151 +
152 + bgpUpdatesExecutor.execute(this::doUpdatesThread);
153 + }
154 +
155 + @Override
156 + public void stop() {
157 + routeSourceService.stop();
158 +
159 + this.hostService.removeListener(hostListener);
160 +
161 + // Stop the thread(s)
162 + bgpUpdatesExecutor.shutdownNow();
163 +
164 + synchronized (this) {
165 + // Cleanup all local state
166 + ribTable4 = new ConcurrentInvertedRadixTree<>(
167 + new DefaultByteArrayNodeFactory());
168 + ribTable6 = new ConcurrentInvertedRadixTree<>(
169 + new DefaultByteArrayNodeFactory());
170 + routeUpdatesQueue.clear();
171 + routesWaitingOnArp.clear();
172 + ip2Mac.clear();
173 + }
174 + }
175 +
176 + /**
177 + * Entry point for route updates.
178 + *
179 + * @param routeUpdates collection of route updates to process
180 + */
181 + private void update(Collection<RouteUpdate> routeUpdates) {
182 + try {
183 + routeUpdatesQueue.put(routeUpdates);
184 + } catch (InterruptedException e) {
185 + log.error("Interrupted while putting on routeUpdatesQueue", e);
186 + Thread.currentThread().interrupt();
187 + }
188 + }
189 +
190 + /**
191 + * Thread for handling route updates.
192 + */
193 + private void doUpdatesThread() {
194 + boolean interrupted = false;
195 + try {
196 + while (!interrupted) {
197 + try {
198 + Collection<RouteUpdate> routeUpdates =
199 + routeUpdatesQueue.take();
200 + processRouteUpdates(routeUpdates);
201 + } catch (InterruptedException e) {
202 + log.error("Interrupted while taking from updates queue", e);
203 + interrupted = true;
204 + } catch (Exception e) {
205 + log.error("exception", e);
206 + }
207 + }
208 + } finally {
209 + if (interrupted) {
210 + Thread.currentThread().interrupt();
211 + }
212 + }
213 + }
214 +
215 + /**
216 + * Gets all IPv4 routes from the RIB.
217 + *
218 + * @return all IPv4 routes from the RIB
219 + */
220 + @Override
221 + public Collection<RouteEntry> getRoutes4() {
222 + Iterator<KeyValuePair<RouteEntry>> it =
223 + ribTable4.getKeyValuePairsForKeysStartingWith("").iterator();
224 +
225 + List<RouteEntry> routes = new LinkedList<>();
226 +
227 + while (it.hasNext()) {
228 + KeyValuePair<RouteEntry> entry = it.next();
229 + routes.add(entry.getValue());
230 + }
231 +
232 + return routes;
233 + }
234 +
235 + /**
236 + * Gets all IPv6 routes from the RIB.
237 + *
238 + * @return all IPv6 routes from the RIB
239 + */
240 + @Override
241 + public Collection<RouteEntry> getRoutes6() {
242 + Iterator<KeyValuePair<RouteEntry>> it =
243 + ribTable6.getKeyValuePairsForKeysStartingWith("").iterator();
244 +
245 + List<RouteEntry> routes = new LinkedList<>();
246 +
247 + while (it.hasNext()) {
248 + KeyValuePair<RouteEntry> entry = it.next();
249 + routes.add(entry.getValue());
250 + }
251 +
252 + return routes;
253 + }
254 +
255 + /**
256 + * Finds a route in the RIB for a prefix. The prefix can be either IPv4 or
257 + * IPv6.
258 + *
259 + * @param prefix the prefix to use
260 + * @return the route if found, otherwise null
261 + */
262 + RouteEntry findRibRoute(IpPrefix prefix) {
263 + String binaryString = createBinaryString(prefix);
264 + if (prefix.isIp4()) {
265 + // IPv4
266 + return ribTable4.getValueForExactKey(binaryString);
267 + }
268 + // IPv6
269 + return ribTable6.getValueForExactKey(binaryString);
270 + }
271 +
272 + /**
273 + * Adds a route to the RIB. The route can be either IPv4 or IPv6.
274 + *
275 + * @param routeEntry the route entry to use
276 + */
277 + void addRibRoute(RouteEntry routeEntry) {
278 + if (routeEntry.isIp4()) {
279 + // IPv4
280 + ribTable4.put(createBinaryString(routeEntry.prefix()), routeEntry);
281 + } else {
282 + // IPv6
283 + ribTable6.put(createBinaryString(routeEntry.prefix()), routeEntry);
284 + }
285 + }
286 +
287 + /**
288 + * Removes a route for a prefix from the RIB. The prefix can be either IPv4
289 + * or IPv6.
290 + *
291 + * @param prefix the prefix to use
292 + * @return true if the route was found and removed, otherwise false
293 + */
294 + boolean removeRibRoute(IpPrefix prefix) {
295 + if (prefix.isIp4()) {
296 + // IPv4
297 + return ribTable4.remove(createBinaryString(prefix));
298 + }
299 + // IPv6
300 + return ribTable6.remove(createBinaryString(prefix));
301 + }
302 +
303 + /**
304 + * Processes route updates.
305 + *
306 + * @param routeUpdates the route updates to process
307 + */
308 + void processRouteUpdates(Collection<RouteUpdate> routeUpdates) {
309 + synchronized (this) {
310 + Collection<IpPrefix> withdrawPrefixes = new LinkedList<>();
311 + Collection<FibUpdate> fibUpdates = new LinkedList<>();
312 + Collection<FibUpdate> fibWithdraws = new LinkedList<>();
313 +
314 + for (RouteUpdate update : routeUpdates) {
315 + switch (update.type()) {
316 + case UPDATE:
317 +
318 + FibEntry fib = processRouteAdd(update.routeEntry(),
319 + withdrawPrefixes);
320 + if (fib != null) {
321 + fibUpdates.add(new FibUpdate(FibUpdate.Type.UPDATE, fib));
322 + }
323 +
324 + break;
325 + case DELETE:
326 + processRouteDelete(update.routeEntry(), withdrawPrefixes);
327 +
328 + break;
329 + default:
330 + log.error("Unknown update Type: {}", update.type());
331 + break;
332 + }
333 + }
334 +
335 + withdrawPrefixes.forEach(p -> fibWithdraws.add(new FibUpdate(
336 + FibUpdate.Type.DELETE, new FibEntry(p, null, null))));
337 +
338 + if (!fibUpdates.isEmpty() || !fibWithdraws.isEmpty()) {
339 + fibComponent.update(fibUpdates, fibWithdraws);
340 + }
341 + }
342 + }
343 +
344 + /**
345 + * Processes adding a route entry.
346 + * <p>
347 + * The route entry is added to the radix tree. If there was an existing
348 + * next hop for this prefix, but the next hop was different, then the
349 + * old route entry is deleted.
350 + * </p>
351 + * <p>
352 + * NOTE: Currently, we don't handle routes if the next hop is within the
353 + * SDN domain.
354 + * </p>
355 + *
356 + * @param routeEntry the route entry to add
357 + * @param withdrawPrefixes the collection of accumulated prefixes whose
358 + * intents will be withdrawn
359 + * @return the corresponding FIB entry change, or null
360 + */
361 + private FibEntry processRouteAdd(RouteEntry routeEntry,
362 + Collection<IpPrefix> withdrawPrefixes) {
363 + log.debug("Processing route add: {}", routeEntry);
364 +
365 + // Find the old next-hop if we are updating an old route entry
366 + IpAddress oldNextHop = null;
367 + RouteEntry oldRouteEntry = findRibRoute(routeEntry.prefix());
368 + if (oldRouteEntry != null) {
369 + oldNextHop = oldRouteEntry.nextHop();
370 + }
371 +
372 + // Add the new route to the RIB
373 + addRibRoute(routeEntry);
374 +
375 + if (oldNextHop != null) {
376 + if (oldNextHop.equals(routeEntry.nextHop())) {
377 + return null; // No change
378 + }
379 + //
380 + // Update an existing nexthop for the prefix.
381 + // We need to remove the old flows for this prefix from the
382 + // switches before the new flows are added.
383 + //
384 + withdrawPrefixes.add(routeEntry.prefix());
385 + }
386 +
387 + if (routingConfigurationService.isIpPrefixLocal(routeEntry.prefix())) {
388 + // Route originated by local SDN domain
389 + // We don't handle these here, reactive routing APP will handle
390 + // these
391 + log.debug("Own route {} to {}",
392 + routeEntry.prefix(), routeEntry.nextHop());
393 + return null;
394 + }
395 +
396 + //
397 + // Find the MAC address of next hop router for this route entry.
398 + // If the MAC address can not be found in ARP cache, then this prefix
399 + // will be put in routesWaitingOnArp queue. Otherwise, generate
400 + // a new route intent.
401 + //
402 +
403 + // Monitor the IP address for updates of the MAC address
404 + hostService.startMonitoringIp(routeEntry.nextHop());
405 +
406 + // Check if we know the MAC address of the next hop
407 + MacAddress nextHopMacAddress = ip2Mac.get(routeEntry.nextHop());
408 + if (nextHopMacAddress == null) {
409 + Set<Host> hosts = hostService.getHostsByIp(routeEntry.nextHop());
410 + if (!hosts.isEmpty()) {
411 + nextHopMacAddress = hosts.iterator().next().mac();
412 + }
413 + if (nextHopMacAddress != null) {
414 + ip2Mac.put(routeEntry.nextHop(), nextHopMacAddress);
415 + }
416 + }
417 + if (nextHopMacAddress == null) {
418 + routesWaitingOnArp.put(routeEntry.nextHop(), routeEntry);
419 + return null;
420 + }
421 + return new FibEntry(routeEntry.prefix(), routeEntry.nextHop(),
422 + nextHopMacAddress);
423 + }
424 +
425 + /**
426 + * Processes the deletion of a route entry.
427 + * <p>
428 + * The prefix for the routing entry is removed from radix tree.
429 + * If the operation is successful, the prefix is added to the collection
430 + * of prefixes whose intents that will be withdrawn.
431 + * </p>
432 + *
433 + * @param routeEntry the route entry to delete
434 + * @param withdrawPrefixes the collection of accumulated prefixes whose
435 + * intents will be withdrawn
436 + */
437 + private void processRouteDelete(RouteEntry routeEntry,
438 + Collection<IpPrefix> withdrawPrefixes) {
439 + log.debug("Processing route delete: {}", routeEntry);
440 + boolean isRemoved = removeRibRoute(routeEntry.prefix());
441 +
442 + if (isRemoved) {
443 + //
444 + // Only withdraw intents if an entry was actually removed from the
445 + // tree. If no entry was removed, the <prefix, nexthop> wasn't
446 + // there so it's probably already been removed and we don't
447 + // need to do anything.
448 + //
449 + withdrawPrefixes.add(routeEntry.prefix());
450 + }
451 +
452 + routesWaitingOnArp.remove(routeEntry.nextHop(), routeEntry);
453 + }
454 +
455 + /**
456 + * Signals the Router that the MAC to IP mapping has potentially been
457 + * updated. This has the effect of updating the MAC address for any
458 + * installed prefixes if it has changed, as well as installing any pending
459 + * prefixes that were waiting for MAC resolution.
460 + *
461 + * @param ipAddress the IP address that an event was received for
462 + * @param macAddress the most recently known MAC address for the IP address
463 + */
464 + private void updateMac(IpAddress ipAddress, MacAddress macAddress) {
465 + log.debug("Received updated MAC info: {} => {}", ipAddress,
466 + macAddress);
467 +
468 + //
469 + // We synchronize on "this" to prevent changes to the Radix tree
470 + // while we're pushing intents. If the tree changes, the
471 + // tree and the intents could get out of sync.
472 + //
473 + synchronized (this) {
474 + Collection<FibUpdate> submitFibEntries = new LinkedList<>();
475 +
476 + Set<RouteEntry> routesToPush =
477 + routesWaitingOnArp.removeAll(ipAddress);
478 +
479 + for (RouteEntry routeEntry : routesToPush) {
480 + // These will always be adds
481 + RouteEntry foundRouteEntry = findRibRoute(routeEntry.prefix());
482 + if (foundRouteEntry != null &&
483 + foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
484 + // We only push FIB updates if the prefix is still in the
485 + // radix tree and the next hop is the same as our entry.
486 + // The prefix could have been removed while we were waiting
487 + // for the ARP, or the next hop could have changed.
488 + submitFibEntries.add(new FibUpdate(FibUpdate.Type.UPDATE,
489 + new FibEntry(routeEntry.prefix(),
490 + ipAddress, macAddress)));
491 + } else {
492 + log.debug("{} has been revoked before the MAC was resolved",
493 + routeEntry);
494 + }
495 + }
496 +
497 + if (!submitFibEntries.isEmpty()) {
498 + fibComponent.update(submitFibEntries, Collections.emptyList());
499 + }
500 +
501 + ip2Mac.put(ipAddress, macAddress);
502 + }
503 + }
504 +
505 + /**
506 + * Listener for host events.
507 + */
508 + class InternalHostListener implements HostListener {
509 + @Override
510 + public void event(HostEvent event) {
511 + log.debug("Received HostEvent {}", event);
512 +
513 + Host host = event.subject();
514 + switch (event.type()) {
515 + case HOST_ADDED:
516 + // FALLTHROUGH
517 + case HOST_UPDATED:
518 + for (IpAddress ipAddress : host.ipAddresses()) {
519 + updateMac(ipAddress, host.mac());
520 + }
521 + break;
522 + case HOST_REMOVED:
523 + for (IpAddress ipAddress : host.ipAddresses()) {
524 + ip2Mac.remove(ipAddress);
525 + }
526 + break;
527 + default:
528 + break;
529 + }
530 + }
531 + }
532 +
533 + /**
534 + * Listener for route events.
535 + */
536 + private class InternalRouteListener implements RouteListener {
537 + @Override
538 + public void update(Collection<RouteUpdate> routeUpdates) {
539 + DefaultRouter.this.update(routeUpdates);
540 + }
541 + }
542 +
543 + @Override
544 + public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) {
545 + RouteEntry routeEntry = null;
546 + Iterable<RouteEntry> routeEntries;
547 +
548 + if (ipAddress.isIp4()) {
549 + routeEntries = ribTable4.getValuesForKeysPrefixing(
550 + createBinaryString(
551 + IpPrefix.valueOf(ipAddress, Ip4Address.BIT_LENGTH)));
552 + } else {
553 + routeEntries = ribTable6.getValuesForKeysPrefixing(
554 + createBinaryString(
555 + IpPrefix.valueOf(ipAddress, Ip6Address.BIT_LENGTH)));
556 + }
557 + if (routeEntries == null) {
558 + return null;
559 + }
560 + Iterator<RouteEntry> it = routeEntries.iterator();
561 + while (it.hasNext()) {
562 + routeEntry = it.next();
563 + }
564 + return routeEntry;
565 + }
566 +
567 +}
...@@ -13,550 +13,110 @@ ...@@ -13,550 +13,110 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 +
16 package org.onosproject.routing.impl; 17 package org.onosproject.routing.impl;
17 18
18 -import com.google.common.collect.HashMultimap;
19 -import com.google.common.collect.Multimaps;
20 -import com.google.common.collect.SetMultimap;
21 -import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 -import com.googlecode.concurrenttrees.common.KeyValuePair;
23 -import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
24 -import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
25 -import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
26 -import org.apache.felix.scr.annotations.Activate;
27 import org.apache.felix.scr.annotations.Component; 19 import org.apache.felix.scr.annotations.Component;
28 -import org.apache.felix.scr.annotations.Deactivate;
29 import org.apache.felix.scr.annotations.Reference; 20 import org.apache.felix.scr.annotations.Reference;
30 import org.apache.felix.scr.annotations.ReferenceCardinality; 21 import org.apache.felix.scr.annotations.ReferenceCardinality;
31 import org.apache.felix.scr.annotations.Service; 22 import org.apache.felix.scr.annotations.Service;
32 -import org.onlab.packet.Ip4Address;
33 -import org.onlab.packet.Ip6Address;
34 import org.onlab.packet.IpAddress; 23 import org.onlab.packet.IpAddress;
35 -import org.onlab.packet.IpPrefix; 24 +import org.onosproject.incubator.net.routing.ResolvedRoute;
36 -import org.onlab.packet.MacAddress; 25 +import org.onosproject.incubator.net.routing.Route;
37 -import org.onosproject.core.CoreService; 26 +import org.onosproject.incubator.net.routing.RouteEvent;
38 -import org.onosproject.net.Host; 27 +import org.onosproject.incubator.net.routing.RouteListener;
39 -import org.onosproject.net.host.HostEvent; 28 +import org.onosproject.incubator.net.routing.RouteService;
40 -import org.onosproject.net.host.HostListener; 29 +import org.onosproject.incubator.net.routing.RouteTableId;
41 -import org.onosproject.net.host.HostService;
42 -import org.onosproject.routing.RouteSourceService;
43 import org.onosproject.routing.FibEntry; 30 import org.onosproject.routing.FibEntry;
44 import org.onosproject.routing.FibListener; 31 import org.onosproject.routing.FibListener;
45 import org.onosproject.routing.FibUpdate; 32 import org.onosproject.routing.FibUpdate;
46 import org.onosproject.routing.RouteEntry; 33 import org.onosproject.routing.RouteEntry;
47 -import org.onosproject.routing.RouteListener;
48 -import org.onosproject.routing.RouteUpdate;
49 import org.onosproject.routing.RoutingService; 34 import org.onosproject.routing.RoutingService;
50 -import org.onosproject.routing.config.RoutingConfigurationService;
51 -import org.slf4j.Logger;
52 -import org.slf4j.LoggerFactory;
53 35
54 import java.util.Collection; 36 import java.util.Collection;
55 import java.util.Collections; 37 import java.util.Collections;
56 -import java.util.Iterator; 38 +import java.util.stream.Collectors;
57 -import java.util.LinkedList;
58 -import java.util.List;
59 -import java.util.Map;
60 -import java.util.Set;
61 -import java.util.concurrent.BlockingQueue;
62 -import java.util.concurrent.ConcurrentHashMap;
63 -import java.util.concurrent.ExecutorService;
64 -import java.util.concurrent.Executors;
65 -import java.util.concurrent.LinkedBlockingQueue;
66 -
67 -import static com.google.common.base.Preconditions.checkNotNull;
68 -import static org.onosproject.routing.RouteEntry.createBinaryString;
69 39
70 /** 40 /**
71 - * This class processes route updates and maintains a Routing Information Base 41 + * Adapts new route service interface to old RoutingService interface.
72 - * (RIB). After route updates have been processed and next hops have been
73 - * resolved, FIB updates are sent to any listening FIB components.
74 */ 42 */
75 -@Component(immediate = true, enabled = false)
76 @Service 43 @Service
44 +@Component(immediate = true, enabled = false)
77 public class Router implements RoutingService { 45 public class Router implements RoutingService {
78 46
79 - private static final Logger log = LoggerFactory.getLogger(Router.class);
80 -
81 - // Route entries are stored in a radix tree.
82 - // The key in this tree is the binary string of prefix of the route.
83 - private InvertedRadixTree<RouteEntry> ribTable4;
84 - private InvertedRadixTree<RouteEntry> ribTable6;
85 -
86 - // Stores all incoming route updates in a queue.
87 - private final BlockingQueue<Collection<RouteUpdate>> routeUpdatesQueue =
88 - new LinkedBlockingQueue<>();
89 -
90 - // Next-hop IP address to route entry mapping for next hops pending MAC
91 - // resolution
92 - private SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp;
93 -
94 - // The IPv4 address to MAC address mapping
95 - private final Map<IpAddress, MacAddress> ip2Mac = new ConcurrentHashMap<>();
96 -
97 - private FibListener fibComponent;
98 -
99 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 - protected CoreService coreService;
101 -
102 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 - protected HostService hostService;
104 -
105 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 - protected RouteSourceService routeSourceService;
107 -
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 47 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 - protected RoutingConfigurationService routingConfigurationService; 48 + protected RouteService routeService;
110 -
111 - private ExecutorService bgpUpdatesExecutor;
112 - private final HostListener hostListener = new InternalHostListener();
113 -
114 - @Activate
115 - public void activate() {
116 - ribTable4 = new ConcurrentInvertedRadixTree<>(
117 - new DefaultByteArrayNodeFactory());
118 - ribTable6 = new ConcurrentInvertedRadixTree<>(
119 - new DefaultByteArrayNodeFactory());
120 -
121 - routesWaitingOnArp = Multimaps.synchronizedSetMultimap(
122 - HashMultimap.create());
123 -
124 - coreService.registerApplication(ROUTER_APP_ID);
125 -
126 - bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
127 - new ThreadFactoryBuilder()
128 - .setNameFormat("rib-updates-%d").build());
129 - }
130 -
131 - @Deactivate
132 - public void deactivate() {
133 - log.debug("Stopped");
134 - }
135 49
136 @Override 50 @Override
137 - public void addFibListener(FibListener fibListener) { 51 + public void start() {
138 - this.fibComponent = checkNotNull(fibListener);
139 } 52 }
140 53
141 @Override 54 @Override
142 - public void start() { 55 + public void addFibListener(FibListener fibListener) {
143 - this.hostService.addListener(hostListener); 56 + routeService.addListener(new InternalRouteListener(fibListener));
144 -
145 - routeSourceService.start(new InternalRouteListener());
146 -
147 - bgpUpdatesExecutor.execute(this::doUpdatesThread);
148 } 57 }
149 58
150 @Override 59 @Override
151 public void stop() { 60 public void stop() {
152 - routeSourceService.stop();
153 -
154 - this.hostService.removeListener(hostListener);
155 -
156 - // Stop the thread(s)
157 - bgpUpdatesExecutor.shutdownNow();
158 -
159 - synchronized (this) {
160 - // Cleanup all local state
161 - ribTable4 = new ConcurrentInvertedRadixTree<>(
162 - new DefaultByteArrayNodeFactory());
163 - ribTable6 = new ConcurrentInvertedRadixTree<>(
164 - new DefaultByteArrayNodeFactory());
165 - routeUpdatesQueue.clear();
166 - routesWaitingOnArp.clear();
167 - ip2Mac.clear();
168 - }
169 } 61 }
170 62
171 - /**
172 - * Entry point for route updates.
173 - *
174 - * @param routeUpdates collection of route updates to process
175 - */
176 - private void update(Collection<RouteUpdate> routeUpdates) {
177 - try {
178 - routeUpdatesQueue.put(routeUpdates);
179 - } catch (InterruptedException e) {
180 - log.error("Interrupted while putting on routeUpdatesQueue", e);
181 - Thread.currentThread().interrupt();
182 - }
183 - }
184 -
185 - /**
186 - * Thread for handling route updates.
187 - */
188 - private void doUpdatesThread() {
189 - boolean interrupted = false;
190 - try {
191 - while (!interrupted) {
192 - try {
193 - Collection<RouteUpdate> routeUpdates =
194 - routeUpdatesQueue.take();
195 - processRouteUpdates(routeUpdates);
196 - } catch (InterruptedException e) {
197 - log.error("Interrupted while taking from updates queue", e);
198 - interrupted = true;
199 - } catch (Exception e) {
200 - log.error("exception", e);
201 - }
202 - }
203 - } finally {
204 - if (interrupted) {
205 - Thread.currentThread().interrupt();
206 - }
207 - }
208 - }
209 -
210 - /**
211 - * Gets all IPv4 routes from the RIB.
212 - *
213 - * @return all IPv4 routes from the RIB
214 - */
215 @Override 63 @Override
216 public Collection<RouteEntry> getRoutes4() { 64 public Collection<RouteEntry> getRoutes4() {
217 - Iterator<KeyValuePair<RouteEntry>> it = 65 + return routeService.getAllRoutes().get(new RouteTableId("ipv4")).stream()
218 - ribTable4.getKeyValuePairsForKeysStartingWith("").iterator(); 66 + .map(route -> new RouteEntry(route.prefix(), route.nextHop()))
219 - 67 + .collect(Collectors.toList());
220 - List<RouteEntry> routes = new LinkedList<>();
221 -
222 - while (it.hasNext()) {
223 - KeyValuePair<RouteEntry> entry = it.next();
224 - routes.add(entry.getValue());
225 - }
226 -
227 - return routes;
228 } 68 }
229 69
230 - /**
231 - * Gets all IPv6 routes from the RIB.
232 - *
233 - * @return all IPv6 routes from the RIB
234 - */
235 @Override 70 @Override
236 public Collection<RouteEntry> getRoutes6() { 71 public Collection<RouteEntry> getRoutes6() {
237 - Iterator<KeyValuePair<RouteEntry>> it = 72 + return routeService.getAllRoutes().get(new RouteTableId("ipv6")).stream()
238 - ribTable6.getKeyValuePairsForKeysStartingWith("").iterator(); 73 + .map(route -> new RouteEntry(route.prefix(), route.nextHop()))
239 - 74 + .collect(Collectors.toList());
240 - List<RouteEntry> routes = new LinkedList<>();
241 -
242 - while (it.hasNext()) {
243 - KeyValuePair<RouteEntry> entry = it.next();
244 - routes.add(entry.getValue());
245 - }
246 -
247 - return routes;
248 - }
249 -
250 - /**
251 - * Finds a route in the RIB for a prefix. The prefix can be either IPv4 or
252 - * IPv6.
253 - *
254 - * @param prefix the prefix to use
255 - * @return the route if found, otherwise null
256 - */
257 - RouteEntry findRibRoute(IpPrefix prefix) {
258 - String binaryString = createBinaryString(prefix);
259 - if (prefix.isIp4()) {
260 - // IPv4
261 - return ribTable4.getValueForExactKey(binaryString);
262 - }
263 - // IPv6
264 - return ribTable6.getValueForExactKey(binaryString);
265 - }
266 -
267 - /**
268 - * Adds a route to the RIB. The route can be either IPv4 or IPv6.
269 - *
270 - * @param routeEntry the route entry to use
271 - */
272 - void addRibRoute(RouteEntry routeEntry) {
273 - if (routeEntry.isIp4()) {
274 - // IPv4
275 - ribTable4.put(createBinaryString(routeEntry.prefix()), routeEntry);
276 - } else {
277 - // IPv6
278 - ribTable6.put(createBinaryString(routeEntry.prefix()), routeEntry);
279 - }
280 } 75 }
281 76
282 - /** 77 + @Override
283 - * Removes a route for a prefix from the RIB. The prefix can be either IPv4 78 + public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) {
284 - * or IPv6. 79 + Route route = routeService.longestPrefixMatch(ipAddress);
285 - * 80 + if (route != null) {
286 - * @param prefix the prefix to use 81 + return new RouteEntry(route.prefix(), route.nextHop());
287 - * @return true if the route was found and removed, otherwise false
288 - */
289 - boolean removeRibRoute(IpPrefix prefix) {
290 - if (prefix.isIp4()) {
291 - // IPv4
292 - return ribTable4.remove(createBinaryString(prefix));
293 - }
294 - // IPv6
295 - return ribTable6.remove(createBinaryString(prefix));
296 - }
297 -
298 - /**
299 - * Processes route updates.
300 - *
301 - * @param routeUpdates the route updates to process
302 - */
303 - void processRouteUpdates(Collection<RouteUpdate> routeUpdates) {
304 - synchronized (this) {
305 - Collection<IpPrefix> withdrawPrefixes = new LinkedList<>();
306 - Collection<FibUpdate> fibUpdates = new LinkedList<>();
307 - Collection<FibUpdate> fibWithdraws = new LinkedList<>();
308 -
309 - for (RouteUpdate update : routeUpdates) {
310 - switch (update.type()) {
311 - case UPDATE:
312 -
313 - FibEntry fib = processRouteAdd(update.routeEntry(),
314 - withdrawPrefixes);
315 - if (fib != null) {
316 - fibUpdates.add(new FibUpdate(FibUpdate.Type.UPDATE, fib));
317 - }
318 -
319 - break;
320 - case DELETE:
321 - processRouteDelete(update.routeEntry(), withdrawPrefixes);
322 -
323 - break;
324 - default:
325 - log.error("Unknown update Type: {}", update.type());
326 - break;
327 - }
328 - }
329 -
330 - withdrawPrefixes.forEach(p -> fibWithdraws.add(new FibUpdate(
331 - FibUpdate.Type.DELETE, new FibEntry(p, null, null))));
332 -
333 - if (!fibUpdates.isEmpty() || !fibWithdraws.isEmpty()) {
334 - fibComponent.update(fibUpdates, fibWithdraws);
335 - }
336 - }
337 - }
338 -
339 - /**
340 - * Processes adding a route entry.
341 - * <p>
342 - * The route entry is added to the radix tree. If there was an existing
343 - * next hop for this prefix, but the next hop was different, then the
344 - * old route entry is deleted.
345 - * </p>
346 - * <p>
347 - * NOTE: Currently, we don't handle routes if the next hop is within the
348 - * SDN domain.
349 - * </p>
350 - *
351 - * @param routeEntry the route entry to add
352 - * @param withdrawPrefixes the collection of accumulated prefixes whose
353 - * intents will be withdrawn
354 - * @return the corresponding FIB entry change, or null
355 - */
356 - private FibEntry processRouteAdd(RouteEntry routeEntry,
357 - Collection<IpPrefix> withdrawPrefixes) {
358 - log.debug("Processing route add: {}", routeEntry);
359 -
360 - // Find the old next-hop if we are updating an old route entry
361 - IpAddress oldNextHop = null;
362 - RouteEntry oldRouteEntry = findRibRoute(routeEntry.prefix());
363 - if (oldRouteEntry != null) {
364 - oldNextHop = oldRouteEntry.nextHop();
365 - }
366 -
367 - // Add the new route to the RIB
368 - addRibRoute(routeEntry);
369 -
370 - if (oldNextHop != null) {
371 - if (oldNextHop.equals(routeEntry.nextHop())) {
372 - return null; // No change
373 - }
374 - //
375 - // Update an existing nexthop for the prefix.
376 - // We need to remove the old flows for this prefix from the
377 - // switches before the new flows are added.
378 - //
379 - withdrawPrefixes.add(routeEntry.prefix());
380 - }
381 -
382 - if (routingConfigurationService.isIpPrefixLocal(routeEntry.prefix())) {
383 - // Route originated by local SDN domain
384 - // We don't handle these here, reactive routing APP will handle
385 - // these
386 - log.debug("Own route {} to {}",
387 - routeEntry.prefix(), routeEntry.nextHop());
388 - return null;
389 - }
390 -
391 - //
392 - // Find the MAC address of next hop router for this route entry.
393 - // If the MAC address can not be found in ARP cache, then this prefix
394 - // will be put in routesWaitingOnArp queue. Otherwise, generate
395 - // a new route intent.
396 - //
397 -
398 - // Monitor the IP address for updates of the MAC address
399 - hostService.startMonitoringIp(routeEntry.nextHop());
400 -
401 - // Check if we know the MAC address of the next hop
402 - MacAddress nextHopMacAddress = ip2Mac.get(routeEntry.nextHop());
403 - if (nextHopMacAddress == null) {
404 - Set<Host> hosts = hostService.getHostsByIp(routeEntry.nextHop());
405 - if (!hosts.isEmpty()) {
406 - nextHopMacAddress = hosts.iterator().next().mac();
407 - }
408 - if (nextHopMacAddress != null) {
409 - ip2Mac.put(routeEntry.nextHop(), nextHopMacAddress);
410 - }
411 - }
412 - if (nextHopMacAddress == null) {
413 - routesWaitingOnArp.put(routeEntry.nextHop(), routeEntry);
414 - return null;
415 - }
416 - return new FibEntry(routeEntry.prefix(), routeEntry.nextHop(),
417 - nextHopMacAddress);
418 - }
419 -
420 - /**
421 - * Processes the deletion of a route entry.
422 - * <p>
423 - * The prefix for the routing entry is removed from radix tree.
424 - * If the operation is successful, the prefix is added to the collection
425 - * of prefixes whose intents that will be withdrawn.
426 - * </p>
427 - *
428 - * @param routeEntry the route entry to delete
429 - * @param withdrawPrefixes the collection of accumulated prefixes whose
430 - * intents will be withdrawn
431 - */
432 - private void processRouteDelete(RouteEntry routeEntry,
433 - Collection<IpPrefix> withdrawPrefixes) {
434 - log.debug("Processing route delete: {}", routeEntry);
435 - boolean isRemoved = removeRibRoute(routeEntry.prefix());
436 -
437 - if (isRemoved) {
438 - //
439 - // Only withdraw intents if an entry was actually removed from the
440 - // tree. If no entry was removed, the <prefix, nexthop> wasn't
441 - // there so it's probably already been removed and we don't
442 - // need to do anything.
443 - //
444 - withdrawPrefixes.add(routeEntry.prefix());
445 } 82 }
446 - 83 + return null;
447 - routesWaitingOnArp.remove(routeEntry.nextHop(), routeEntry);
448 } 84 }
449 85
450 /** 86 /**
451 - * Signals the Router that the MAC to IP mapping has potentially been 87 + * Internal route listener.
452 - * updated. This has the effect of updating the MAC address for any
453 - * installed prefixes if it has changed, as well as installing any pending
454 - * prefixes that were waiting for MAC resolution.
455 - *
456 - * @param ipAddress the IP address that an event was received for
457 - * @param macAddress the most recently known MAC address for the IP address
458 */ 88 */
459 - private void updateMac(IpAddress ipAddress, MacAddress macAddress) { 89 + private class InternalRouteListener implements RouteListener {
460 - log.debug("Received updated MAC info: {} => {}", ipAddress,
461 - macAddress);
462 -
463 - //
464 - // We synchronize on "this" to prevent changes to the Radix tree
465 - // while we're pushing intents. If the tree changes, the
466 - // tree and the intents could get out of sync.
467 - //
468 - synchronized (this) {
469 - Collection<FibUpdate> submitFibEntries = new LinkedList<>();
470 -
471 - Set<RouteEntry> routesToPush =
472 - routesWaitingOnArp.removeAll(ipAddress);
473 -
474 - for (RouteEntry routeEntry : routesToPush) {
475 - // These will always be adds
476 - RouteEntry foundRouteEntry = findRibRoute(routeEntry.prefix());
477 - if (foundRouteEntry != null &&
478 - foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
479 - // We only push FIB updates if the prefix is still in the
480 - // radix tree and the next hop is the same as our entry.
481 - // The prefix could have been removed while we were waiting
482 - // for the ARP, or the next hop could have changed.
483 - submitFibEntries.add(new FibUpdate(FibUpdate.Type.UPDATE,
484 - new FibEntry(routeEntry.prefix(),
485 - ipAddress, macAddress)));
486 - } else {
487 - log.debug("{} has been revoked before the MAC was resolved",
488 - routeEntry);
489 - }
490 - }
491 90
492 - if (!submitFibEntries.isEmpty()) { 91 + private final FibListener fibListener;
493 - fibComponent.update(submitFibEntries, Collections.emptyList());
494 - }
495 92
496 - ip2Mac.put(ipAddress, macAddress); 93 + /**
94 + * Constructor.
95 + *
96 + * @param fibListener FIB listener
97 + */
98 + public InternalRouteListener(FibListener fibListener) {
99 + this.fibListener = fibListener;
497 } 100 }
498 - }
499 101
500 - /**
501 - * Listener for host events.
502 - */
503 - class InternalHostListener implements HostListener {
504 @Override 102 @Override
505 - public void event(HostEvent event) { 103 + public void event(RouteEvent event) {
506 - log.debug("Received HostEvent {}", event); 104 + ResolvedRoute route = event.subject();
105 + FibEntry entry = new FibEntry(route.prefix(), route.nextHop(), route.nextHopMac());
507 106
508 - Host host = event.subject();
509 switch (event.type()) { 107 switch (event.type()) {
510 - case HOST_ADDED: 108 + case ROUTE_ADDED:
511 - // FALLTHROUGH 109 + case ROUTE_UPDATED:
512 - case HOST_UPDATED: 110 + fibListener.update(Collections.singleton(new FibUpdate(FibUpdate.Type.UPDATE, entry)),
513 - for (IpAddress ipAddress : host.ipAddresses()) { 111 + Collections.emptyList());
514 - updateMac(ipAddress, host.mac());
515 - }
516 break; 112 break;
517 - case HOST_REMOVED: 113 + case ROUTE_REMOVED:
518 - for (IpAddress ipAddress : host.ipAddresses()) { 114 + fibListener.update(Collections.emptyList(),
519 - ip2Mac.remove(ipAddress); 115 + Collections.singleton(new FibUpdate(FibUpdate.Type.DELETE, entry)));
520 - }
521 break; 116 break;
522 default: 117 default:
523 break; 118 break;
524 } 119 }
525 } 120 }
526 } 121 }
527 -
528 - /**
529 - * Listener for route events.
530 - */
531 - private class InternalRouteListener implements RouteListener {
532 - @Override
533 - public void update(Collection<RouteUpdate> routeUpdates) {
534 - Router.this.update(routeUpdates);
535 - }
536 - }
537 -
538 - @Override
539 - public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) {
540 - RouteEntry routeEntry = null;
541 - Iterable<RouteEntry> routeEntries;
542 -
543 - if (ipAddress.isIp4()) {
544 - routeEntries = ribTable4.getValuesForKeysPrefixing(
545 - createBinaryString(
546 - IpPrefix.valueOf(ipAddress, Ip4Address.BIT_LENGTH)));
547 - } else {
548 - routeEntries = ribTable6.getValuesForKeysPrefixing(
549 - createBinaryString(
550 - IpPrefix.valueOf(ipAddress, Ip6Address.BIT_LENGTH)));
551 - }
552 - if (routeEntries == null) {
553 - return null;
554 - }
555 - Iterator<RouteEntry> it = routeEntries.iterator();
556 - while (it.hasNext()) {
557 - routeEntry = it.next();
558 - }
559 - return routeEntry;
560 - }
561 -
562 } 122 }
......
...@@ -33,8 +33,7 @@ import org.onlab.junit.TestUtils; ...@@ -33,8 +33,7 @@ import org.onlab.junit.TestUtils;
33 import org.onlab.junit.TestUtils.TestUtilsException; 33 import org.onlab.junit.TestUtils.TestUtilsException;
34 import org.onlab.packet.Ip4Address; 34 import org.onlab.packet.Ip4Address;
35 import org.onlab.packet.Ip4Prefix; 35 import org.onlab.packet.Ip4Prefix;
36 -import org.onosproject.routing.RouteListener; 36 +import org.onosproject.incubator.net.routing.RouteAdminService;
37 -import org.onosproject.routing.RouteUpdate;
38 import org.osgi.service.component.ComponentContext; 37 import org.osgi.service.component.ComponentContext;
39 38
40 import java.net.InetAddress; 39 import java.net.InetAddress;
...@@ -48,6 +47,7 @@ import java.util.concurrent.Executors; ...@@ -48,6 +47,7 @@ import java.util.concurrent.Executors;
48 import java.util.concurrent.TimeUnit; 47 import java.util.concurrent.TimeUnit;
49 48
50 import static org.easymock.EasyMock.createMock; 49 import static org.easymock.EasyMock.createMock;
50 +import static org.easymock.EasyMock.createNiceMock;
51 import static org.easymock.EasyMock.expect; 51 import static org.easymock.EasyMock.expect;
52 import static org.easymock.EasyMock.replay; 52 import static org.easymock.EasyMock.replay;
53 import static org.hamcrest.Matchers.hasSize; 53 import static org.hamcrest.Matchers.hasSize;
...@@ -85,6 +85,8 @@ public class BgpSessionManagerTest { ...@@ -85,6 +85,8 @@ public class BgpSessionManagerTest {
85 // Timeout waiting for a message to be received 85 // Timeout waiting for a message to be received
86 private static final int MESSAGE_TIMEOUT_MS = 5000; // 5s 86 private static final int MESSAGE_TIMEOUT_MS = 5000; // 5s
87 87
88 + private RouteAdminService routeService;
89 +
88 // The BGP Session Manager to test 90 // The BGP Session Manager to test
89 private BgpSessionManager bgpSessionManager; 91 private BgpSessionManager bgpSessionManager;
90 92
...@@ -102,19 +104,6 @@ public class BgpSessionManagerTest { ...@@ -102,19 +104,6 @@ public class BgpSessionManagerTest {
102 // The socket that the remote peers should connect to 104 // The socket that the remote peers should connect to
103 private InetSocketAddress connectToSocket; 105 private InetSocketAddress connectToSocket;
104 106
105 - private final DummyRouteListener dummyRouteListener =
106 - new DummyRouteListener();
107 -
108 - /**
109 - * Dummy implementation for the RouteListener interface.
110 - */
111 - private class DummyRouteListener implements RouteListener {
112 - @Override
113 - public void update(Collection<RouteUpdate> routeUpdate) {
114 - // Nothing to do
115 - }
116 - }
117 -
118 /** 107 /**
119 * A class to capture the state for a BGP peer. 108 * A class to capture the state for a BGP peer.
120 */ 109 */
...@@ -238,13 +227,11 @@ public class BgpSessionManagerTest { ...@@ -238,13 +227,11 @@ public class BgpSessionManagerTest {
238 } 227 }
239 228
240 @SuppressWarnings("unchecked") 229 @SuppressWarnings("unchecked")
241 - private Dictionary 230 + private void getDictionaryMock(ComponentContext componentContext) {
242 - getDictionaryMock(ComponentContext componentContext) {
243 Dictionary dictionary = createMock(Dictionary.class); 231 Dictionary dictionary = createMock(Dictionary.class);
244 expect(dictionary.get("bgpPort")).andReturn("0"); 232 expect(dictionary.get("bgpPort")).andReturn("0");
245 replay(dictionary); 233 replay(dictionary);
246 expect(componentContext.getProperties()).andReturn(dictionary); 234 expect(componentContext.getProperties()).andReturn(dictionary);
247 - return dictionary;
248 } 235 }
249 236
250 @Before 237 @Before
...@@ -262,12 +249,16 @@ public class BgpSessionManagerTest { ...@@ -262,12 +249,16 @@ public class BgpSessionManagerTest {
262 // connections. 249 // connections.
263 // 250 //
264 bgpSessionManager = new BgpSessionManager(); 251 bgpSessionManager = new BgpSessionManager();
252 +
253 + routeService = createNiceMock(RouteAdminService.class);
254 + replay(routeService);
255 + bgpSessionManager.routeService = routeService;
256 +
265 // NOTE: We use port 0 to bind on any available port 257 // NOTE: We use port 0 to bind on any available port
266 ComponentContext componentContext = createMock(ComponentContext.class); 258 ComponentContext componentContext = createMock(ComponentContext.class);
267 - Dictionary dictionary = getDictionaryMock(componentContext); 259 + getDictionaryMock(componentContext);
268 replay(componentContext); 260 replay(componentContext);
269 bgpSessionManager.activate(componentContext); 261 bgpSessionManager.activate(componentContext);
270 - bgpSessionManager.start(dummyRouteListener);
271 262
272 // Get the port number the BGP Session Manager is listening on 263 // Get the port number the BGP Session Manager is listening on
273 Channel serverChannel = TestUtils.getField(bgpSessionManager, 264 Channel serverChannel = TestUtils.getField(bgpSessionManager,
...@@ -547,6 +538,7 @@ public class BgpSessionManagerTest { ...@@ -547,6 +538,7 @@ public class BgpSessionManagerTest {
547 withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16")); 538 withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16"));
548 withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24")); 539 withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24"));
549 withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32")); 540 withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32"));
541 +
550 // Write the routes 542 // Write the routes
551 message = peer1.peerChannelHandler.prepareBgpUpdate( 543 message = peer1.peerChannelHandler.prepareBgpUpdate(
552 NEXT_HOP1_ROUTER, 544 NEXT_HOP1_ROUTER,
......
...@@ -39,7 +39,7 @@ import org.onosproject.net.host.HostListener; ...@@ -39,7 +39,7 @@ import org.onosproject.net.host.HostListener;
39 import org.onosproject.net.host.HostService; 39 import org.onosproject.net.host.HostService;
40 import org.onosproject.net.provider.ProviderId; 40 import org.onosproject.net.provider.ProviderId;
41 import org.onosproject.routing.config.RoutingConfigurationService; 41 import org.onosproject.routing.config.RoutingConfigurationService;
42 -import org.onosproject.routing.impl.Router.InternalHostListener; 42 +import org.onosproject.routing.impl.DefaultRouter.InternalHostListener;
43 import org.onosproject.routing.RouteSourceService; 43 import org.onosproject.routing.RouteSourceService;
44 import org.onosproject.routing.FibEntry; 44 import org.onosproject.routing.FibEntry;
45 import org.onosproject.routing.FibListener; 45 import org.onosproject.routing.FibListener;
...@@ -74,7 +74,7 @@ public class RouterAsyncArpTest { ...@@ -74,7 +74,7 @@ public class RouterAsyncArpTest {
74 DeviceId.deviceId("of:0000000000000003"), 74 DeviceId.deviceId("of:0000000000000003"),
75 PortNumber.portNumber(1)); 75 PortNumber.portNumber(1));
76 76
77 - private Router router; 77 + private DefaultRouter router;
78 private InternalHostListener internalHostListener; 78 private InternalHostListener internalHostListener;
79 79
80 @Before 80 @Before
...@@ -90,7 +90,7 @@ public class RouterAsyncArpTest { ...@@ -90,7 +90,7 @@ public class RouterAsyncArpTest {
90 90
91 fibListener = createMock(FibListener.class); 91 fibListener = createMock(FibListener.class);
92 92
93 - router = new Router(); 93 + router = new DefaultRouter();
94 router.coreService = createNiceMock(CoreService.class); 94 router.coreService = createNiceMock(CoreService.class);
95 router.hostService = hostService; 95 router.hostService = hostService;
96 router.routingConfigurationService = routingConfigurationService; 96 router.routingConfigurationService = routingConfigurationService;
......
...@@ -90,7 +90,7 @@ public class RouterTest { ...@@ -90,7 +90,7 @@ public class RouterTest {
90 private static final ConnectPoint SW6_ETH1 = new ConnectPoint( 90 private static final ConnectPoint SW6_ETH1 = new ConnectPoint(
91 DeviceId.deviceId("of:0000000000000006"), 91 DeviceId.deviceId("of:0000000000000006"),
92 PortNumber.portNumber(1)); 92 PortNumber.portNumber(1));
93 - private Router router; 93 + private DefaultRouter router;
94 94
95 @Before 95 @Before
96 public void setUp() throws Exception { 96 public void setUp() throws Exception {
...@@ -105,7 +105,7 @@ public class RouterTest { ...@@ -105,7 +105,7 @@ public class RouterTest {
105 105
106 fibListener = createMock(FibListener.class); 106 fibListener = createMock(FibListener.class);
107 107
108 - router = new Router(); 108 + router = new DefaultRouter();
109 router.coreService = createNiceMock(CoreService.class); 109 router.coreService = createNiceMock(CoreService.class);
110 router.hostService = hostService; 110 router.hostService = hostService;
111 router.routingConfigurationService = routingConfigurationService; 111 router.routingConfigurationService = routingConfigurationService;
......
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
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 +
17 +package org.onosproject.incubator.net.routing;
18 +
19 +import org.onlab.packet.IpAddress;
20 +
21 +import java.util.Collection;
22 +import java.util.Map;
23 +import java.util.Set;
24 +
25 +/**
26 + * Adapter class for the route service.
27 + */
28 +public class RouteServiceAdapter implements RouteAdminService {
29 + @Override
30 + public void update(Collection<Route> routes) {
31 +
32 + }
33 +
34 + @Override
35 + public void withdraw(Collection<Route> routes) {
36 +
37 + }
38 +
39 + @Override
40 + public Map<RouteTableId, Collection<Route>> getAllRoutes() {
41 + return null;
42 + }
43 +
44 + @Override
45 + public Route longestPrefixMatch(IpAddress ip) {
46 + return null;
47 + }
48 +
49 + @Override
50 + public Collection<Route> getRoutesForNextHop(IpAddress nextHop) {
51 + return null;
52 + }
53 +
54 + @Override
55 + public Set<NextHop> getNextHops() {
56 + return null;
57 + }
58 +
59 + @Override
60 + public void addListener(RouteListener listener) {
61 +
62 + }
63 +
64 + @Override
65 + public void removeListener(RouteListener listener) {
66 +
67 + }
68 +}