blob: 04b435200a7f4e970d69e57a3a9932fb94813b8b [file] [log] [blame]
Jonathan Hartdf207092015-12-10 11:19:25 -08001/*
Jonathan Hartf4bd0482017-01-27 15:11:18 -08002 * Copyright 2017-present Open Networking Laboratory
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;
43import org.onosproject.incubator.net.routing.RouteEvent;
44import org.onosproject.incubator.net.routing.RouteListener;
45import org.onosproject.incubator.net.routing.RouteService;
Jonathan Hartdf207092015-12-10 11:19:25 -080046import org.onosproject.net.DeviceId;
Charles Chand55e84d2016-03-30 17:54:24 -070047import org.onosproject.net.config.ConfigFactory;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -080048import org.onosproject.net.config.NetworkConfigEvent;
49import org.onosproject.net.config.NetworkConfigListener;
Charles Chand55e84d2016-03-30 17:54:24 -070050import org.onosproject.net.config.NetworkConfigRegistry;
Jonathan Hartdf207092015-12-10 11:19:25 -080051import org.onosproject.net.config.NetworkConfigService;
Charles Chand55e84d2016-03-30 17:54:24 -070052import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hartdf207092015-12-10 11:19:25 -080053import org.onosproject.net.device.DeviceService;
54import org.onosproject.net.flow.DefaultTrafficSelector;
55import org.onosproject.net.flow.DefaultTrafficTreatment;
56import org.onosproject.net.flow.TrafficSelector;
57import org.onosproject.net.flow.TrafficTreatment;
58import org.onosproject.net.flow.criteria.Criteria;
59import org.onosproject.net.flowobjective.DefaultFilteringObjective;
60import org.onosproject.net.flowobjective.DefaultForwardingObjective;
61import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070062import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080063import org.onosproject.net.flowobjective.FilteringObjective;
64import org.onosproject.net.flowobjective.FlowObjectiveService;
65import org.onosproject.net.flowobjective.ForwardingObjective;
66import org.onosproject.net.flowobjective.NextObjective;
Jonathan Hartdf207092015-12-10 11:19:25 -080067import org.onosproject.net.flowobjective.ObjectiveContext;
Jonathan Hartf4bd0482017-01-27 15:11:18 -080068import org.onosproject.routing.AsyncDeviceFetcher;
69import org.onosproject.routing.NextHop;
70import org.onosproject.routing.NextHopGroupKey;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080071import org.onosproject.routing.RouterInfo;
72import org.onosproject.routing.InterfaceProvisionRequest;
73import org.onosproject.routing.Router;
Jonathan Hartdf207092015-12-10 11:19:25 -080074import org.onosproject.routing.RoutingService;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080075import org.onosproject.routing.config.RouterConfigHelper;
76import org.onosproject.routing.config.RoutersConfig;
77import org.onosproject.routing.config.RoutingConfigurationService;
Jonathan Hartb9401902016-02-02 18:46:01 -080078import org.osgi.service.component.ComponentContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080079import org.slf4j.Logger;
80import org.slf4j.LoggerFactory;
81
Jonathan Hartb9401902016-02-02 18:46:01 -080082import java.util.Dictionary;
Jonathan Hartdf207092015-12-10 11:19:25 -080083import java.util.Map;
Jonathan Hartdf207092015-12-10 11:19:25 -080084import java.util.Set;
85
86/**
87 * Programs routes to a single OpenFlow switch.
88 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080089@Component(immediate = true)
Jonathan Harte7327042017-02-02 13:11:25 -080090public class FibInstaller {
Jonathan Hartdf207092015-12-10 11:19:25 -080091
92 private final Logger log = LoggerFactory.getLogger(getClass());
Jonathan Harte7327042017-02-02 13:11:25 -080093 private static final String APP_NAME = "org.onosproject.fibinstaller";
Jonathan Hartdf207092015-12-10 11:19:25 -080094
95 private static final int PRIORITY_OFFSET = 100;
96 private static final int PRIORITY_MULTIPLIER = 5;
97
Charles Chan03a73e02016-10-24 14:52:01 -070098 // FIXME: This should be eliminated when we have an API in SR that
99 // programs the fabric switches for VR
Saurav Das49cb5a12016-01-16 22:54:07 -0800100 public static final short ASSIGNED_VLAN = 4094;
101
Jonathan Hartdf207092015-12-10 11:19:25 -0800102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected CoreService coreService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700106 protected RouteService routeService;
Jonathan Hartdf207092015-12-10 11:19:25 -0800107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected InterfaceService interfaceService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected NetworkConfigService networkConfigService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chand55e84d2016-03-30 17:54:24 -0700115 protected NetworkConfigRegistry networkConfigRegistry;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartb9401902016-02-02 18:46:01 -0800118 protected ComponentConfigService componentConfigService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800121 protected FlowObjectiveService flowObjectiveService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected DeviceService deviceService;
125
gaurava2e61a52016-05-05 03:39:31 +0530126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected ApplicationService applicationService;
128
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected RoutingConfigurationService rs;
131
Jonathan Hartb9401902016-02-02 18:46:01 -0800132 @Property(name = "routeToNextHop", boolValue = false,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530133 label = "Install a /32 or /128 route to each next hop")
Jonathan Hartb9401902016-02-02 18:46:01 -0800134 private boolean routeToNextHop = false;
135
Jonathan Hartdf207092015-12-10 11:19:25 -0800136 // Device id of data-plane switch - should be learned from config
137 private DeviceId deviceId;
138
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800139 private Router interfaceManager;
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700140 private AsyncDeviceFetcher asyncDeviceFetcher;
Jonathan Hart883fd372016-02-10 14:36:15 -0800141
Charles Chand55e84d2016-03-30 17:54:24 -0700142 private ApplicationId coreAppId;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800143 private ApplicationId routerAppId;
Jonathan Harte7327042017-02-02 13:11:25 -0800144 private ApplicationId fibAppId;
Jonathan Hartdf207092015-12-10 11:19:25 -0800145
146 // Reference count for how many times a next hop is used by a route
147 private final Multiset<IpAddress> nextHopsCount = ConcurrentHashMultiset.create();
148
149 // Mapping from prefix to its current next hop
150 private final Map<IpPrefix, IpAddress> prefixToNextHop = Maps.newHashMap();
151
152 // Mapping from next hop IP to next hop object containing group info
153 private final Map<IpAddress, Integer> nextHops = Maps.newHashMap();
154
Jonathan Hart25bd6682016-06-03 10:45:47 -0700155 private final InternalRouteListener routeListener = new InternalRouteListener();
156 private final InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
Jonathan Hartdf207092015-12-10 11:19:25 -0800157
Charles Chand55e84d2016-03-30 17:54:24 -0700158 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
159 new ConfigFactory<ApplicationId, McastConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
160 McastConfig.class, "multicast") {
161 @Override
162 public McastConfig createConfig() {
163 return new McastConfig();
164 }
165 };
166
Jonathan Hartdf207092015-12-10 11:19:25 -0800167 @Activate
Jonathan Hartb9401902016-02-02 18:46:01 -0800168 protected void activate(ComponentContext context) {
Jonathan Hartb9401902016-02-02 18:46:01 -0800169 componentConfigService.registerProperties(getClass());
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800170 modified(context);
171
Charles Chand55e84d2016-03-30 17:54:24 -0700172 coreAppId = coreService.registerApplication(CoreService.CORE_APP_NAME);
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800173 routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
Jonathan Harte7327042017-02-02 13:11:25 -0800174 fibAppId = coreService.registerApplication(APP_NAME);
Jonathan Hartb9401902016-02-02 18:46:01 -0800175
Charles Chand55e84d2016-03-30 17:54:24 -0700176 networkConfigRegistry.registerConfigFactory(mcastConfigFactory);
177
Jonathan Hart25bd6682016-06-03 10:45:47 -0700178 networkConfigService.addListener(configListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700179
180 asyncDeviceFetcher = AsyncDeviceFetcher.create(deviceService);
gaurav164cf6d2016-03-25 21:43:04 +0530181
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800182 processRouterConfig();
Jonathan Hartdf207092015-12-10 11:19:25 -0800183
Jonathan Harte7327042017-02-02 13:11:25 -0800184 applicationService.registerDeactivateHook(fibAppId, () -> cleanUp());
gaurava2e61a52016-05-05 03:39:31 +0530185
Jonathan Hartdf207092015-12-10 11:19:25 -0800186 log.info("Started");
187 }
188
189 @Deactivate
190 protected void deactivate() {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700191 asyncDeviceFetcher.shutdown();
Jonathan Hart25bd6682016-06-03 10:45:47 -0700192 networkConfigService.removeListener(configListener);
gaurav164cf6d2016-03-25 21:43:04 +0530193
Jonathan Hartb9401902016-02-02 18:46:01 -0800194 componentConfigService.unregisterProperties(getClass(), false);
195
Jonathan Hartdf207092015-12-10 11:19:25 -0800196 log.info("Stopped");
197 }
198
Jonathan Hartb9401902016-02-02 18:46:01 -0800199 @Modified
200 protected void modified(ComponentContext context) {
201 Dictionary<?, ?> properties = context.getProperties();
202 if (properties == null) {
203 return;
204 }
205
206 String strRouteToNextHop = Tools.get(properties, "routeToNextHop");
207 routeToNextHop = Boolean.parseBoolean(strRouteToNextHop);
208
209 log.info("routeToNextHop set to {}", routeToNextHop);
210 }
211
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800212 private void processRouterConfig() {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800213 Set<RoutersConfig.Router> routerConfigs =
214 RouterConfigHelper.getRouterConfigurations(networkConfigService, routerAppId);
215 if (routerConfigs.isEmpty()) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800216 log.info("Router config not available");
Jonathan Hartdf207092015-12-10 11:19:25 -0800217 return;
218 }
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800219 RoutersConfig.Router routerConfig = routerConfigs.stream().findFirst().get();
Jonathan Hartdf207092015-12-10 11:19:25 -0800220
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800221 if (interfaceManager == null) {
222 deviceId = routerConfig.controlPlaneConnectPoint().deviceId();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700223 log.info("Router device ID is {}", deviceId);
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800224
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700225 routeService.addListener(routeListener);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800226
227 interfaceManager = createRouter(RouterInfo.from(routerConfig));
gaurava2e61a52016-05-05 03:39:31 +0530228 } else {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800229 interfaceManager.changeConfiguration(RouterInfo.from(routerConfig));
gaurava2e61a52016-05-05 03:39:31 +0530230 }
gaurav25118892016-08-24 05:35:03 +0530231 }
232
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800233 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800234 * Removes filtering objectives and routes before deactivate.
235 */
236 private void cleanUp() {
237 //remove the route listener
238 routeService.removeListener(routeListener);
239
240 //clean up the routes.
241 for (Map.Entry<IpPrefix, IpAddress> routes: prefixToNextHop.entrySet()) {
242 deleteRoute(new ResolvedRoute(routes.getKey(), null, null, null));
243 }
244
245 if (interfaceManager != null) {
246 interfaceManager.cleanup();
247 }
248 }
249
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800250 private Router createRouter(RouterInfo info) {
251 return new Router(
252 info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800253 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800254 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800255 this::provisionInterface,
256 this::unprovisionInterface);
257 }
258
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700259 private void updateRoute(ResolvedRoute route) {
260 addNextHop(route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800261
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700262 Integer nextId;
263 synchronized (this) {
264 nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800265 }
266
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700267 flowObjectiveService.forward(deviceId,
268 generateRibForwardingObj(route.prefix(), nextId).add());
269 log.trace("Sending forwarding objective {} -> nextId:{}", route, nextId);
Jonathan Hartdf207092015-12-10 11:19:25 -0800270 }
271
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700272 private synchronized void deleteRoute(ResolvedRoute route) {
273 //Integer nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800274
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700275 /* Group group = deleteNextHop(route.prefix());
276 if (group == null) {
277 log.warn("Group not found when deleting {}", route);
278 return;
279 }*/
Jonathan Hartdf207092015-12-10 11:19:25 -0800280
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700281 flowObjectiveService.forward(deviceId,
282 generateRibForwardingObj(route.prefix(), null).remove());
Jonathan Hartdf207092015-12-10 11:19:25 -0800283 }
284
285 private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
286 Integer nextId) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530287 TrafficSelector selector = buildIpSelectorFromIpPrefix(prefix).build();
Jonathan Hartdf207092015-12-10 11:19:25 -0800288 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
289
290 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
Jonathan Harte7327042017-02-02 13:11:25 -0800291 .fromApp(fibAppId)
Jonathan Hartdf207092015-12-10 11:19:25 -0800292 .makePermanent()
293 .withSelector(selector)
294 .withPriority(priority)
295 .withFlag(ForwardingObjective.Flag.SPECIFIC);
296
297 if (nextId == null) {
298 // Route withdraws are not specified with next hops. Generating
299 // dummy treatment as there is no equivalent nextId info.
300 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
301 } else {
302 fwdBuilder.nextStep(nextId);
303 }
304 return fwdBuilder;
305 }
306
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530307 /**
308 * Method to build IPv4 or IPv6 selector.
309 *
310 * @param prefixToMatch the prefix to match
311 * @return the traffic selector builder
312 */
313 private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
314 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
315 // If the prefix is IPv4
316 if (prefixToMatch.isIp4()) {
317 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
318 selectorBuilder.matchIPDst(prefixToMatch);
319 return selectorBuilder;
320 }
321 // If the prefix is IPv6
322 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
323 selectorBuilder.matchIPv6Dst(prefixToMatch);
324 return selectorBuilder;
325 }
326
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700327 private synchronized void addNextHop(ResolvedRoute route) {
328 prefixToNextHop.put(route.prefix(), route.nextHop());
329 if (nextHopsCount.count(route.nextHop()) == 0) {
Jonathan Hartdf207092015-12-10 11:19:25 -0800330 // There was no next hop in the multiset
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700331 Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800332 if (egressIntf == null) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700333 log.warn("no egress interface found for {}", route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800334 return;
335 }
336
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700337 NextHopGroupKey groupKey = new NextHopGroupKey(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800338
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700339 NextHop nextHop = new NextHop(route.nextHop(), route.nextHopMac(), groupKey);
Jonathan Hartdf207092015-12-10 11:19:25 -0800340
Jonathan Hartca47cd72015-12-13 12:31:09 -0800341 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800342 .setEthSrc(egressIntf.mac())
Jonathan Hartca47cd72015-12-13 12:31:09 -0800343 .setEthDst(nextHop.mac());
344
Saurav Das49cb5a12016-01-16 22:54:07 -0800345 TrafficSelector.Builder metabuilder = null;
Jonathan Hartca47cd72015-12-13 12:31:09 -0800346 if (!egressIntf.vlan().equals(VlanId.NONE)) {
347 treatment.pushVlan()
348 .setVlanId(egressIntf.vlan())
349 .setVlanPcp((byte) 0);
Saurav Das49cb5a12016-01-16 22:54:07 -0800350 } else {
351 // untagged outgoing port may require internal vlan in some pipelines
352 metabuilder = DefaultTrafficSelector.builder();
353 metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
Jonathan Hartca47cd72015-12-13 12:31:09 -0800354 }
355
356 treatment.setOutput(egressIntf.connectPoint().port());
Jonathan Hartdf207092015-12-10 11:19:25 -0800357
358 int nextId = flowObjectiveService.allocateNextId();
Saurav Das49cb5a12016-01-16 22:54:07 -0800359 NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800360 .withId(nextId)
Jonathan Hartca47cd72015-12-13 12:31:09 -0800361 .addTreatment(treatment.build())
Jonathan Hartdf207092015-12-10 11:19:25 -0800362 .withType(NextObjective.Type.SIMPLE)
Jonathan Harte7327042017-02-02 13:11:25 -0800363 .fromApp(fibAppId);
Saurav Das49cb5a12016-01-16 22:54:07 -0800364 if (metabuilder != null) {
365 nextBuilder.withMeta(metabuilder.build());
366 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800367
Saurav Das49cb5a12016-01-16 22:54:07 -0800368 NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
Jonathan Hartdf207092015-12-10 11:19:25 -0800369 flowObjectiveService.next(deviceId, nextObjective);
370
371 nextHops.put(nextHop.ip(), nextId);
372
Jonathan Hartb9401902016-02-02 18:46:01 -0800373 if (routeToNextHop) {
374 // Install route to next hop
375 ForwardingObjective fob =
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700376 generateRibForwardingObj(IpPrefix.valueOf(route.nextHop(), 32), nextId).add();
Jonathan Hartb9401902016-02-02 18:46:01 -0800377 flowObjectiveService.forward(deviceId, fob);
378 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800379 }
380
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700381 nextHopsCount.add(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800382 }
383
384 /*private synchronized Group deleteNextHop(IpPrefix prefix) {
385 IpAddress nextHopIp = prefixToNextHop.remove(prefix);
386 NextHop nextHop = nextHops.get(nextHopIp);
387 if (nextHop == null) {
388 log.warn("No next hop found when removing prefix {}", prefix);
389 return null;
390 }
391
392 Group group = groupService.getGroup(deviceId,
393 new DefaultGroupKey(appKryo.
394 serialize(nextHop.group())));
395
396 // FIXME disabling group deletes for now until we verify the logic is OK
397 if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
398 // There was one or less next hops, so there are now none
399
400 log.debug("removing group for next hop {}", nextHop);
401
402 nextHops.remove(nextHopIp);
403
404 groupService.removeGroup(deviceId,
405 new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
406 appId);
407 }
408
409 return group;
410 }*/
411
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800412 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800413 updateInterfaceFilters(intf, true);
gaurav164cf6d2016-03-25 21:43:04 +0530414 }
415
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800416 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800417 updateInterfaceFilters(intf, false);
418 }
419
420 /**
421 * Installs or removes flow objectives relating to an interface.
422 *
423 * @param intf interface to update objectives for
424 * @param install true to install the objectives, false to remove them
425 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800426 private void updateInterfaceFilters(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800427 updateFilteringObjective(intf, install);
428 updateMcastFilteringObjective(intf, install);
429 }
430
431 /**
432 * Installs or removes unicast filtering objectives relating to an interface.
433 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800434 * @param routerIntf interface to update objectives for
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800435 * @param install true to install the objectives, false to remove them
436 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800437 private void updateFilteringObjective(InterfaceProvisionRequest routerIntf, boolean install) {
438 Interface intf = routerIntf.intf();
Charles Chand55e84d2016-03-30 17:54:24 -0700439 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
440 VlanId.vlanId(ASSIGNED_VLAN) :
441 egressVlan();
gaurav164cf6d2016-03-25 21:43:04 +0530442
443 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
444 // first add filter for the interface
445 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
446 .addCondition(Criteria.matchEthDst(intf.mac()))
447 .addCondition(Criteria.matchVlanId(intf.vlan()));
448 fob.withPriority(PRIORITY_OFFSET);
449 if (intf.vlan() == VlanId.NONE) {
450 TrafficTreatment tt = DefaultTrafficTreatment.builder()
Charles Chand55e84d2016-03-30 17:54:24 -0700451 .pushVlan().setVlanId(assignedVlan).build();
gaurav164cf6d2016-03-25 21:43:04 +0530452 fob.withMeta(tt);
453 }
Jonathan Harte7327042017-02-02 13:11:25 -0800454 fob.permit().fromApp(fibAppId);
gaurav164cf6d2016-03-25 21:43:04 +0530455 sendFilteringObjective(install, fob, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700456
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800457 // then add the same mac/vlan filters for control-plane connect point
458 fob.withKey(Criteria.matchInPort(routerIntf.controlPlaneConnectPoint().port()));
459 sendFilteringObjective(install, fob, intf);
Jonathan Hartdf207092015-12-10 11:19:25 -0800460 }
461
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800462 /**
463 * Installs or removes multicast filtering objectives relating to an interface.
464 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800465 * @param routerIntf interface to update objectives for
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800466 * @param install true to install the objectives, false to remove them
467 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800468 private void updateMcastFilteringObjective(InterfaceProvisionRequest routerIntf, boolean install) {
469 Interface intf = routerIntf.intf();
Charles Chand55e84d2016-03-30 17:54:24 -0700470 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
471 VlanId.vlanId(ASSIGNED_VLAN) :
472 egressVlan();
473
474 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
475 // first add filter for the interface
476 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
477 .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
478 MacAddress.IPV4_MULTICAST_MASK))
479 .addCondition(Criteria.matchVlanId(ingressVlan()));
480 fob.withPriority(PRIORITY_OFFSET);
481 TrafficTreatment tt = DefaultTrafficTreatment.builder()
482 .pushVlan().setVlanId(assignedVlan).build();
483 fob.withMeta(tt);
484
Jonathan Harte7327042017-02-02 13:11:25 -0800485 fob.permit().fromApp(fibAppId);
Charles Chand55e84d2016-03-30 17:54:24 -0700486 sendFilteringObjective(install, fob, intf);
487 }
488
Saurav Das49cb5a12016-01-16 22:54:07 -0800489 private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
490 Interface intf) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800491
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700492 ObjectiveContext context = new DefaultObjectiveContext(
493 (objective) -> log.info("Installed filter for interface {}", intf),
494 (objective, error) ->
495 log.error("Failed to install filter for interface {}: {}", intf, error));
gaurav164cf6d2016-03-25 21:43:04 +0530496
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700497 FilteringObjective filter = install ? fob.add(context) : fob.remove(context);
498
499 flowObjectiveService.filter(deviceId, filter);
Saurav Das49cb5a12016-01-16 22:54:07 -0800500 }
501
Charles Chand55e84d2016-03-30 17:54:24 -0700502 private VlanId ingressVlan() {
503 McastConfig mcastConfig =
504 networkConfigService.getConfig(coreAppId, McastConfig.class);
505 return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
506 }
507
508 private VlanId egressVlan() {
509 McastConfig mcastConfig =
510 networkConfigService.getConfig(coreAppId, McastConfig.class);
511 return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
512 }
513
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800514 /**
515 * Listener for route changes.
516 */
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700517 private class InternalRouteListener implements RouteListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800518 @Override
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700519 public void event(RouteEvent event) {
520 ResolvedRoute route = event.subject();
521 switch (event.type()) {
522 case ROUTE_ADDED:
523 case ROUTE_UPDATED:
524 updateRoute(route);
525 break;
526 case ROUTE_REMOVED:
527 deleteRoute(route);
528 break;
529 default:
530 break;
531 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800532 }
533 }
534
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800535 /**
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800536 * Listener for network config events.
537 */
538 private class InternalNetworkConfigListener implements NetworkConfigListener {
539 @Override
540 public void event(NetworkConfigEvent event) {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700541 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800542 switch (event.type()) {
543 case CONFIG_ADDED:
544 case CONFIG_UPDATED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800545 processRouterConfig();
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800546 break;
547 case CONFIG_REGISTERED:
gaurav25118892016-08-24 05:35:03 +0530548 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800549 case CONFIG_UNREGISTERED:
gaurav25118892016-08-24 05:35:03 +0530550 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800551 case CONFIG_REMOVED:
gaurav25118892016-08-24 05:35:03 +0530552 cleanUp();
553 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800554 default:
555 break;
556 }
557 }
558 }
559 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800560}