blob: e24aff1506bf73bad4ce950f7c7e78c375ea1b8a [file] [log] [blame]
Jonathan Hartdf207092015-12-10 11:19:25 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Jonathan Hartdf207092015-12-10 11:19:25 -08003 *
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
Jonathan Hartf4bd0482017-01-27 15:11:18 -080017package org.onosproject.routing.fibinstaller;
Jonathan Hartdf207092015-12-10 11:19:25 -080018
19import com.google.common.collect.ConcurrentHashMultiset;
Jonathan Hartdf207092015-12-10 11:19:25 -080020import com.google.common.collect.Maps;
Jonathan Hartdf207092015-12-10 11:19:25 -080021import com.google.common.collect.Multiset;
22import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
Jonathan Hartb9401902016-02-02 18:46:01 -080025import org.apache.felix.scr.annotations.Modified;
26import org.apache.felix.scr.annotations.Property;
Jonathan Hartdf207092015-12-10 11:19:25 -080027import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.onlab.packet.Ethernet;
30import org.onlab.packet.IpAddress;
31import org.onlab.packet.IpPrefix;
Charles Chand55e84d2016-03-30 17:54:24 -070032import org.onlab.packet.MacAddress;
Jonathan Hartca47cd72015-12-13 12:31:09 -080033import org.onlab.packet.VlanId;
Jonathan Hartb9401902016-02-02 18:46:01 -080034import org.onlab.util.Tools;
gaurava2e61a52016-05-05 03:39:31 +053035import org.onosproject.app.ApplicationService;
Jonathan Hartb9401902016-02-02 18:46:01 -080036import org.onosproject.cfg.ComponentConfigService;
Jonathan Hartdf207092015-12-10 11:19:25 -080037import org.onosproject.core.ApplicationId;
38import org.onosproject.core.CoreService;
Charles Chand55e84d2016-03-30 17:54:24 -070039import org.onosproject.incubator.net.config.basics.McastConfig;
Jonathan Hartdf207092015-12-10 11:19:25 -080040import org.onosproject.incubator.net.intf.Interface;
41import org.onosproject.incubator.net.intf.InterfaceService;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070042import org.onosproject.incubator.net.routing.ResolvedRoute;
Jonathan Hartf2e7a342017-03-20 15:43:21 -070043import org.onosproject.incubator.net.routing.Route;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070044import org.onosproject.incubator.net.routing.RouteEvent;
45import org.onosproject.incubator.net.routing.RouteListener;
46import org.onosproject.incubator.net.routing.RouteService;
Jonathan Hartdf207092015-12-10 11:19:25 -080047import org.onosproject.net.DeviceId;
Charles Chand55e84d2016-03-30 17:54:24 -070048import org.onosproject.net.config.ConfigFactory;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -080049import org.onosproject.net.config.NetworkConfigEvent;
50import org.onosproject.net.config.NetworkConfigListener;
Charles Chand55e84d2016-03-30 17:54:24 -070051import org.onosproject.net.config.NetworkConfigRegistry;
Jonathan Hartdf207092015-12-10 11:19:25 -080052import org.onosproject.net.config.NetworkConfigService;
Charles Chand55e84d2016-03-30 17:54:24 -070053import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hartdf207092015-12-10 11:19:25 -080054import org.onosproject.net.device.DeviceService;
55import org.onosproject.net.flow.DefaultTrafficSelector;
56import org.onosproject.net.flow.DefaultTrafficTreatment;
57import org.onosproject.net.flow.TrafficSelector;
58import org.onosproject.net.flow.TrafficTreatment;
59import org.onosproject.net.flow.criteria.Criteria;
60import org.onosproject.net.flowobjective.DefaultFilteringObjective;
61import org.onosproject.net.flowobjective.DefaultForwardingObjective;
62import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070063import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080064import org.onosproject.net.flowobjective.FilteringObjective;
65import org.onosproject.net.flowobjective.FlowObjectiveService;
66import org.onosproject.net.flowobjective.ForwardingObjective;
67import org.onosproject.net.flowobjective.NextObjective;
Jonathan Hartdf207092015-12-10 11:19:25 -080068import org.onosproject.net.flowobjective.ObjectiveContext;
Jonathan Hartf2e7a342017-03-20 15:43:21 -070069import org.onosproject.routing.InterfaceProvisionRequest;
Jonathan Hartf4bd0482017-01-27 15:11:18 -080070import org.onosproject.routing.NextHop;
71import org.onosproject.routing.NextHopGroupKey;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080072import org.onosproject.routing.Router;
Jonathan Hartf2e7a342017-03-20 15:43:21 -070073import org.onosproject.routing.RouterInfo;
Jonathan Hartdf207092015-12-10 11:19:25 -080074import org.onosproject.routing.RoutingService;
Jonathan Hart60e7f512017-02-10 10:24:24 -080075import org.onosproject.routing.config.RoutingConfiguration;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080076import org.onosproject.routing.config.RoutersConfig;
Jonathan Hartb9401902016-02-02 18:46:01 -080077import org.osgi.service.component.ComponentContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080078import org.slf4j.Logger;
79import org.slf4j.LoggerFactory;
80
Jonathan Hartb9401902016-02-02 18:46:01 -080081import java.util.Dictionary;
Jonathan Hartdf207092015-12-10 11:19:25 -080082import java.util.Map;
Jonathan Hartdf207092015-12-10 11:19:25 -080083import java.util.Set;
84
85/**
86 * Programs routes to a single OpenFlow switch.
87 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080088@Component(immediate = true)
Jonathan Harte7327042017-02-02 13:11:25 -080089public class FibInstaller {
Jonathan Hartdf207092015-12-10 11:19:25 -080090
91 private final Logger log = LoggerFactory.getLogger(getClass());
Jonathan Harte7327042017-02-02 13:11:25 -080092 private static final String APP_NAME = "org.onosproject.fibinstaller";
Jonathan Hartdf207092015-12-10 11:19:25 -080093
94 private static final int PRIORITY_OFFSET = 100;
95 private static final int PRIORITY_MULTIPLIER = 5;
96
Charles Chan03a73e02016-10-24 14:52:01 -070097 // FIXME: This should be eliminated when we have an API in SR that
98 // programs the fabric switches for VR
Saurav Das49cb5a12016-01-16 22:54:07 -080099 public static final short ASSIGNED_VLAN = 4094;
100
Jonathan Hartdf207092015-12-10 11:19:25 -0800101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected CoreService coreService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700105 protected RouteService routeService;
Jonathan Hartdf207092015-12-10 11:19:25 -0800106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected InterfaceService interfaceService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected NetworkConfigService networkConfigService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chand55e84d2016-03-30 17:54:24 -0700114 protected NetworkConfigRegistry networkConfigRegistry;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartb9401902016-02-02 18:46:01 -0800117 protected ComponentConfigService componentConfigService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800120 protected FlowObjectiveService flowObjectiveService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected DeviceService deviceService;
124
gaurava2e61a52016-05-05 03:39:31 +0530125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected ApplicationService applicationService;
127
Jonathan Hartb9401902016-02-02 18:46:01 -0800128 @Property(name = "routeToNextHop", boolValue = false,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530129 label = "Install a /32 or /128 route to each next hop")
Jonathan Hartb9401902016-02-02 18:46:01 -0800130 private boolean routeToNextHop = false;
131
Jonathan Hartdf207092015-12-10 11:19:25 -0800132 // Device id of data-plane switch - should be learned from config
133 private DeviceId deviceId;
134
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800135 private Router interfaceManager;
Jonathan Hart883fd372016-02-10 14:36:15 -0800136
Charles Chand55e84d2016-03-30 17:54:24 -0700137 private ApplicationId coreAppId;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800138 private ApplicationId routerAppId;
Jonathan Harte7327042017-02-02 13:11:25 -0800139 private ApplicationId fibAppId;
Jonathan Hartdf207092015-12-10 11:19:25 -0800140
141 // Reference count for how many times a next hop is used by a route
142 private final Multiset<IpAddress> nextHopsCount = ConcurrentHashMultiset.create();
143
144 // Mapping from prefix to its current next hop
145 private final Map<IpPrefix, IpAddress> prefixToNextHop = Maps.newHashMap();
146
147 // Mapping from next hop IP to next hop object containing group info
148 private final Map<IpAddress, Integer> nextHops = Maps.newHashMap();
149
Jonathan Hart25bd6682016-06-03 10:45:47 -0700150 private final InternalRouteListener routeListener = new InternalRouteListener();
151 private final InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
Jonathan Hartdf207092015-12-10 11:19:25 -0800152
Charles Chand55e84d2016-03-30 17:54:24 -0700153 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
154 new ConfigFactory<ApplicationId, McastConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
155 McastConfig.class, "multicast") {
156 @Override
157 public McastConfig createConfig() {
158 return new McastConfig();
159 }
160 };
161
Jonathan Hartdf207092015-12-10 11:19:25 -0800162 @Activate
Jonathan Hartb9401902016-02-02 18:46:01 -0800163 protected void activate(ComponentContext context) {
Jonathan Hartb9401902016-02-02 18:46:01 -0800164 componentConfigService.registerProperties(getClass());
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800165 modified(context);
166
Jonathan Hart60e7f512017-02-10 10:24:24 -0800167 RoutingConfiguration.register(networkConfigRegistry);
168
Charles Chand55e84d2016-03-30 17:54:24 -0700169 coreAppId = coreService.registerApplication(CoreService.CORE_APP_NAME);
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800170 routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
Jonathan Harte7327042017-02-02 13:11:25 -0800171 fibAppId = coreService.registerApplication(APP_NAME);
Jonathan Hartb9401902016-02-02 18:46:01 -0800172
Charles Chand55e84d2016-03-30 17:54:24 -0700173 networkConfigRegistry.registerConfigFactory(mcastConfigFactory);
174
Jonathan Hart25bd6682016-06-03 10:45:47 -0700175 networkConfigService.addListener(configListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700176
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800177 processRouterConfig();
Jonathan Hartdf207092015-12-10 11:19:25 -0800178
Jonathan Harte7327042017-02-02 13:11:25 -0800179 applicationService.registerDeactivateHook(fibAppId, () -> cleanUp());
gaurava2e61a52016-05-05 03:39:31 +0530180
Jonathan Hartdf207092015-12-10 11:19:25 -0800181 log.info("Started");
182 }
183
184 @Deactivate
185 protected void deactivate() {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700186 networkConfigService.removeListener(configListener);
gaurav164cf6d2016-03-25 21:43:04 +0530187
Jonathan Hart60e7f512017-02-10 10:24:24 -0800188 RoutingConfiguration.unregister(networkConfigRegistry);
189
Jonathan Hartb9401902016-02-02 18:46:01 -0800190 componentConfigService.unregisterProperties(getClass(), false);
191
Jonathan Hartdf207092015-12-10 11:19:25 -0800192 log.info("Stopped");
193 }
194
Jonathan Hartb9401902016-02-02 18:46:01 -0800195 @Modified
196 protected void modified(ComponentContext context) {
197 Dictionary<?, ?> properties = context.getProperties();
198 if (properties == null) {
199 return;
200 }
201
202 String strRouteToNextHop = Tools.get(properties, "routeToNextHop");
203 routeToNextHop = Boolean.parseBoolean(strRouteToNextHop);
204
205 log.info("routeToNextHop set to {}", routeToNextHop);
206 }
207
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800208 private void processRouterConfig() {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800209 Set<RoutersConfig.Router> routerConfigs =
Jonathan Hart60e7f512017-02-10 10:24:24 -0800210 RoutingConfiguration.getRouterConfigurations(networkConfigService, routerAppId);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800211 if (routerConfigs.isEmpty()) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800212 log.info("Router config not available");
Jonathan Hartdf207092015-12-10 11:19:25 -0800213 return;
214 }
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800215 RoutersConfig.Router routerConfig = routerConfigs.stream().findFirst().get();
Jonathan Hartdf207092015-12-10 11:19:25 -0800216
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800217 if (interfaceManager == null) {
218 deviceId = routerConfig.controlPlaneConnectPoint().deviceId();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700219 log.info("Router device ID is {}", deviceId);
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800220
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700221 routeService.addListener(routeListener);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800222
223 interfaceManager = createRouter(RouterInfo.from(routerConfig));
gaurava2e61a52016-05-05 03:39:31 +0530224 } else {
Charles Chanc6d227e2017-02-28 15:15:17 -0800225 interfaceManager.changeConfiguration(RouterInfo.from(routerConfig), false);
gaurava2e61a52016-05-05 03:39:31 +0530226 }
gaurav25118892016-08-24 05:35:03 +0530227 }
228
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800229 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800230 * Removes filtering objectives and routes before deactivate.
231 */
232 private void cleanUp() {
233 //remove the route listener
234 routeService.removeListener(routeListener);
235
236 //clean up the routes.
Jonathan Hartf2e7a342017-03-20 15:43:21 -0700237 prefixToNextHop.entrySet().stream()
238 .map(e -> new Route(Route.Source.UNDEFINED, e.getKey(), e.getValue()))
239 .forEach(this::deleteRoute);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800240
241 if (interfaceManager != null) {
242 interfaceManager.cleanup();
243 }
244 }
245
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800246 private Router createRouter(RouterInfo info) {
247 return new Router(
248 info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800249 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800250 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800251 this::provisionInterface,
Charles Chanc6d227e2017-02-28 15:15:17 -0800252 this::unprovisionInterface,
253 false);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800254 }
255
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700256 private void updateRoute(ResolvedRoute route) {
257 addNextHop(route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800258
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700259 Integer nextId;
260 synchronized (this) {
261 nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800262 }
263
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700264 flowObjectiveService.forward(deviceId,
265 generateRibForwardingObj(route.prefix(), nextId).add());
266 log.trace("Sending forwarding objective {} -> nextId:{}", route, nextId);
Jonathan Hartdf207092015-12-10 11:19:25 -0800267 }
268
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700269 private synchronized void deleteRoute(ResolvedRoute route) {
Jonathan Hart10dbafd2017-05-18 15:53:03 -0700270 deleteRoute(route.route());
Jonathan Hartf2e7a342017-03-20 15:43:21 -0700271 }
272
273 private void deleteRoute(Route route) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700274 //Integer nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800275
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700276 /* Group group = deleteNextHop(route.prefix());
277 if (group == null) {
278 log.warn("Group not found when deleting {}", route);
279 return;
280 }*/
Jonathan Hartdf207092015-12-10 11:19:25 -0800281
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700282 flowObjectiveService.forward(deviceId,
283 generateRibForwardingObj(route.prefix(), null).remove());
Jonathan Hartdf207092015-12-10 11:19:25 -0800284 }
285
286 private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
287 Integer nextId) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530288 TrafficSelector selector = buildIpSelectorFromIpPrefix(prefix).build();
Jonathan Hartdf207092015-12-10 11:19:25 -0800289 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
290
291 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
Jonathan Harte7327042017-02-02 13:11:25 -0800292 .fromApp(fibAppId)
Jonathan Hartdf207092015-12-10 11:19:25 -0800293 .makePermanent()
294 .withSelector(selector)
295 .withPriority(priority)
296 .withFlag(ForwardingObjective.Flag.SPECIFIC);
297
298 if (nextId == null) {
299 // Route withdraws are not specified with next hops. Generating
300 // dummy treatment as there is no equivalent nextId info.
301 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
302 } else {
303 fwdBuilder.nextStep(nextId);
304 }
305 return fwdBuilder;
306 }
307
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530308 /**
309 * Method to build IPv4 or IPv6 selector.
310 *
311 * @param prefixToMatch the prefix to match
312 * @return the traffic selector builder
313 */
314 private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
315 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
316 // If the prefix is IPv4
317 if (prefixToMatch.isIp4()) {
318 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
319 selectorBuilder.matchIPDst(prefixToMatch);
320 return selectorBuilder;
321 }
322 // If the prefix is IPv6
323 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
324 selectorBuilder.matchIPv6Dst(prefixToMatch);
325 return selectorBuilder;
326 }
327
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700328 private synchronized void addNextHop(ResolvedRoute route) {
329 prefixToNextHop.put(route.prefix(), route.nextHop());
330 if (nextHopsCount.count(route.nextHop()) == 0) {
Jonathan Hartdf207092015-12-10 11:19:25 -0800331 // There was no next hop in the multiset
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700332 Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800333 if (egressIntf == null) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700334 log.warn("no egress interface found for {}", route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800335 return;
336 }
337
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700338 NextHopGroupKey groupKey = new NextHopGroupKey(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800339
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700340 NextHop nextHop = new NextHop(route.nextHop(), route.nextHopMac(), groupKey);
Jonathan Hartdf207092015-12-10 11:19:25 -0800341
Jonathan Hartca47cd72015-12-13 12:31:09 -0800342 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800343 .setEthSrc(egressIntf.mac())
Jonathan Hartca47cd72015-12-13 12:31:09 -0800344 .setEthDst(nextHop.mac());
345
Saurav Das49cb5a12016-01-16 22:54:07 -0800346 TrafficSelector.Builder metabuilder = null;
Jonathan Hartca47cd72015-12-13 12:31:09 -0800347 if (!egressIntf.vlan().equals(VlanId.NONE)) {
348 treatment.pushVlan()
349 .setVlanId(egressIntf.vlan())
350 .setVlanPcp((byte) 0);
Saurav Das49cb5a12016-01-16 22:54:07 -0800351 } else {
352 // untagged outgoing port may require internal vlan in some pipelines
353 metabuilder = DefaultTrafficSelector.builder();
354 metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
Jonathan Hartca47cd72015-12-13 12:31:09 -0800355 }
356
357 treatment.setOutput(egressIntf.connectPoint().port());
Jonathan Hartdf207092015-12-10 11:19:25 -0800358
359 int nextId = flowObjectiveService.allocateNextId();
Saurav Das49cb5a12016-01-16 22:54:07 -0800360 NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800361 .withId(nextId)
Jonathan Hartca47cd72015-12-13 12:31:09 -0800362 .addTreatment(treatment.build())
Jonathan Hartdf207092015-12-10 11:19:25 -0800363 .withType(NextObjective.Type.SIMPLE)
Jonathan Harte7327042017-02-02 13:11:25 -0800364 .fromApp(fibAppId);
Saurav Das49cb5a12016-01-16 22:54:07 -0800365 if (metabuilder != null) {
366 nextBuilder.withMeta(metabuilder.build());
367 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800368
Saurav Das49cb5a12016-01-16 22:54:07 -0800369 NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
Jonathan Hartdf207092015-12-10 11:19:25 -0800370 flowObjectiveService.next(deviceId, nextObjective);
371
372 nextHops.put(nextHop.ip(), nextId);
373
Jonathan Hartb9401902016-02-02 18:46:01 -0800374 if (routeToNextHop) {
375 // Install route to next hop
376 ForwardingObjective fob =
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700377 generateRibForwardingObj(IpPrefix.valueOf(route.nextHop(), 32), nextId).add();
Jonathan Hartb9401902016-02-02 18:46:01 -0800378 flowObjectiveService.forward(deviceId, fob);
379 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800380 }
381
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700382 nextHopsCount.add(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800383 }
384
385 /*private synchronized Group deleteNextHop(IpPrefix prefix) {
386 IpAddress nextHopIp = prefixToNextHop.remove(prefix);
387 NextHop nextHop = nextHops.get(nextHopIp);
388 if (nextHop == null) {
389 log.warn("No next hop found when removing prefix {}", prefix);
390 return null;
391 }
392
393 Group group = groupService.getGroup(deviceId,
394 new DefaultGroupKey(appKryo.
395 serialize(nextHop.group())));
396
397 // FIXME disabling group deletes for now until we verify the logic is OK
398 if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
399 // There was one or less next hops, so there are now none
400
401 log.debug("removing group for next hop {}", nextHop);
402
403 nextHops.remove(nextHopIp);
404
405 groupService.removeGroup(deviceId,
406 new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
407 appId);
408 }
409
410 return group;
411 }*/
412
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800413 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800414 updateInterfaceFilters(intf, true);
gaurav164cf6d2016-03-25 21:43:04 +0530415 }
416
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800417 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800418 updateInterfaceFilters(intf, false);
419 }
420
421 /**
422 * Installs or removes flow objectives relating to an interface.
423 *
424 * @param intf interface to update objectives for
425 * @param install true to install the objectives, false to remove them
426 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800427 private void updateInterfaceFilters(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800428 updateFilteringObjective(intf, install);
429 updateMcastFilteringObjective(intf, install);
430 }
431
432 /**
433 * Installs or removes unicast filtering objectives relating to an interface.
434 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800435 * @param routerIntf interface to update objectives for
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800436 * @param install true to install the objectives, false to remove them
437 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800438 private void updateFilteringObjective(InterfaceProvisionRequest routerIntf, boolean install) {
439 Interface intf = routerIntf.intf();
Charles Chand55e84d2016-03-30 17:54:24 -0700440 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
441 VlanId.vlanId(ASSIGNED_VLAN) :
442 egressVlan();
gaurav164cf6d2016-03-25 21:43:04 +0530443
444 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
445 // first add filter for the interface
446 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
447 .addCondition(Criteria.matchEthDst(intf.mac()))
448 .addCondition(Criteria.matchVlanId(intf.vlan()));
449 fob.withPriority(PRIORITY_OFFSET);
450 if (intf.vlan() == VlanId.NONE) {
451 TrafficTreatment tt = DefaultTrafficTreatment.builder()
Charles Chand55e84d2016-03-30 17:54:24 -0700452 .pushVlan().setVlanId(assignedVlan).build();
gaurav164cf6d2016-03-25 21:43:04 +0530453 fob.withMeta(tt);
454 }
Jonathan Harte7327042017-02-02 13:11:25 -0800455 fob.permit().fromApp(fibAppId);
gaurav164cf6d2016-03-25 21:43:04 +0530456 sendFilteringObjective(install, fob, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700457
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800458 // then add the same mac/vlan filters for control-plane connect point
459 fob.withKey(Criteria.matchInPort(routerIntf.controlPlaneConnectPoint().port()));
460 sendFilteringObjective(install, fob, intf);
Jonathan Hartdf207092015-12-10 11:19:25 -0800461 }
462
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800463 /**
464 * Installs or removes multicast filtering objectives relating to an interface.
465 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800466 * @param routerIntf interface to update objectives for
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800467 * @param install true to install the objectives, false to remove them
468 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800469 private void updateMcastFilteringObjective(InterfaceProvisionRequest routerIntf, boolean install) {
470 Interface intf = routerIntf.intf();
Charles Chand55e84d2016-03-30 17:54:24 -0700471 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
472 VlanId.vlanId(ASSIGNED_VLAN) :
473 egressVlan();
474
475 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
476 // first add filter for the interface
477 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
478 .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
479 MacAddress.IPV4_MULTICAST_MASK))
480 .addCondition(Criteria.matchVlanId(ingressVlan()));
481 fob.withPriority(PRIORITY_OFFSET);
482 TrafficTreatment tt = DefaultTrafficTreatment.builder()
483 .pushVlan().setVlanId(assignedVlan).build();
484 fob.withMeta(tt);
485
Jonathan Harte7327042017-02-02 13:11:25 -0800486 fob.permit().fromApp(fibAppId);
Charles Chand55e84d2016-03-30 17:54:24 -0700487 sendFilteringObjective(install, fob, intf);
488 }
489
Saurav Das49cb5a12016-01-16 22:54:07 -0800490 private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
491 Interface intf) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800492
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700493 ObjectiveContext context = new DefaultObjectiveContext(
494 (objective) -> log.info("Installed filter for interface {}", intf),
495 (objective, error) ->
496 log.error("Failed to install filter for interface {}: {}", intf, error));
gaurav164cf6d2016-03-25 21:43:04 +0530497
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700498 FilteringObjective filter = install ? fob.add(context) : fob.remove(context);
499
500 flowObjectiveService.filter(deviceId, filter);
Saurav Das49cb5a12016-01-16 22:54:07 -0800501 }
502
Charles Chand55e84d2016-03-30 17:54:24 -0700503 private VlanId ingressVlan() {
504 McastConfig mcastConfig =
505 networkConfigService.getConfig(coreAppId, McastConfig.class);
506 return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
507 }
508
509 private VlanId egressVlan() {
510 McastConfig mcastConfig =
511 networkConfigService.getConfig(coreAppId, McastConfig.class);
512 return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
513 }
514
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800515 /**
516 * Listener for route changes.
517 */
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700518 private class InternalRouteListener implements RouteListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800519 @Override
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700520 public void event(RouteEvent event) {
521 ResolvedRoute route = event.subject();
522 switch (event.type()) {
523 case ROUTE_ADDED:
524 case ROUTE_UPDATED:
525 updateRoute(route);
526 break;
527 case ROUTE_REMOVED:
528 deleteRoute(route);
529 break;
530 default:
531 break;
532 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800533 }
534 }
535
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800536 /**
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800537 * Listener for network config events.
538 */
539 private class InternalNetworkConfigListener implements NetworkConfigListener {
540 @Override
541 public void event(NetworkConfigEvent event) {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700542 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800543 switch (event.type()) {
544 case CONFIG_ADDED:
545 case CONFIG_UPDATED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800546 processRouterConfig();
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800547 break;
548 case CONFIG_REGISTERED:
gaurav25118892016-08-24 05:35:03 +0530549 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800550 case CONFIG_UNREGISTERED:
gaurav25118892016-08-24 05:35:03 +0530551 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800552 case CONFIG_REMOVED:
gaurav25118892016-08-24 05:35:03 +0530553 cleanUp();
554 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800555 default:
556 break;
557 }
558 }
559 }
560 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800561}