blob: b55dba6aba173655d34e73179a94d8a059fd3421 [file] [log] [blame]
Jonathan Hartdf207092015-12-10 11:19:25 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-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 Hartc22e8472015-11-17 18:25:45 -080017package org.onosproject.routing.impl;
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;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070022import com.google.common.collect.Sets;
Jonathan Hartdf207092015-12-10 11:19:25 -080023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
Jonathan Hartb9401902016-02-02 18:46:01 -080026import org.apache.felix.scr.annotations.Modified;
27import org.apache.felix.scr.annotations.Property;
Jonathan Hartdf207092015-12-10 11:19:25 -080028import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
30import org.onlab.packet.Ethernet;
31import org.onlab.packet.IpAddress;
32import org.onlab.packet.IpPrefix;
Charles Chand55e84d2016-03-30 17:54:24 -070033import org.onlab.packet.MacAddress;
Jonathan Hartca47cd72015-12-13 12:31:09 -080034import org.onlab.packet.VlanId;
Jonathan Hartb9401902016-02-02 18:46:01 -080035import org.onlab.util.Tools;
gaurava2e61a52016-05-05 03:39:31 +053036import org.onosproject.app.ApplicationService;
Jonathan Hartb9401902016-02-02 18:46:01 -080037import org.onosproject.cfg.ComponentConfigService;
Jonathan Hartdf207092015-12-10 11:19:25 -080038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
Charles Chand55e84d2016-03-30 17:54:24 -070040import org.onosproject.incubator.net.config.basics.McastConfig;
Jonathan Hartdf207092015-12-10 11:19:25 -080041import org.onosproject.incubator.net.intf.Interface;
42import org.onosproject.incubator.net.intf.InterfaceService;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070043import org.onosproject.incubator.net.routing.ResolvedRoute;
44import org.onosproject.incubator.net.routing.RouteEvent;
45import org.onosproject.incubator.net.routing.RouteListener;
46import org.onosproject.incubator.net.routing.RouteService;
Saurav Das49cb5a12016-01-16 22:54:07 -080047import org.onosproject.net.ConnectPoint;
Jonathan Hartdf207092015-12-10 11:19:25 -080048import org.onosproject.net.DeviceId;
Charles Chand55e84d2016-03-30 17:54:24 -070049import org.onosproject.net.config.ConfigFactory;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -080050import org.onosproject.net.config.NetworkConfigEvent;
51import org.onosproject.net.config.NetworkConfigListener;
Charles Chand55e84d2016-03-30 17:54:24 -070052import org.onosproject.net.config.NetworkConfigRegistry;
Jonathan Hartdf207092015-12-10 11:19:25 -080053import org.onosproject.net.config.NetworkConfigService;
Charles Chand55e84d2016-03-30 17:54:24 -070054import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hartdf207092015-12-10 11:19:25 -080055import org.onosproject.net.device.DeviceService;
56import org.onosproject.net.flow.DefaultTrafficSelector;
57import org.onosproject.net.flow.DefaultTrafficTreatment;
58import org.onosproject.net.flow.TrafficSelector;
59import org.onosproject.net.flow.TrafficTreatment;
60import org.onosproject.net.flow.criteria.Criteria;
61import org.onosproject.net.flowobjective.DefaultFilteringObjective;
62import org.onosproject.net.flowobjective.DefaultForwardingObjective;
63import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070064import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080065import org.onosproject.net.flowobjective.FilteringObjective;
66import org.onosproject.net.flowobjective.FlowObjectiveService;
67import org.onosproject.net.flowobjective.ForwardingObjective;
68import org.onosproject.net.flowobjective.NextObjective;
Jonathan Hartdf207092015-12-10 11:19:25 -080069import org.onosproject.net.flowobjective.ObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080070import org.onosproject.routing.RoutingService;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -080071import org.onosproject.routing.config.RouterConfig;
Jonathan Hartb9401902016-02-02 18:46:01 -080072import org.osgi.service.component.ComponentContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080073import org.slf4j.Logger;
74import org.slf4j.LoggerFactory;
75
Jonathan Hartb9401902016-02-02 18:46:01 -080076import java.util.Dictionary;
Jonathan Hartdf207092015-12-10 11:19:25 -080077import java.util.Map;
Jonathan Hartdf207092015-12-10 11:19:25 -080078import java.util.Set;
79
80/**
81 * Programs routes to a single OpenFlow switch.
82 */
Jonathan Hartc22e8472015-11-17 18:25:45 -080083@Component(immediate = true, enabled = false)
84public class SingleSwitchFibInstaller {
Jonathan Hartdf207092015-12-10 11:19:25 -080085
86 private final Logger log = LoggerFactory.getLogger(getClass());
gaurava2e61a52016-05-05 03:39:31 +053087 private static final String APP_NAME = "org.onosproject.vrouter";
Jonathan Hartdf207092015-12-10 11:19:25 -080088
89 private static final int PRIORITY_OFFSET = 100;
90 private static final int PRIORITY_MULTIPLIER = 5;
91
Charles Chan03a73e02016-10-24 14:52:01 -070092 // FIXME: This should be eliminated when we have an API in SR that
93 // programs the fabric switches for VR
Saurav Das49cb5a12016-01-16 22:54:07 -080094 public static final short ASSIGNED_VLAN = 4094;
95
Jonathan Hartdf207092015-12-10 11:19:25 -080096 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected CoreService coreService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700100 protected RouteService routeService;
Jonathan Hartdf207092015-12-10 11:19:25 -0800101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected InterfaceService interfaceService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected NetworkConfigService networkConfigService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chand55e84d2016-03-30 17:54:24 -0700109 protected NetworkConfigRegistry networkConfigRegistry;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartb9401902016-02-02 18:46:01 -0800112 protected ComponentConfigService componentConfigService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800115 protected FlowObjectiveService flowObjectiveService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected DeviceService deviceService;
119
gaurava2e61a52016-05-05 03:39:31 +0530120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected ApplicationService applicationService;
122
Jonathan Hartb9401902016-02-02 18:46:01 -0800123 @Property(name = "routeToNextHop", boolValue = false,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530124 label = "Install a /32 or /128 route to each next hop")
Jonathan Hartb9401902016-02-02 18:46:01 -0800125 private boolean routeToNextHop = false;
126
Jonathan Hartdf207092015-12-10 11:19:25 -0800127 // Device id of data-plane switch - should be learned from config
128 private DeviceId deviceId;
129
Saurav Das49cb5a12016-01-16 22:54:07 -0800130 private ConnectPoint controlPlaneConnectPoint;
131
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700132 private RouterInterfaceManager interfaceManager;
133 private AsyncDeviceFetcher asyncDeviceFetcher;
Jonathan Hart883fd372016-02-10 14:36:15 -0800134
Charles Chand55e84d2016-03-30 17:54:24 -0700135 private ApplicationId coreAppId;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800136 private ApplicationId routerAppId;
gaurava2e61a52016-05-05 03:39:31 +0530137 private ApplicationId vrouterAppId;
Jonathan Hartdf207092015-12-10 11:19:25 -0800138
139 // Reference count for how many times a next hop is used by a route
140 private final Multiset<IpAddress> nextHopsCount = ConcurrentHashMultiset.create();
141
142 // Mapping from prefix to its current next hop
143 private final Map<IpPrefix, IpAddress> prefixToNextHop = Maps.newHashMap();
144
145 // Mapping from next hop IP to next hop object containing group info
146 private final Map<IpAddress, Integer> nextHops = Maps.newHashMap();
147
Jonathan Hart25bd6682016-06-03 10:45:47 -0700148 private final InternalRouteListener routeListener = new InternalRouteListener();
149 private final InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
Jonathan Hartdf207092015-12-10 11:19:25 -0800150
Charles Chand55e84d2016-03-30 17:54:24 -0700151 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
152 new ConfigFactory<ApplicationId, McastConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
153 McastConfig.class, "multicast") {
154 @Override
155 public McastConfig createConfig() {
156 return new McastConfig();
157 }
158 };
159
Jonathan Hartdf207092015-12-10 11:19:25 -0800160 @Activate
Jonathan Hartb9401902016-02-02 18:46:01 -0800161 protected void activate(ComponentContext context) {
Jonathan Hartb9401902016-02-02 18:46:01 -0800162 componentConfigService.registerProperties(getClass());
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800163 modified(context);
164
Charles Chand55e84d2016-03-30 17:54:24 -0700165 coreAppId = coreService.registerApplication(CoreService.CORE_APP_NAME);
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800166 routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
gaurava2e61a52016-05-05 03:39:31 +0530167 vrouterAppId = coreService.registerApplication(APP_NAME);
Jonathan Hartb9401902016-02-02 18:46:01 -0800168
Charles Chand55e84d2016-03-30 17:54:24 -0700169 networkConfigRegistry.registerConfigFactory(mcastConfigFactory);
170
Jonathan Hart25bd6682016-06-03 10:45:47 -0700171 networkConfigService.addListener(configListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700172
173 asyncDeviceFetcher = AsyncDeviceFetcher.create(deviceService);
gaurav164cf6d2016-03-25 21:43:04 +0530174
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800175 processRouterConfig();
Jonathan Hartdf207092015-12-10 11:19:25 -0800176
Charles Chan00d8b5f2016-12-04 17:17:39 -0800177 // FIXME: There can be an issue when this component is deactivated before vRouter.
178 // This will be addressed in CORD-710.
Jonathan Hartf8035d32016-06-16 16:23:26 -0700179 applicationService.registerDeactivateHook(vrouterAppId, () -> 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() {
Charles Chan00d8b5f2016-12-04 17:17:39 -0800186 // FIXME: This will also remove flows when an instance goes down.
187 // This is a temporary solution and should be addressed in CORD-710.
188 cleanUp();
189
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700190 asyncDeviceFetcher.shutdown();
Jonathan Hart25bd6682016-06-03 10:45:47 -0700191 networkConfigService.removeListener(configListener);
gaurav164cf6d2016-03-25 21:43:04 +0530192
Jonathan Hartb9401902016-02-02 18:46:01 -0800193 componentConfigService.unregisterProperties(getClass(), false);
194
Jonathan Hartdf207092015-12-10 11:19:25 -0800195 log.info("Stopped");
196 }
197
Jonathan Hartb9401902016-02-02 18:46:01 -0800198 @Modified
199 protected void modified(ComponentContext context) {
200 Dictionary<?, ?> properties = context.getProperties();
201 if (properties == null) {
202 return;
203 }
204
205 String strRouteToNextHop = Tools.get(properties, "routeToNextHop");
206 routeToNextHop = Boolean.parseBoolean(strRouteToNextHop);
207
208 log.info("routeToNextHop set to {}", routeToNextHop);
209 }
210
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800211 private void processRouterConfig() {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800212 RouterConfig routerConfig =
213 networkConfigService.getConfig(routerAppId, RoutingService.ROUTER_CONFIG_CLASS);
Jonathan Hartdf207092015-12-10 11:19:25 -0800214
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800215 if (routerConfig == null) {
216 log.info("Router config not available");
Jonathan Hartdf207092015-12-10 11:19:25 -0800217 return;
218 }
219
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700220 Set<String> interfaces = Sets.newHashSet(routerConfig.getInterfaces());
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800221
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700222 if (deviceId == null) {
223 controlPlaneConnectPoint = routerConfig.getControlPlaneConnectPoint();
224 log.info("Control Plane Connect Point: {}", controlPlaneConnectPoint);
Jonathan Hart883fd372016-02-10 14:36:15 -0800225
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700226 deviceId = routerConfig.getControlPlaneConnectPoint().deviceId();
227 log.info("Router device ID is {}", deviceId);
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800228
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700229 routeService.addListener(routeListener);
230 asyncDeviceFetcher.getDevice(deviceId).whenComplete((deviceId, e) ->
231 interfaceManager = createRouter(deviceId, interfaces));
gaurava2e61a52016-05-05 03:39:31 +0530232 } else {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700233 interfaceManager.changeConfiguredInterfaces(interfaces);
gaurava2e61a52016-05-05 03:39:31 +0530234 }
gaurav25118892016-08-24 05:35:03 +0530235 }
236
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800237 /*
238 * Removes filtering objectives and routes before deactivate.
239 */
240 private void cleanUp() {
241 //remove the route listener
242 routeService.removeListener(routeListener);
243
244 //clean up the routes.
245 for (Map.Entry<IpPrefix, IpAddress> routes: prefixToNextHop.entrySet()) {
246 deleteRoute(new ResolvedRoute(routes.getKey(), null, null, null));
247 }
248
249 if (interfaceManager != null) {
250 interfaceManager.cleanup();
251 }
252 }
253
254 private RouterInterfaceManager createRouter(DeviceId deviceId, Set<String> configuredInterfaces) {
255 return new RouterInterfaceManager(deviceId,
256 configuredInterfaces,
257 interfaceService,
258 this::provisionInterface,
259 this::unprovisionInterface);
260 }
261
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700262 private void updateRoute(ResolvedRoute route) {
263 addNextHop(route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800264
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700265 Integer nextId;
266 synchronized (this) {
267 nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800268 }
269
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700270 flowObjectiveService.forward(deviceId,
271 generateRibForwardingObj(route.prefix(), nextId).add());
272 log.trace("Sending forwarding objective {} -> nextId:{}", route, nextId);
Jonathan Hartdf207092015-12-10 11:19:25 -0800273 }
274
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700275 private synchronized void deleteRoute(ResolvedRoute route) {
276 //Integer nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800277
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700278 /* Group group = deleteNextHop(route.prefix());
279 if (group == null) {
280 log.warn("Group not found when deleting {}", route);
281 return;
282 }*/
Jonathan Hartdf207092015-12-10 11:19:25 -0800283
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700284 flowObjectiveService.forward(deviceId,
285 generateRibForwardingObj(route.prefix(), null).remove());
Jonathan Hartdf207092015-12-10 11:19:25 -0800286 }
287
288 private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
289 Integer nextId) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530290 TrafficSelector selector = buildIpSelectorFromIpPrefix(prefix).build();
Jonathan Hartdf207092015-12-10 11:19:25 -0800291 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
292
293 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
Saurav Das49cb5a12016-01-16 22:54:07 -0800294 .fromApp(routerAppId)
Jonathan Hartdf207092015-12-10 11:19:25 -0800295 .makePermanent()
296 .withSelector(selector)
297 .withPriority(priority)
298 .withFlag(ForwardingObjective.Flag.SPECIFIC);
299
300 if (nextId == null) {
301 // Route withdraws are not specified with next hops. Generating
302 // dummy treatment as there is no equivalent nextId info.
303 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
304 } else {
305 fwdBuilder.nextStep(nextId);
306 }
307 return fwdBuilder;
308 }
309
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530310 /**
311 * Method to build IPv4 or IPv6 selector.
312 *
313 * @param prefixToMatch the prefix to match
314 * @return the traffic selector builder
315 */
316 private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
317 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
318 // If the prefix is IPv4
319 if (prefixToMatch.isIp4()) {
320 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
321 selectorBuilder.matchIPDst(prefixToMatch);
322 return selectorBuilder;
323 }
324 // If the prefix is IPv6
325 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
326 selectorBuilder.matchIPv6Dst(prefixToMatch);
327 return selectorBuilder;
328 }
329
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700330 private synchronized void addNextHop(ResolvedRoute route) {
331 prefixToNextHop.put(route.prefix(), route.nextHop());
332 if (nextHopsCount.count(route.nextHop()) == 0) {
Jonathan Hartdf207092015-12-10 11:19:25 -0800333 // There was no next hop in the multiset
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700334 Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800335 if (egressIntf == null) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700336 log.warn("no egress interface found for {}", route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800337 return;
338 }
339
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700340 NextHopGroupKey groupKey = new NextHopGroupKey(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800341
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700342 NextHop nextHop = new NextHop(route.nextHop(), route.nextHopMac(), groupKey);
Jonathan Hartdf207092015-12-10 11:19:25 -0800343
Jonathan Hartca47cd72015-12-13 12:31:09 -0800344 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800345 .setEthSrc(egressIntf.mac())
Jonathan Hartca47cd72015-12-13 12:31:09 -0800346 .setEthDst(nextHop.mac());
347
Saurav Das49cb5a12016-01-16 22:54:07 -0800348 TrafficSelector.Builder metabuilder = null;
Jonathan Hartca47cd72015-12-13 12:31:09 -0800349 if (!egressIntf.vlan().equals(VlanId.NONE)) {
350 treatment.pushVlan()
351 .setVlanId(egressIntf.vlan())
352 .setVlanPcp((byte) 0);
Saurav Das49cb5a12016-01-16 22:54:07 -0800353 } else {
354 // untagged outgoing port may require internal vlan in some pipelines
355 metabuilder = DefaultTrafficSelector.builder();
356 metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
Jonathan Hartca47cd72015-12-13 12:31:09 -0800357 }
358
359 treatment.setOutput(egressIntf.connectPoint().port());
Jonathan Hartdf207092015-12-10 11:19:25 -0800360
361 int nextId = flowObjectiveService.allocateNextId();
Saurav Das49cb5a12016-01-16 22:54:07 -0800362 NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800363 .withId(nextId)
Jonathan Hartca47cd72015-12-13 12:31:09 -0800364 .addTreatment(treatment.build())
Jonathan Hartdf207092015-12-10 11:19:25 -0800365 .withType(NextObjective.Type.SIMPLE)
Saurav Das49cb5a12016-01-16 22:54:07 -0800366 .fromApp(routerAppId);
367 if (metabuilder != null) {
368 nextBuilder.withMeta(metabuilder.build());
369 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800370
Saurav Das49cb5a12016-01-16 22:54:07 -0800371 NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
Jonathan Hartdf207092015-12-10 11:19:25 -0800372 flowObjectiveService.next(deviceId, nextObjective);
373
374 nextHops.put(nextHop.ip(), nextId);
375
Jonathan Hartb9401902016-02-02 18:46:01 -0800376 if (routeToNextHop) {
377 // Install route to next hop
378 ForwardingObjective fob =
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700379 generateRibForwardingObj(IpPrefix.valueOf(route.nextHop(), 32), nextId).add();
Jonathan Hartb9401902016-02-02 18:46:01 -0800380 flowObjectiveService.forward(deviceId, fob);
381 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800382 }
383
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700384 nextHopsCount.add(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800385 }
386
387 /*private synchronized Group deleteNextHop(IpPrefix prefix) {
388 IpAddress nextHopIp = prefixToNextHop.remove(prefix);
389 NextHop nextHop = nextHops.get(nextHopIp);
390 if (nextHop == null) {
391 log.warn("No next hop found when removing prefix {}", prefix);
392 return null;
393 }
394
395 Group group = groupService.getGroup(deviceId,
396 new DefaultGroupKey(appKryo.
397 serialize(nextHop.group())));
398
399 // FIXME disabling group deletes for now until we verify the logic is OK
400 if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
401 // There was one or less next hops, so there are now none
402
403 log.debug("removing group for next hop {}", nextHop);
404
405 nextHops.remove(nextHopIp);
406
407 groupService.removeGroup(deviceId,
408 new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
409 appId);
410 }
411
412 return group;
413 }*/
414
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800415 private void provisionInterface(Interface intf) {
416 updateInterfaceFilters(intf, true);
gaurav164cf6d2016-03-25 21:43:04 +0530417 }
418
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800419 private void unprovisionInterface(Interface intf) {
420 updateInterfaceFilters(intf, false);
421 }
422
423 /**
424 * Installs or removes flow objectives relating to an interface.
425 *
426 * @param intf interface to update objectives for
427 * @param install true to install the objectives, false to remove them
428 */
429 private void updateInterfaceFilters(Interface intf, boolean install) {
430 updateFilteringObjective(intf, install);
431 updateMcastFilteringObjective(intf, install);
432 }
433
434 /**
435 * Installs or removes unicast filtering objectives relating to an interface.
436 *
437 * @param intf interface to update objectives for
438 * @param install true to install the objectives, false to remove them
439 */
440 private void updateFilteringObjective(Interface intf, boolean install) {
Charles Chand55e84d2016-03-30 17:54:24 -0700441 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
442 VlanId.vlanId(ASSIGNED_VLAN) :
443 egressVlan();
gaurav164cf6d2016-03-25 21:43:04 +0530444
445 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
446 // first add filter for the interface
447 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
448 .addCondition(Criteria.matchEthDst(intf.mac()))
449 .addCondition(Criteria.matchVlanId(intf.vlan()));
450 fob.withPriority(PRIORITY_OFFSET);
451 if (intf.vlan() == VlanId.NONE) {
452 TrafficTreatment tt = DefaultTrafficTreatment.builder()
Charles Chand55e84d2016-03-30 17:54:24 -0700453 .pushVlan().setVlanId(assignedVlan).build();
gaurav164cf6d2016-03-25 21:43:04 +0530454 fob.withMeta(tt);
455 }
gaurav164cf6d2016-03-25 21:43:04 +0530456 fob.permit().fromApp(routerAppId);
457 sendFilteringObjective(install, fob, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700458
gaurav164cf6d2016-03-25 21:43:04 +0530459 if (controlPlaneConnectPoint != null) {
460 // then add the same mac/vlan filters for control-plane connect point
461 fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port()));
Saurav Das49cb5a12016-01-16 22:54:07 -0800462 sendFilteringObjective(install, fob, intf);
Jonathan Hartdf207092015-12-10 11:19:25 -0800463 }
464 }
465
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800466 /**
467 * Installs or removes multicast filtering objectives relating to an interface.
468 *
469 * @param intf interface to update objectives for
470 * @param install true to install the objectives, false to remove them
471 */
472 private void updateMcastFilteringObjective(Interface intf, boolean install) {
Charles Chand55e84d2016-03-30 17:54:24 -0700473 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
474 VlanId.vlanId(ASSIGNED_VLAN) :
475 egressVlan();
476
477 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
478 // first add filter for the interface
479 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
480 .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
481 MacAddress.IPV4_MULTICAST_MASK))
482 .addCondition(Criteria.matchVlanId(ingressVlan()));
483 fob.withPriority(PRIORITY_OFFSET);
484 TrafficTreatment tt = DefaultTrafficTreatment.builder()
485 .pushVlan().setVlanId(assignedVlan).build();
486 fob.withMeta(tt);
487
488 fob.permit().fromApp(routerAppId);
489 sendFilteringObjective(install, fob, intf);
490 }
491
Saurav Das49cb5a12016-01-16 22:54:07 -0800492 private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
493 Interface intf) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800494
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700495 ObjectiveContext context = new DefaultObjectiveContext(
496 (objective) -> log.info("Installed filter for interface {}", intf),
497 (objective, error) ->
498 log.error("Failed to install filter for interface {}: {}", intf, error));
gaurav164cf6d2016-03-25 21:43:04 +0530499
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700500 FilteringObjective filter = install ? fob.add(context) : fob.remove(context);
501
502 flowObjectiveService.filter(deviceId, filter);
Saurav Das49cb5a12016-01-16 22:54:07 -0800503 }
504
Charles Chand55e84d2016-03-30 17:54:24 -0700505 private VlanId ingressVlan() {
506 McastConfig mcastConfig =
507 networkConfigService.getConfig(coreAppId, McastConfig.class);
508 return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
509 }
510
511 private VlanId egressVlan() {
512 McastConfig mcastConfig =
513 networkConfigService.getConfig(coreAppId, McastConfig.class);
514 return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
515 }
516
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800517 /**
518 * Listener for route changes.
519 */
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700520 private class InternalRouteListener implements RouteListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800521 @Override
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700522 public void event(RouteEvent event) {
523 ResolvedRoute route = event.subject();
524 switch (event.type()) {
525 case ROUTE_ADDED:
526 case ROUTE_UPDATED:
527 updateRoute(route);
528 break;
529 case ROUTE_REMOVED:
530 deleteRoute(route);
531 break;
532 default:
533 break;
534 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800535 }
536 }
537
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800538 /**
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800539 * Listener for network config events.
540 */
541 private class InternalNetworkConfigListener implements NetworkConfigListener {
542 @Override
543 public void event(NetworkConfigEvent event) {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700544 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800545 switch (event.type()) {
546 case CONFIG_ADDED:
547 case CONFIG_UPDATED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800548 processRouterConfig();
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800549 break;
550 case CONFIG_REGISTERED:
gaurav25118892016-08-24 05:35:03 +0530551 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800552 case CONFIG_UNREGISTERED:
gaurav25118892016-08-24 05:35:03 +0530553 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800554 case CONFIG_REMOVED:
gaurav25118892016-08-24 05:35:03 +0530555 cleanUp();
556 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800557 default:
558 break;
559 }
560 }
561 }
562 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800563}