blob: c036d8ca409d5b7d80d2f9e2c84b4d80b1438c3a [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;
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;
gaurav164cf6d2016-03-25 21:43:04 +053041import org.onosproject.incubator.net.intf.InterfaceEvent;
42import org.onosproject.incubator.net.intf.InterfaceListener;
Jonathan Hartdf207092015-12-10 11:19:25 -080043import org.onosproject.incubator.net.intf.InterfaceService;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070044import org.onosproject.incubator.net.routing.ResolvedRoute;
45import org.onosproject.incubator.net.routing.RouteEvent;
46import org.onosproject.incubator.net.routing.RouteListener;
47import org.onosproject.incubator.net.routing.RouteService;
Saurav Das49cb5a12016-01-16 22:54:07 -080048import org.onosproject.net.ConnectPoint;
Jonathan Hartdf207092015-12-10 11:19:25 -080049import org.onosproject.net.DeviceId;
Charles Chand55e84d2016-03-30 17:54:24 -070050import org.onosproject.net.config.ConfigFactory;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -080051import org.onosproject.net.config.NetworkConfigEvent;
52import org.onosproject.net.config.NetworkConfigListener;
Charles Chand55e84d2016-03-30 17:54:24 -070053import org.onosproject.net.config.NetworkConfigRegistry;
Jonathan Hartdf207092015-12-10 11:19:25 -080054import org.onosproject.net.config.NetworkConfigService;
Charles Chand55e84d2016-03-30 17:54:24 -070055import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hartdf207092015-12-10 11:19:25 -080056import org.onosproject.net.device.DeviceEvent;
57import org.onosproject.net.device.DeviceListener;
58import org.onosproject.net.device.DeviceService;
59import org.onosproject.net.flow.DefaultTrafficSelector;
60import org.onosproject.net.flow.DefaultTrafficTreatment;
61import org.onosproject.net.flow.TrafficSelector;
62import org.onosproject.net.flow.TrafficTreatment;
63import org.onosproject.net.flow.criteria.Criteria;
64import org.onosproject.net.flowobjective.DefaultFilteringObjective;
65import org.onosproject.net.flowobjective.DefaultForwardingObjective;
66import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070067import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080068import org.onosproject.net.flowobjective.FilteringObjective;
69import org.onosproject.net.flowobjective.FlowObjectiveService;
70import org.onosproject.net.flowobjective.ForwardingObjective;
71import org.onosproject.net.flowobjective.NextObjective;
Jonathan Hartdf207092015-12-10 11:19:25 -080072import org.onosproject.net.flowobjective.ObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080073import org.onosproject.routing.RoutingService;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -080074import org.onosproject.routing.config.RouterConfig;
Jonathan Hartb9401902016-02-02 18:46:01 -080075import org.osgi.service.component.ComponentContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080076import org.slf4j.Logger;
77import org.slf4j.LoggerFactory;
78
Jonathan Hartb9401902016-02-02 18:46:01 -080079import java.util.Dictionary;
Jonathan Hart883fd372016-02-10 14:36:15 -080080import java.util.List;
Jonathan Hartdf207092015-12-10 11:19:25 -080081import java.util.Map;
Jonathan Hartdf207092015-12-10 11:19:25 -080082import java.util.Set;
Jonathan Hart883fd372016-02-10 14:36:15 -080083import java.util.stream.Collectors;
Jonathan Hartdf207092015-12-10 11:19:25 -080084
85/**
86 * Programs routes to a single OpenFlow switch.
87 */
Jonathan Hartc22e8472015-11-17 18:25:45 -080088@Component(immediate = true, enabled = false)
89public class SingleSwitchFibInstaller {
Jonathan Hartdf207092015-12-10 11:19:25 -080090
91 private final Logger log = LoggerFactory.getLogger(getClass());
gaurava2e61a52016-05-05 03:39:31 +053092 private static final String APP_NAME = "org.onosproject.vrouter";
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
Saurav Das49cb5a12016-01-16 22:54:07 -080097 public static final short ASSIGNED_VLAN = 4094;
98
Jonathan Hartdf207092015-12-10 11:19:25 -080099 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected CoreService coreService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700103 protected RouteService routeService;
Jonathan Hartdf207092015-12-10 11:19:25 -0800104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected InterfaceService interfaceService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected NetworkConfigService networkConfigService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chand55e84d2016-03-30 17:54:24 -0700112 protected NetworkConfigRegistry networkConfigRegistry;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartb9401902016-02-02 18:46:01 -0800115 protected ComponentConfigService componentConfigService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800118 protected FlowObjectiveService flowObjectiveService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected DeviceService deviceService;
122
gaurava2e61a52016-05-05 03:39:31 +0530123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected ApplicationService applicationService;
125
Jonathan Hartb9401902016-02-02 18:46:01 -0800126 @Property(name = "routeToNextHop", boolValue = false,
127 label = "Install a /32 route to each next hop")
128 private boolean routeToNextHop = false;
129
Jonathan Hartdf207092015-12-10 11:19:25 -0800130 // Device id of data-plane switch - should be learned from config
131 private DeviceId deviceId;
132
Saurav Das49cb5a12016-01-16 22:54:07 -0800133 private ConnectPoint controlPlaneConnectPoint;
134
Jonathan Hart883fd372016-02-10 14:36:15 -0800135 private List<String> interfaces;
136
Charles Chand55e84d2016-03-30 17:54:24 -0700137 private ApplicationId coreAppId;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800138 private ApplicationId routerAppId;
gaurava2e61a52016-05-05 03:39:31 +0530139 private ApplicationId vrouterAppId;
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 InternalDeviceListener deviceListener = new InternalDeviceListener();
151 private final InternalInterfaceListener internalInterfaceList = new InternalInterfaceListener();
152 private final InternalRouteListener routeListener = new InternalRouteListener();
153 private final InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
Jonathan Hartdf207092015-12-10 11:19:25 -0800154
Charles Chand55e84d2016-03-30 17:54:24 -0700155 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
156 new ConfigFactory<ApplicationId, McastConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
157 McastConfig.class, "multicast") {
158 @Override
159 public McastConfig createConfig() {
160 return new McastConfig();
161 }
162 };
163
Jonathan Hartdf207092015-12-10 11:19:25 -0800164 @Activate
Jonathan Hartb9401902016-02-02 18:46:01 -0800165 protected void activate(ComponentContext context) {
Jonathan Hartb9401902016-02-02 18:46:01 -0800166 componentConfigService.registerProperties(getClass());
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800167 modified(context);
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);
gaurava2e61a52016-05-05 03:39:31 +0530171 vrouterAppId = 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 Hartdf207092015-12-10 11:19:25 -0800176 deviceService.addListener(deviceListener);
gaurav164cf6d2016-03-25 21:43:04 +0530177 interfaceService.addListener(internalInterfaceList);
178
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800179 updateConfig();
Jonathan Hartdf207092015-12-10 11:19:25 -0800180
Jonathan Hartf8035d32016-06-16 16:23:26 -0700181 applicationService.registerDeactivateHook(vrouterAppId, () -> cleanUp());
gaurava2e61a52016-05-05 03:39:31 +0530182
Jonathan Hartdf207092015-12-10 11:19:25 -0800183 log.info("Started");
184 }
185
186 @Deactivate
187 protected void deactivate() {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700188 routeService.removeListener(routeListener);
Jonathan Hartdf207092015-12-10 11:19:25 -0800189 deviceService.removeListener(deviceListener);
gaurav164cf6d2016-03-25 21:43:04 +0530190 interfaceService.removeListener(internalInterfaceList);
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
gaurava2e61a52016-05-05 03:39:31 +0530211 //remove filtering objectives and routes before deactivate.
212 private void cleanUp() {
gaurav25118892016-08-24 05:35:03 +0530213 //remove the route listener
214 routeService.removeListener(routeListener);
215
gaurava2e61a52016-05-05 03:39:31 +0530216 //clean up the routes.
217 for (Map.Entry<IpPrefix, IpAddress> routes: prefixToNextHop.entrySet()) {
218 deleteRoute(new ResolvedRoute(routes.getKey(), null, null));
219 }
gaurav25118892016-08-24 05:35:03 +0530220
gaurava2e61a52016-05-05 03:39:31 +0530221 //clean up the filtering objective for interfaces.
222 Set<Interface> intfs = getInterfaces();
gaurav25118892016-08-24 05:35:03 +0530223 if (!intfs.isEmpty()) {
224 processIntfFilters(false, intfs);
225 }
gaurava2e61a52016-05-05 03:39:31 +0530226 }
227
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800228 private void updateConfig() {
229 RouterConfig routerConfig =
230 networkConfigService.getConfig(routerAppId, RoutingService.ROUTER_CONFIG_CLASS);
Jonathan Hartdf207092015-12-10 11:19:25 -0800231
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800232 if (routerConfig == null) {
233 log.info("Router config not available");
Jonathan Hartdf207092015-12-10 11:19:25 -0800234 return;
235 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800236 controlPlaneConnectPoint = routerConfig.getControlPlaneConnectPoint();
237 log.info("Control Plane Connect Point: {}", controlPlaneConnectPoint);
Jonathan Hartdf207092015-12-10 11:19:25 -0800238
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800239 deviceId = routerConfig.getControlPlaneConnectPoint().deviceId();
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800240 log.info("Router device ID is {}", deviceId);
241
Jonathan Hart883fd372016-02-10 14:36:15 -0800242 interfaces = routerConfig.getInterfaces();
243 log.info("Using interfaces: {}", interfaces.isEmpty() ? "all" : interfaces);
244
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700245 routeService.addListener(routeListener);
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800246 updateDevice();
247 }
248
gaurav25118892016-08-24 05:35:03 +0530249 //remove the filtering objective for interfaces which are no longer part of vRouter config.
250 private void removeFilteringObjectives(NetworkConfigEvent event) {
251 RouterConfig prevRouterConfig = (RouterConfig) event.prevConfig().get();
252 List<String> prevInterfaces = prevRouterConfig.getInterfaces();
253
254 Set<Interface> previntfs = filterInterfaces(prevInterfaces);
255 //if previous interface list is empty it means filtering objectives are
256 //installed for all the interfaces.
257 if (previntfs.isEmpty() && !interfaces.isEmpty()) {
258 Set<Interface> allIntfs = interfaceService.getInterfaces();
259 for (Interface allIntf : allIntfs) {
260 if (!interfaces.contains(allIntf.name())) {
261 processIntfFilter(false, allIntf);
262 }
263 }
264 return;
265 }
266
267 //remove the filtering objective for the interfaces which are not
268 //part of updated interfaces list.
269 for (Interface prevIntf : previntfs) {
270 if (!interfaces.contains(prevIntf.name())) {
271 processIntfFilter(false, prevIntf);
272 }
273 }
274 }
275
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800276 private void updateDevice() {
277 if (deviceId != null && deviceService.isAvailable(deviceId)) {
gaurava2e61a52016-05-05 03:39:31 +0530278 Set<Interface> intfs = getInterfaces();
Jonathan Hart883fd372016-02-10 14:36:15 -0800279 processIntfFilters(true, intfs);
Jonathan Hartdf207092015-12-10 11:19:25 -0800280 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800281 }
282
gaurava2e61a52016-05-05 03:39:31 +0530283 private Set<Interface> getInterfaces() {
284 Set<Interface> intfs;
285 if (interfaces.isEmpty()) {
286 intfs = interfaceService.getInterfaces();
287 } else {
288 // TODO need to fix by making interface names globally unique
gaurav25118892016-08-24 05:35:03 +0530289 intfs = filterInterfaces(interfaces);
gaurava2e61a52016-05-05 03:39:31 +0530290 }
291 return intfs;
292 }
293
gaurav25118892016-08-24 05:35:03 +0530294 private Set<Interface> filterInterfaces(List<String> interfaces) {
295 Set<Interface> intfs = interfaceService.getInterfaces().stream()
296 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
297 .filter(intf -> interfaces.contains(intf.name()))
298 .collect(Collectors.toSet());
299 return intfs;
300 }
301
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700302 private void updateRoute(ResolvedRoute route) {
303 addNextHop(route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800304
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700305 Integer nextId;
306 synchronized (this) {
307 nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800308 }
309
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700310 flowObjectiveService.forward(deviceId,
311 generateRibForwardingObj(route.prefix(), nextId).add());
312 log.trace("Sending forwarding objective {} -> nextId:{}", route, nextId);
Jonathan Hartdf207092015-12-10 11:19:25 -0800313 }
314
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700315 private synchronized void deleteRoute(ResolvedRoute route) {
316 //Integer nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800317
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700318 /* Group group = deleteNextHop(route.prefix());
319 if (group == null) {
320 log.warn("Group not found when deleting {}", route);
321 return;
322 }*/
Jonathan Hartdf207092015-12-10 11:19:25 -0800323
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700324 flowObjectiveService.forward(deviceId,
325 generateRibForwardingObj(route.prefix(), null).remove());
Jonathan Hartdf207092015-12-10 11:19:25 -0800326 }
327
328 private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
329 Integer nextId) {
330 TrafficSelector selector = DefaultTrafficSelector.builder()
331 .matchEthType(Ethernet.TYPE_IPV4)
332 .matchIPDst(prefix)
333 .build();
334
335 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
336
337 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
Saurav Das49cb5a12016-01-16 22:54:07 -0800338 .fromApp(routerAppId)
Jonathan Hartdf207092015-12-10 11:19:25 -0800339 .makePermanent()
340 .withSelector(selector)
341 .withPriority(priority)
342 .withFlag(ForwardingObjective.Flag.SPECIFIC);
343
344 if (nextId == null) {
345 // Route withdraws are not specified with next hops. Generating
346 // dummy treatment as there is no equivalent nextId info.
347 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
348 } else {
349 fwdBuilder.nextStep(nextId);
350 }
351 return fwdBuilder;
352 }
353
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700354 private synchronized void addNextHop(ResolvedRoute route) {
355 prefixToNextHop.put(route.prefix(), route.nextHop());
356 if (nextHopsCount.count(route.nextHop()) == 0) {
Jonathan Hartdf207092015-12-10 11:19:25 -0800357 // There was no next hop in the multiset
358
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700359 Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800360 if (egressIntf == null) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700361 log.warn("no egress interface found for {}", route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800362 return;
363 }
364
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700365 NextHopGroupKey groupKey = new NextHopGroupKey(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800366
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700367 NextHop nextHop = new NextHop(route.nextHop(), route.nextHopMac(), groupKey);
Jonathan Hartdf207092015-12-10 11:19:25 -0800368
Jonathan Hartca47cd72015-12-13 12:31:09 -0800369 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800370 .setEthSrc(egressIntf.mac())
Jonathan Hartca47cd72015-12-13 12:31:09 -0800371 .setEthDst(nextHop.mac());
372
Saurav Das49cb5a12016-01-16 22:54:07 -0800373 TrafficSelector.Builder metabuilder = null;
Jonathan Hartca47cd72015-12-13 12:31:09 -0800374 if (!egressIntf.vlan().equals(VlanId.NONE)) {
375 treatment.pushVlan()
376 .setVlanId(egressIntf.vlan())
377 .setVlanPcp((byte) 0);
Saurav Das49cb5a12016-01-16 22:54:07 -0800378 } else {
379 // untagged outgoing port may require internal vlan in some pipelines
380 metabuilder = DefaultTrafficSelector.builder();
381 metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
Jonathan Hartca47cd72015-12-13 12:31:09 -0800382 }
383
384 treatment.setOutput(egressIntf.connectPoint().port());
Jonathan Hartdf207092015-12-10 11:19:25 -0800385
386 int nextId = flowObjectiveService.allocateNextId();
Saurav Das49cb5a12016-01-16 22:54:07 -0800387 NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800388 .withId(nextId)
Jonathan Hartca47cd72015-12-13 12:31:09 -0800389 .addTreatment(treatment.build())
Jonathan Hartdf207092015-12-10 11:19:25 -0800390 .withType(NextObjective.Type.SIMPLE)
Saurav Das49cb5a12016-01-16 22:54:07 -0800391 .fromApp(routerAppId);
392 if (metabuilder != null) {
393 nextBuilder.withMeta(metabuilder.build());
394 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800395
Saurav Das49cb5a12016-01-16 22:54:07 -0800396 NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
Jonathan Hartdf207092015-12-10 11:19:25 -0800397 flowObjectiveService.next(deviceId, nextObjective);
398
399 nextHops.put(nextHop.ip(), nextId);
400
Jonathan Hartb9401902016-02-02 18:46:01 -0800401 if (routeToNextHop) {
402 // Install route to next hop
403 ForwardingObjective fob =
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700404 generateRibForwardingObj(IpPrefix.valueOf(route.nextHop(), 32), nextId).add();
Jonathan Hartb9401902016-02-02 18:46:01 -0800405 flowObjectiveService.forward(deviceId, fob);
406 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800407 }
408
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700409 nextHopsCount.add(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800410 }
411
412 /*private synchronized Group deleteNextHop(IpPrefix prefix) {
413 IpAddress nextHopIp = prefixToNextHop.remove(prefix);
414 NextHop nextHop = nextHops.get(nextHopIp);
415 if (nextHop == null) {
416 log.warn("No next hop found when removing prefix {}", prefix);
417 return null;
418 }
419
420 Group group = groupService.getGroup(deviceId,
421 new DefaultGroupKey(appKryo.
422 serialize(nextHop.group())));
423
424 // FIXME disabling group deletes for now until we verify the logic is OK
425 if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
426 // There was one or less next hops, so there are now none
427
428 log.debug("removing group for next hop {}", nextHop);
429
430 nextHops.remove(nextHopIp);
431
432 groupService.removeGroup(deviceId,
433 new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
434 appId);
435 }
436
437 return group;
438 }*/
439
440 private void processIntfFilters(boolean install, Set<Interface> intfs) {
441 log.info("Processing {} router interfaces", intfs.size());
442 for (Interface intf : intfs) {
443 if (!intf.connectPoint().deviceId().equals(deviceId)) {
444 // Ignore interfaces if they are not on the router switch
445 continue;
446 }
447
gaurav164cf6d2016-03-25 21:43:04 +0530448 createFilteringObjective(install, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700449 createMcastFilteringObjective(install, intf);
gaurav164cf6d2016-03-25 21:43:04 +0530450 }
451 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800452
gaurav164cf6d2016-03-25 21:43:04 +0530453 //process filtering objective for interface add/remove.
454 private void processIntfFilter(boolean install, Interface intf) {
455
456 if (!intf.connectPoint().deviceId().equals(deviceId)) {
457 // Ignore interfaces if they are not on the router switch
458 return;
459 }
gaurav25118892016-08-24 05:35:03 +0530460 if (!interfaces.contains(intf.name()) && install) {
461 return;
462 }
gaurav164cf6d2016-03-25 21:43:04 +0530463
464 createFilteringObjective(install, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700465 createMcastFilteringObjective(install, intf);
gaurav164cf6d2016-03-25 21:43:04 +0530466 }
467
468 //create filtering objective for interface
469 private void createFilteringObjective(boolean install, Interface intf) {
Charles Chand55e84d2016-03-30 17:54:24 -0700470 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
471 VlanId.vlanId(ASSIGNED_VLAN) :
472 egressVlan();
gaurav164cf6d2016-03-25 21:43:04 +0530473
474 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
475 // first add filter for the interface
476 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
477 .addCondition(Criteria.matchEthDst(intf.mac()))
478 .addCondition(Criteria.matchVlanId(intf.vlan()));
479 fob.withPriority(PRIORITY_OFFSET);
480 if (intf.vlan() == VlanId.NONE) {
481 TrafficTreatment tt = DefaultTrafficTreatment.builder()
Charles Chand55e84d2016-03-30 17:54:24 -0700482 .pushVlan().setVlanId(assignedVlan).build();
gaurav164cf6d2016-03-25 21:43:04 +0530483 fob.withMeta(tt);
484 }
gaurav164cf6d2016-03-25 21:43:04 +0530485 fob.permit().fromApp(routerAppId);
486 sendFilteringObjective(install, fob, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700487
gaurav164cf6d2016-03-25 21:43:04 +0530488 if (controlPlaneConnectPoint != null) {
489 // then add the same mac/vlan filters for control-plane connect point
490 fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port()));
Saurav Das49cb5a12016-01-16 22:54:07 -0800491 sendFilteringObjective(install, fob, intf);
Jonathan Hartdf207092015-12-10 11:19:25 -0800492 }
493 }
494
Charles Chand55e84d2016-03-30 17:54:24 -0700495 //create filtering objective for multicast traffic
496 private void createMcastFilteringObjective(boolean install, Interface intf) {
497 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
498 VlanId.vlanId(ASSIGNED_VLAN) :
499 egressVlan();
500
501 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
502 // first add filter for the interface
503 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
504 .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
505 MacAddress.IPV4_MULTICAST_MASK))
506 .addCondition(Criteria.matchVlanId(ingressVlan()));
507 fob.withPriority(PRIORITY_OFFSET);
508 TrafficTreatment tt = DefaultTrafficTreatment.builder()
509 .pushVlan().setVlanId(assignedVlan).build();
510 fob.withMeta(tt);
511
512 fob.permit().fromApp(routerAppId);
513 sendFilteringObjective(install, fob, intf);
514 }
515
Saurav Das49cb5a12016-01-16 22:54:07 -0800516 private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
517 Interface intf) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800518
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700519 ObjectiveContext context = new DefaultObjectiveContext(
520 (objective) -> log.info("Installed filter for interface {}", intf),
521 (objective, error) ->
522 log.error("Failed to install filter for interface {}: {}", intf, error));
gaurav164cf6d2016-03-25 21:43:04 +0530523
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700524 FilteringObjective filter = install ? fob.add(context) : fob.remove(context);
525
526 flowObjectiveService.filter(deviceId, filter);
Saurav Das49cb5a12016-01-16 22:54:07 -0800527 }
528
Charles Chand55e84d2016-03-30 17:54:24 -0700529 private VlanId ingressVlan() {
530 McastConfig mcastConfig =
531 networkConfigService.getConfig(coreAppId, McastConfig.class);
532 return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
533 }
534
535 private VlanId egressVlan() {
536 McastConfig mcastConfig =
537 networkConfigService.getConfig(coreAppId, McastConfig.class);
538 return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
539 }
540
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700541 private class InternalRouteListener implements RouteListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800542 @Override
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700543 public void event(RouteEvent event) {
544 ResolvedRoute route = event.subject();
545 switch (event.type()) {
546 case ROUTE_ADDED:
547 case ROUTE_UPDATED:
548 updateRoute(route);
549 break;
550 case ROUTE_REMOVED:
551 deleteRoute(route);
552 break;
553 default:
554 break;
555 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800556 }
557 }
558
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800559 /**
560 * Listener for device events used to trigger driver setup when a device is
561 * (re)detected.
562 */
563 private class InternalDeviceListener implements DeviceListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800564 @Override
565 public void event(DeviceEvent event) {
566 switch (event.type()) {
567 case DEVICE_ADDED:
568 case DEVICE_AVAILABILITY_CHANGED:
569 if (deviceService.isAvailable(event.subject().id())) {
570 log.info("Device connected {}", event.subject().id());
571 if (event.subject().id().equals(deviceId)) {
Charles Chanf555a732016-02-15 15:37:15 -0800572 updateDevice();
Jonathan Hartdf207092015-12-10 11:19:25 -0800573 }
574 }
575 break;
576 // TODO other cases
577 case DEVICE_UPDATED:
578 case DEVICE_REMOVED:
579 case DEVICE_SUSPENDED:
580 case PORT_ADDED:
581 case PORT_UPDATED:
582 case PORT_REMOVED:
583 default:
584 break;
585 }
586 }
587 }
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800588
589 /**
590 * Listener for network config events.
591 */
592 private class InternalNetworkConfigListener implements NetworkConfigListener {
593 @Override
594 public void event(NetworkConfigEvent event) {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700595 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800596 switch (event.type()) {
597 case CONFIG_ADDED:
598 case CONFIG_UPDATED:
599 updateConfig();
gaurav25118892016-08-24 05:35:03 +0530600 if (event.prevConfig().isPresent()) {
601 removeFilteringObjectives(event);
602 }
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800603 break;
604 case CONFIG_REGISTERED:
gaurav25118892016-08-24 05:35:03 +0530605 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800606 case CONFIG_UNREGISTERED:
gaurav25118892016-08-24 05:35:03 +0530607 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800608 case CONFIG_REMOVED:
gaurav25118892016-08-24 05:35:03 +0530609 cleanUp();
610 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800611 default:
612 break;
613 }
614 }
615 }
616 }
gaurav164cf6d2016-03-25 21:43:04 +0530617
618 private class InternalInterfaceListener implements InterfaceListener {
gaurav164cf6d2016-03-25 21:43:04 +0530619 @Override
620 public void event(InterfaceEvent event) {
621 Interface intf = event.subject();
622 switch (event.type()) {
623 case INTERFACE_ADDED:
624 if (intf != null) {
625 processIntfFilter(true, intf);
626 }
627 break;
628 case INTERFACE_UPDATED:
629 break;
630 case INTERFACE_REMOVED:
631 if (intf != null) {
632 processIntfFilter(false, intf);
633 }
634 break;
635 default:
636 break;
637 }
638 }
639 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800640}