blob: 5925904e5052e85406b1f24e0871f5be4c39d8c9 [file] [log] [blame]
piere91c87f2019-10-16 16:58:20 +02001/*
2 * Copyright 2019-present Open Networking Foundation
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
17package org.onosproject.routeservice.impl;
18
19import org.onlab.util.PredictableExecutor;
20import org.onosproject.net.Host;
21import org.onosproject.net.host.HostService;
22import org.onosproject.routeservice.ResolvedRoute;
23import org.onosproject.routeservice.Route;
24import org.onosproject.routeservice.RouteSet;
25import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
27
28import java.util.Comparator;
29import java.util.Objects;
30import java.util.Optional;
31import java.util.Set;
32import java.util.stream.Collectors;
33
34import static org.onlab.util.Tools.groupedThreads;
35
36/**
37 * Resolves routes in multi-thread fashion.
38 */
39class RouteResolver {
40
41 private final Logger log = LoggerFactory.getLogger(this.getClass());
42 private static final int DEFAULT_BUCKETS = 0;
43 private RouteManager routeManager;
44 private HostService hostService;
45 protected PredictableExecutor routeResolvers;
46
47 /**
48 * Creates a new route resolver.
49 *
50 * @param routeManager route service
51 * @param hostService host service
52 */
53 RouteResolver(RouteManager routeManager, HostService hostService) {
54 this.routeManager = routeManager;
55 this.hostService = hostService;
56 routeResolvers = new PredictableExecutor(DEFAULT_BUCKETS, groupedThreads("onos/route-resolver",
57 "route-resolver-%d", log));
58 }
59
60 /**
61 * Shuts down the route resolver.
62 */
63 void shutdown() {
64 routeResolvers.shutdown();
65 }
66
67 private ResolvedRoute tryResolve(Route route) {
68 ResolvedRoute resolvedRoute = resolve(route);
69 if (resolvedRoute == null) {
70 resolvedRoute = new ResolvedRoute(route, null, null);
71 }
72 return resolvedRoute;
73 }
74
75 // Used by external reads
76 Set<ResolvedRoute> resolveRouteSet(RouteSet routeSet) {
77 return routeSet.routes().stream()
78 .map(this::tryResolve)
79 .collect(Collectors.toSet());
80 }
81
82 // Used by external reads and by resolvers
83 ResolvedRoute resolve(Route route) {
84 hostService.startMonitoringIp(route.nextHop());
85 Set<Host> hosts = hostService.getHostsByIp(route.nextHop());
86
87 return hosts.stream().findFirst()
88 .map(host -> new ResolvedRoute(route, host.mac(), host.vlan()))
89 .orElse(null);
90 }
91
92 private ResolvedRoute decide(ResolvedRoute route1, ResolvedRoute route2) {
93 return Comparator.comparing(ResolvedRoute::nextHop)
94 .compare(route1, route2) <= 0 ? route1 : route2;
95 }
96
97 private void resolveInternal(RouteSet routes) {
98 if (routes.routes() == null) {
99 // The routes were removed before we got to them, nothing to do
100 return;
101 }
102
103 Set<ResolvedRoute> resolvedRoutes = routes.routes().stream()
104 .map(this::resolve)
105 .filter(Objects::nonNull)
106 .collect(Collectors.toSet());
107
108 Optional<ResolvedRoute> bestRoute = resolvedRoutes.stream()
109 .reduce(this::decide);
110
111 if (bestRoute.isPresent()) {
112 routeManager.store(bestRoute.get(), resolvedRoutes);
113 } else {
114 routeManager.remove(routes.prefix());
115 }
116 }
117
118 // Offload to the resolvers using prefix hashcode as hint
119 // TODO Remove RouteManager reference using PickyCallable
120 void resolve(RouteSet routes) {
121 routeResolvers.execute(() -> resolveInternal(routes), routes.prefix().hashCode());
122 }
123}