blob: 33e4bd7c2a239ada401dca24a63080ec76153fd2 [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
gaurava2e61a52016-05-05 03:39:31 +0530181 applicationService.registerDeactivateHook(vrouterAppId, () -> {
182 this.cleanUp();
183 });
184
Jonathan Hartdf207092015-12-10 11:19:25 -0800185 log.info("Started");
186 }
187
188 @Deactivate
189 protected void deactivate() {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700190 routeService.removeListener(routeListener);
Jonathan Hartdf207092015-12-10 11:19:25 -0800191 deviceService.removeListener(deviceListener);
gaurav164cf6d2016-03-25 21:43:04 +0530192 interfaceService.removeListener(internalInterfaceList);
Jonathan Hart25bd6682016-06-03 10:45:47 -0700193 networkConfigService.removeListener(configListener);
gaurav164cf6d2016-03-25 21:43:04 +0530194
Jonathan Hartdf207092015-12-10 11:19:25 -0800195 //processIntfFilters(false, configService.getInterfaces()); //TODO necessary?
196
Jonathan Hartb9401902016-02-02 18:46:01 -0800197 componentConfigService.unregisterProperties(getClass(), false);
198
Jonathan Hartdf207092015-12-10 11:19:25 -0800199 log.info("Stopped");
200 }
201
Jonathan Hartb9401902016-02-02 18:46:01 -0800202 @Modified
203 protected void modified(ComponentContext context) {
204 Dictionary<?, ?> properties = context.getProperties();
205 if (properties == null) {
206 return;
207 }
208
209 String strRouteToNextHop = Tools.get(properties, "routeToNextHop");
210 routeToNextHop = Boolean.parseBoolean(strRouteToNextHop);
211
212 log.info("routeToNextHop set to {}", routeToNextHop);
213 }
214
gaurava2e61a52016-05-05 03:39:31 +0530215 //remove filtering objectives and routes before deactivate.
216 private void cleanUp() {
217 //clean up the routes.
218 for (Map.Entry<IpPrefix, IpAddress> routes: prefixToNextHop.entrySet()) {
219 deleteRoute(new ResolvedRoute(routes.getKey(), null, null));
220 }
221 //clean up the filtering objective for interfaces.
222 Set<Interface> intfs = getInterfaces();
223 processIntfFilters(false, intfs);
224 }
225
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800226 private void updateConfig() {
227 RouterConfig routerConfig =
228 networkConfigService.getConfig(routerAppId, RoutingService.ROUTER_CONFIG_CLASS);
Jonathan Hartdf207092015-12-10 11:19:25 -0800229
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800230 if (routerConfig == null) {
231 log.info("Router config not available");
Jonathan Hartdf207092015-12-10 11:19:25 -0800232 return;
233 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800234 controlPlaneConnectPoint = routerConfig.getControlPlaneConnectPoint();
235 log.info("Control Plane Connect Point: {}", controlPlaneConnectPoint);
Jonathan Hartdf207092015-12-10 11:19:25 -0800236
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800237 deviceId = routerConfig.getControlPlaneConnectPoint().deviceId();
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800238 log.info("Router device ID is {}", deviceId);
239
Jonathan Hart883fd372016-02-10 14:36:15 -0800240 interfaces = routerConfig.getInterfaces();
241 log.info("Using interfaces: {}", interfaces.isEmpty() ? "all" : interfaces);
242
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700243 routeService.addListener(routeListener);
244
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800245 updateDevice();
246 }
247
248 private void updateDevice() {
249 if (deviceId != null && deviceService.isAvailable(deviceId)) {
gaurava2e61a52016-05-05 03:39:31 +0530250 Set<Interface> intfs = getInterfaces();
Jonathan Hart883fd372016-02-10 14:36:15 -0800251 processIntfFilters(true, intfs);
Jonathan Hartdf207092015-12-10 11:19:25 -0800252 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800253 }
254
gaurava2e61a52016-05-05 03:39:31 +0530255 private Set<Interface> getInterfaces() {
256 Set<Interface> intfs;
257 if (interfaces.isEmpty()) {
258 intfs = interfaceService.getInterfaces();
259 } else {
260 // TODO need to fix by making interface names globally unique
261 intfs = interfaceService.getInterfaces().stream()
262 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
263 .filter(intf -> interfaces.contains(intf.name()))
264 .collect(Collectors.toSet());
265 }
266 return intfs;
267 }
268
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700269 private void updateRoute(ResolvedRoute route) {
270 addNextHop(route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800271
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700272 Integer nextId;
273 synchronized (this) {
274 nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800275 }
276
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700277 flowObjectiveService.forward(deviceId,
278 generateRibForwardingObj(route.prefix(), nextId).add());
279 log.trace("Sending forwarding objective {} -> nextId:{}", route, nextId);
Jonathan Hartdf207092015-12-10 11:19:25 -0800280 }
281
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700282 private synchronized void deleteRoute(ResolvedRoute route) {
283 //Integer nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800284
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700285 /* Group group = deleteNextHop(route.prefix());
286 if (group == null) {
287 log.warn("Group not found when deleting {}", route);
288 return;
289 }*/
Jonathan Hartdf207092015-12-10 11:19:25 -0800290
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700291 flowObjectiveService.forward(deviceId,
292 generateRibForwardingObj(route.prefix(), null).remove());
Jonathan Hartdf207092015-12-10 11:19:25 -0800293 }
294
295 private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
296 Integer nextId) {
297 TrafficSelector selector = DefaultTrafficSelector.builder()
298 .matchEthType(Ethernet.TYPE_IPV4)
299 .matchIPDst(prefix)
300 .build();
301
302 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
303
304 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
Saurav Das49cb5a12016-01-16 22:54:07 -0800305 .fromApp(routerAppId)
Jonathan Hartdf207092015-12-10 11:19:25 -0800306 .makePermanent()
307 .withSelector(selector)
308 .withPriority(priority)
309 .withFlag(ForwardingObjective.Flag.SPECIFIC);
310
311 if (nextId == null) {
312 // Route withdraws are not specified with next hops. Generating
313 // dummy treatment as there is no equivalent nextId info.
314 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
315 } else {
316 fwdBuilder.nextStep(nextId);
317 }
318 return fwdBuilder;
319 }
320
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700321 private synchronized void addNextHop(ResolvedRoute route) {
322 prefixToNextHop.put(route.prefix(), route.nextHop());
323 if (nextHopsCount.count(route.nextHop()) == 0) {
Jonathan Hartdf207092015-12-10 11:19:25 -0800324 // There was no next hop in the multiset
325
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700326 Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800327 if (egressIntf == null) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700328 log.warn("no egress interface found for {}", route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800329 return;
330 }
331
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700332 NextHopGroupKey groupKey = new NextHopGroupKey(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800333
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700334 NextHop nextHop = new NextHop(route.nextHop(), route.nextHopMac(), groupKey);
Jonathan Hartdf207092015-12-10 11:19:25 -0800335
Jonathan Hartca47cd72015-12-13 12:31:09 -0800336 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800337 .setEthSrc(egressIntf.mac())
Jonathan Hartca47cd72015-12-13 12:31:09 -0800338 .setEthDst(nextHop.mac());
339
Saurav Das49cb5a12016-01-16 22:54:07 -0800340 TrafficSelector.Builder metabuilder = null;
Jonathan Hartca47cd72015-12-13 12:31:09 -0800341 if (!egressIntf.vlan().equals(VlanId.NONE)) {
342 treatment.pushVlan()
343 .setVlanId(egressIntf.vlan())
344 .setVlanPcp((byte) 0);
Saurav Das49cb5a12016-01-16 22:54:07 -0800345 } else {
346 // untagged outgoing port may require internal vlan in some pipelines
347 metabuilder = DefaultTrafficSelector.builder();
348 metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
Jonathan Hartca47cd72015-12-13 12:31:09 -0800349 }
350
351 treatment.setOutput(egressIntf.connectPoint().port());
Jonathan Hartdf207092015-12-10 11:19:25 -0800352
353 int nextId = flowObjectiveService.allocateNextId();
Saurav Das49cb5a12016-01-16 22:54:07 -0800354 NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800355 .withId(nextId)
Jonathan Hartca47cd72015-12-13 12:31:09 -0800356 .addTreatment(treatment.build())
Jonathan Hartdf207092015-12-10 11:19:25 -0800357 .withType(NextObjective.Type.SIMPLE)
Saurav Das49cb5a12016-01-16 22:54:07 -0800358 .fromApp(routerAppId);
359 if (metabuilder != null) {
360 nextBuilder.withMeta(metabuilder.build());
361 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800362
Saurav Das49cb5a12016-01-16 22:54:07 -0800363 NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
Jonathan Hartdf207092015-12-10 11:19:25 -0800364 flowObjectiveService.next(deviceId, nextObjective);
365
366 nextHops.put(nextHop.ip(), nextId);
367
Jonathan Hartb9401902016-02-02 18:46:01 -0800368 if (routeToNextHop) {
369 // Install route to next hop
370 ForwardingObjective fob =
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700371 generateRibForwardingObj(IpPrefix.valueOf(route.nextHop(), 32), nextId).add();
Jonathan Hartb9401902016-02-02 18:46:01 -0800372 flowObjectiveService.forward(deviceId, fob);
373 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800374 }
375
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700376 nextHopsCount.add(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800377 }
378
379 /*private synchronized Group deleteNextHop(IpPrefix prefix) {
380 IpAddress nextHopIp = prefixToNextHop.remove(prefix);
381 NextHop nextHop = nextHops.get(nextHopIp);
382 if (nextHop == null) {
383 log.warn("No next hop found when removing prefix {}", prefix);
384 return null;
385 }
386
387 Group group = groupService.getGroup(deviceId,
388 new DefaultGroupKey(appKryo.
389 serialize(nextHop.group())));
390
391 // FIXME disabling group deletes for now until we verify the logic is OK
392 if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
393 // There was one or less next hops, so there are now none
394
395 log.debug("removing group for next hop {}", nextHop);
396
397 nextHops.remove(nextHopIp);
398
399 groupService.removeGroup(deviceId,
400 new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
401 appId);
402 }
403
404 return group;
405 }*/
406
407 private void processIntfFilters(boolean install, Set<Interface> intfs) {
408 log.info("Processing {} router interfaces", intfs.size());
409 for (Interface intf : intfs) {
410 if (!intf.connectPoint().deviceId().equals(deviceId)) {
411 // Ignore interfaces if they are not on the router switch
412 continue;
413 }
414
gaurav164cf6d2016-03-25 21:43:04 +0530415 createFilteringObjective(install, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700416 createMcastFilteringObjective(install, intf);
gaurav164cf6d2016-03-25 21:43:04 +0530417 }
418 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800419
gaurav164cf6d2016-03-25 21:43:04 +0530420 //process filtering objective for interface add/remove.
421 private void processIntfFilter(boolean install, Interface intf) {
422
423 if (!intf.connectPoint().deviceId().equals(deviceId)) {
424 // Ignore interfaces if they are not on the router switch
425 return;
426 }
427
428 createFilteringObjective(install, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700429 createMcastFilteringObjective(install, intf);
gaurav164cf6d2016-03-25 21:43:04 +0530430 }
431
432 //create filtering objective for interface
433 private void createFilteringObjective(boolean install, Interface intf) {
Charles Chand55e84d2016-03-30 17:54:24 -0700434 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
435 VlanId.vlanId(ASSIGNED_VLAN) :
436 egressVlan();
gaurav164cf6d2016-03-25 21:43:04 +0530437
438 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
439 // first add filter for the interface
440 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
441 .addCondition(Criteria.matchEthDst(intf.mac()))
442 .addCondition(Criteria.matchVlanId(intf.vlan()));
443 fob.withPriority(PRIORITY_OFFSET);
444 if (intf.vlan() == VlanId.NONE) {
445 TrafficTreatment tt = DefaultTrafficTreatment.builder()
Charles Chand55e84d2016-03-30 17:54:24 -0700446 .pushVlan().setVlanId(assignedVlan).build();
gaurav164cf6d2016-03-25 21:43:04 +0530447 fob.withMeta(tt);
448 }
gaurav164cf6d2016-03-25 21:43:04 +0530449 fob.permit().fromApp(routerAppId);
450 sendFilteringObjective(install, fob, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700451
gaurav164cf6d2016-03-25 21:43:04 +0530452 if (controlPlaneConnectPoint != null) {
453 // then add the same mac/vlan filters for control-plane connect point
454 fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port()));
Saurav Das49cb5a12016-01-16 22:54:07 -0800455 sendFilteringObjective(install, fob, intf);
Jonathan Hartdf207092015-12-10 11:19:25 -0800456 }
457 }
458
Charles Chand55e84d2016-03-30 17:54:24 -0700459 //create filtering objective for multicast traffic
460 private void createMcastFilteringObjective(boolean install, Interface intf) {
461 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
462 VlanId.vlanId(ASSIGNED_VLAN) :
463 egressVlan();
464
465 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
466 // first add filter for the interface
467 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
468 .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
469 MacAddress.IPV4_MULTICAST_MASK))
470 .addCondition(Criteria.matchVlanId(ingressVlan()));
471 fob.withPriority(PRIORITY_OFFSET);
472 TrafficTreatment tt = DefaultTrafficTreatment.builder()
473 .pushVlan().setVlanId(assignedVlan).build();
474 fob.withMeta(tt);
475
476 fob.permit().fromApp(routerAppId);
477 sendFilteringObjective(install, fob, intf);
478 }
479
Saurav Das49cb5a12016-01-16 22:54:07 -0800480 private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
481 Interface intf) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800482
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700483 ObjectiveContext context = new DefaultObjectiveContext(
484 (objective) -> log.info("Installed filter for interface {}", intf),
485 (objective, error) ->
486 log.error("Failed to install filter for interface {}: {}", intf, error));
gaurav164cf6d2016-03-25 21:43:04 +0530487
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700488 FilteringObjective filter = install ? fob.add(context) : fob.remove(context);
489
490 flowObjectiveService.filter(deviceId, filter);
Saurav Das49cb5a12016-01-16 22:54:07 -0800491 }
492
Charles Chand55e84d2016-03-30 17:54:24 -0700493 private VlanId ingressVlan() {
494 McastConfig mcastConfig =
495 networkConfigService.getConfig(coreAppId, McastConfig.class);
496 return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
497 }
498
499 private VlanId egressVlan() {
500 McastConfig mcastConfig =
501 networkConfigService.getConfig(coreAppId, McastConfig.class);
502 return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
503 }
504
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700505 private class InternalRouteListener implements RouteListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800506 @Override
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700507 public void event(RouteEvent event) {
508 ResolvedRoute route = event.subject();
509 switch (event.type()) {
510 case ROUTE_ADDED:
511 case ROUTE_UPDATED:
512 updateRoute(route);
513 break;
514 case ROUTE_REMOVED:
515 deleteRoute(route);
516 break;
517 default:
518 break;
519 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800520 }
521 }
522
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800523 /**
524 * Listener for device events used to trigger driver setup when a device is
525 * (re)detected.
526 */
527 private class InternalDeviceListener implements DeviceListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800528 @Override
529 public void event(DeviceEvent event) {
530 switch (event.type()) {
531 case DEVICE_ADDED:
532 case DEVICE_AVAILABILITY_CHANGED:
533 if (deviceService.isAvailable(event.subject().id())) {
534 log.info("Device connected {}", event.subject().id());
535 if (event.subject().id().equals(deviceId)) {
Charles Chanf555a732016-02-15 15:37:15 -0800536 updateDevice();
Jonathan Hartdf207092015-12-10 11:19:25 -0800537 }
538 }
539 break;
540 // TODO other cases
541 case DEVICE_UPDATED:
542 case DEVICE_REMOVED:
543 case DEVICE_SUSPENDED:
544 case PORT_ADDED:
545 case PORT_UPDATED:
546 case PORT_REMOVED:
547 default:
548 break;
549 }
550 }
551 }
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800552
553 /**
554 * Listener for network config events.
555 */
556 private class InternalNetworkConfigListener implements NetworkConfigListener {
557 @Override
558 public void event(NetworkConfigEvent event) {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700559 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800560 switch (event.type()) {
561 case CONFIG_ADDED:
562 case CONFIG_UPDATED:
563 updateConfig();
564 break;
565 case CONFIG_REGISTERED:
566 case CONFIG_UNREGISTERED:
567 case CONFIG_REMOVED:
568 default:
569 break;
570 }
571 }
572 }
573 }
gaurav164cf6d2016-03-25 21:43:04 +0530574
575 private class InternalInterfaceListener implements InterfaceListener {
gaurav164cf6d2016-03-25 21:43:04 +0530576 @Override
577 public void event(InterfaceEvent event) {
578 Interface intf = event.subject();
579 switch (event.type()) {
580 case INTERFACE_ADDED:
581 if (intf != null) {
582 processIntfFilter(true, intf);
583 }
584 break;
585 case INTERFACE_UPDATED:
586 break;
587 case INTERFACE_REMOVED:
588 if (intf != null) {
589 processIntfFilter(false, intf);
590 }
591 break;
592 default:
593 break;
594 }
595 }
596 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800597}