blob: f0649b9e97be13d1152e601e1287c7815cf42cb8 [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;
35import org.onosproject.cfg.ComponentConfigService;
Jonathan Hartdf207092015-12-10 11:19:25 -080036import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
Charles Chand55e84d2016-03-30 17:54:24 -070038import org.onosproject.incubator.net.config.basics.McastConfig;
Jonathan Hartdf207092015-12-10 11:19:25 -080039import org.onosproject.incubator.net.intf.Interface;
gaurav164cf6d2016-03-25 21:43:04 +053040import org.onosproject.incubator.net.intf.InterfaceEvent;
41import org.onosproject.incubator.net.intf.InterfaceListener;
Jonathan Hartdf207092015-12-10 11:19:25 -080042import 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.DeviceEvent;
56import org.onosproject.net.device.DeviceListener;
57import org.onosproject.net.device.DeviceService;
58import org.onosproject.net.flow.DefaultTrafficSelector;
59import org.onosproject.net.flow.DefaultTrafficTreatment;
60import org.onosproject.net.flow.TrafficSelector;
61import org.onosproject.net.flow.TrafficTreatment;
62import org.onosproject.net.flow.criteria.Criteria;
63import org.onosproject.net.flowobjective.DefaultFilteringObjective;
64import org.onosproject.net.flowobjective.DefaultForwardingObjective;
65import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070066import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080067import org.onosproject.net.flowobjective.FilteringObjective;
68import org.onosproject.net.flowobjective.FlowObjectiveService;
69import org.onosproject.net.flowobjective.ForwardingObjective;
70import org.onosproject.net.flowobjective.NextObjective;
Jonathan Hartdf207092015-12-10 11:19:25 -080071import org.onosproject.net.flowobjective.ObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080072import org.onosproject.routing.RoutingService;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -080073import org.onosproject.routing.config.RouterConfig;
Jonathan Hartb9401902016-02-02 18:46:01 -080074import org.osgi.service.component.ComponentContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080075import org.slf4j.Logger;
76import org.slf4j.LoggerFactory;
77
Jonathan Hartb9401902016-02-02 18:46:01 -080078import java.util.Dictionary;
Jonathan Hart883fd372016-02-10 14:36:15 -080079import java.util.List;
Jonathan Hartdf207092015-12-10 11:19:25 -080080import java.util.Map;
Jonathan Hartdf207092015-12-10 11:19:25 -080081import java.util.Set;
Jonathan Hart883fd372016-02-10 14:36:15 -080082import java.util.stream.Collectors;
Jonathan Hartdf207092015-12-10 11:19:25 -080083
84/**
85 * Programs routes to a single OpenFlow switch.
86 */
Jonathan Hartc22e8472015-11-17 18:25:45 -080087@Component(immediate = true, enabled = false)
88public class SingleSwitchFibInstaller {
Jonathan Hartdf207092015-12-10 11:19:25 -080089
90 private final Logger log = LoggerFactory.getLogger(getClass());
91
92 private static final int PRIORITY_OFFSET = 100;
93 private static final int PRIORITY_MULTIPLIER = 5;
94
Saurav Das49cb5a12016-01-16 22:54:07 -080095 public static final short ASSIGNED_VLAN = 4094;
96
Jonathan Hartdf207092015-12-10 11:19:25 -080097 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected CoreService coreService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700101 protected RouteService routeService;
Jonathan Hartdf207092015-12-10 11:19:25 -0800102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected InterfaceService interfaceService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected NetworkConfigService networkConfigService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chand55e84d2016-03-30 17:54:24 -0700110 protected NetworkConfigRegistry networkConfigRegistry;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartb9401902016-02-02 18:46:01 -0800113 protected ComponentConfigService componentConfigService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800116 protected FlowObjectiveService flowObjectiveService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected DeviceService deviceService;
120
Jonathan Hartb9401902016-02-02 18:46:01 -0800121 @Property(name = "routeToNextHop", boolValue = false,
122 label = "Install a /32 route to each next hop")
123 private boolean routeToNextHop = false;
124
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800125 private InternalDeviceListener deviceListener;
Jonathan Hartdf207092015-12-10 11:19:25 -0800126
127 // 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 Hart883fd372016-02-10 14:36:15 -0800132 private List<String> interfaces;
133
Charles Chand55e84d2016-03-30 17:54:24 -0700134 private ApplicationId coreAppId;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800135 private ApplicationId routerAppId;
Jonathan Hartdf207092015-12-10 11:19:25 -0800136
137 // Reference count for how many times a next hop is used by a route
138 private final Multiset<IpAddress> nextHopsCount = ConcurrentHashMultiset.create();
139
140 // Mapping from prefix to its current next hop
141 private final Map<IpPrefix, IpAddress> prefixToNextHop = Maps.newHashMap();
142
143 // Mapping from next hop IP to next hop object containing group info
144 private final Map<IpAddress, Integer> nextHops = Maps.newHashMap();
145
gaurav164cf6d2016-03-25 21:43:04 +0530146 //interface object for event
147 private InternalInterfaceListener internalInterfaceList = new InternalInterfaceListener();
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700148 private InternalRouteListener routeListener = new InternalRouteListener();
Jonathan Hartdf207092015-12-10 11:19:25 -0800149
Charles Chand55e84d2016-03-30 17:54:24 -0700150 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
151 new ConfigFactory<ApplicationId, McastConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
152 McastConfig.class, "multicast") {
153 @Override
154 public McastConfig createConfig() {
155 return new McastConfig();
156 }
157 };
158
Jonathan Hartdf207092015-12-10 11:19:25 -0800159 @Activate
Jonathan Hartb9401902016-02-02 18:46:01 -0800160 protected void activate(ComponentContext context) {
Jonathan Hartb9401902016-02-02 18:46:01 -0800161 componentConfigService.registerProperties(getClass());
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800162 modified(context);
163
Charles Chand55e84d2016-03-30 17:54:24 -0700164 coreAppId = coreService.registerApplication(CoreService.CORE_APP_NAME);
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800165 routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
Jonathan Hartb9401902016-02-02 18:46:01 -0800166
Charles Chand55e84d2016-03-30 17:54:24 -0700167 networkConfigRegistry.registerConfigFactory(mcastConfigFactory);
168
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800169 deviceListener = new InternalDeviceListener();
Jonathan Hartdf207092015-12-10 11:19:25 -0800170 deviceService.addListener(deviceListener);
171
gaurav164cf6d2016-03-25 21:43:04 +0530172 interfaceService.addListener(internalInterfaceList);
173
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800174 updateConfig();
Jonathan Hartdf207092015-12-10 11:19:25 -0800175
176 log.info("Started");
177 }
178
179 @Deactivate
180 protected void deactivate() {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700181 routeService.removeListener(routeListener);
Jonathan Hartdf207092015-12-10 11:19:25 -0800182 deviceService.removeListener(deviceListener);
gaurav164cf6d2016-03-25 21:43:04 +0530183 interfaceService.removeListener(internalInterfaceList);
184
Jonathan Hartdf207092015-12-10 11:19:25 -0800185 //processIntfFilters(false, configService.getInterfaces()); //TODO necessary?
186
Jonathan Hartb9401902016-02-02 18:46:01 -0800187 componentConfigService.unregisterProperties(getClass(), false);
188
Jonathan Hartdf207092015-12-10 11:19:25 -0800189 log.info("Stopped");
190 }
191
Jonathan Hartb9401902016-02-02 18:46:01 -0800192 @Modified
193 protected void modified(ComponentContext context) {
194 Dictionary<?, ?> properties = context.getProperties();
195 if (properties == null) {
196 return;
197 }
198
199 String strRouteToNextHop = Tools.get(properties, "routeToNextHop");
200 routeToNextHop = Boolean.parseBoolean(strRouteToNextHop);
201
202 log.info("routeToNextHop set to {}", routeToNextHop);
203 }
204
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800205 private void updateConfig() {
206 RouterConfig routerConfig =
207 networkConfigService.getConfig(routerAppId, RoutingService.ROUTER_CONFIG_CLASS);
Jonathan Hartdf207092015-12-10 11:19:25 -0800208
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800209 if (routerConfig == null) {
210 log.info("Router config not available");
Jonathan Hartdf207092015-12-10 11:19:25 -0800211 return;
212 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800213 controlPlaneConnectPoint = routerConfig.getControlPlaneConnectPoint();
214 log.info("Control Plane Connect Point: {}", controlPlaneConnectPoint);
Jonathan Hartdf207092015-12-10 11:19:25 -0800215
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800216 deviceId = routerConfig.getControlPlaneConnectPoint().deviceId();
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800217 log.info("Router device ID is {}", deviceId);
218
Jonathan Hart883fd372016-02-10 14:36:15 -0800219 interfaces = routerConfig.getInterfaces();
220 log.info("Using interfaces: {}", interfaces.isEmpty() ? "all" : interfaces);
221
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700222 routeService.addListener(routeListener);
223
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800224 updateDevice();
225 }
226
227 private void updateDevice() {
228 if (deviceId != null && deviceService.isAvailable(deviceId)) {
Jonathan Hart883fd372016-02-10 14:36:15 -0800229
230 Set<Interface> intfs;
231 if (interfaces.isEmpty()) {
232 intfs = interfaceService.getInterfaces();
233 } else {
234 // TODO need to fix by making interface names globally unique
235 intfs = interfaceService.getInterfaces().stream()
236 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
237 .filter(intf -> interfaces.contains(intf.name()))
238 .collect(Collectors.toSet());
239 }
240
241 processIntfFilters(true, intfs);
Jonathan Hartdf207092015-12-10 11:19:25 -0800242 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800243 }
244
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700245 private void updateRoute(ResolvedRoute route) {
246 addNextHop(route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800247
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700248 Integer nextId;
249 synchronized (this) {
250 nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800251 }
252
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700253 flowObjectiveService.forward(deviceId,
254 generateRibForwardingObj(route.prefix(), nextId).add());
255 log.trace("Sending forwarding objective {} -> nextId:{}", route, nextId);
Jonathan Hartdf207092015-12-10 11:19:25 -0800256 }
257
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700258 private synchronized void deleteRoute(ResolvedRoute route) {
259 //Integer nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800260
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700261 /* Group group = deleteNextHop(route.prefix());
262 if (group == null) {
263 log.warn("Group not found when deleting {}", route);
264 return;
265 }*/
Jonathan Hartdf207092015-12-10 11:19:25 -0800266
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700267 flowObjectiveService.forward(deviceId,
268 generateRibForwardingObj(route.prefix(), null).remove());
Jonathan Hartdf207092015-12-10 11:19:25 -0800269 }
270
271 private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
272 Integer nextId) {
273 TrafficSelector selector = DefaultTrafficSelector.builder()
274 .matchEthType(Ethernet.TYPE_IPV4)
275 .matchIPDst(prefix)
276 .build();
277
278 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
279
280 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
Saurav Das49cb5a12016-01-16 22:54:07 -0800281 .fromApp(routerAppId)
Jonathan Hartdf207092015-12-10 11:19:25 -0800282 .makePermanent()
283 .withSelector(selector)
284 .withPriority(priority)
285 .withFlag(ForwardingObjective.Flag.SPECIFIC);
286
287 if (nextId == null) {
288 // Route withdraws are not specified with next hops. Generating
289 // dummy treatment as there is no equivalent nextId info.
290 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
291 } else {
292 fwdBuilder.nextStep(nextId);
293 }
294 return fwdBuilder;
295 }
296
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700297 private synchronized void addNextHop(ResolvedRoute route) {
298 prefixToNextHop.put(route.prefix(), route.nextHop());
299 if (nextHopsCount.count(route.nextHop()) == 0) {
Jonathan Hartdf207092015-12-10 11:19:25 -0800300 // There was no next hop in the multiset
301
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700302 Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800303 if (egressIntf == null) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700304 log.warn("no egress interface found for {}", route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800305 return;
306 }
307
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700308 NextHopGroupKey groupKey = new NextHopGroupKey(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800309
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700310 NextHop nextHop = new NextHop(route.nextHop(), route.nextHopMac(), groupKey);
Jonathan Hartdf207092015-12-10 11:19:25 -0800311
Jonathan Hartca47cd72015-12-13 12:31:09 -0800312 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800313 .setEthSrc(egressIntf.mac())
Jonathan Hartca47cd72015-12-13 12:31:09 -0800314 .setEthDst(nextHop.mac());
315
Saurav Das49cb5a12016-01-16 22:54:07 -0800316 TrafficSelector.Builder metabuilder = null;
Jonathan Hartca47cd72015-12-13 12:31:09 -0800317 if (!egressIntf.vlan().equals(VlanId.NONE)) {
318 treatment.pushVlan()
319 .setVlanId(egressIntf.vlan())
320 .setVlanPcp((byte) 0);
Saurav Das49cb5a12016-01-16 22:54:07 -0800321 } else {
322 // untagged outgoing port may require internal vlan in some pipelines
323 metabuilder = DefaultTrafficSelector.builder();
324 metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
Jonathan Hartca47cd72015-12-13 12:31:09 -0800325 }
326
327 treatment.setOutput(egressIntf.connectPoint().port());
Jonathan Hartdf207092015-12-10 11:19:25 -0800328
329 int nextId = flowObjectiveService.allocateNextId();
Saurav Das49cb5a12016-01-16 22:54:07 -0800330 NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800331 .withId(nextId)
Jonathan Hartca47cd72015-12-13 12:31:09 -0800332 .addTreatment(treatment.build())
Jonathan Hartdf207092015-12-10 11:19:25 -0800333 .withType(NextObjective.Type.SIMPLE)
Saurav Das49cb5a12016-01-16 22:54:07 -0800334 .fromApp(routerAppId);
335 if (metabuilder != null) {
336 nextBuilder.withMeta(metabuilder.build());
337 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800338
Saurav Das49cb5a12016-01-16 22:54:07 -0800339 NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
Jonathan Hartdf207092015-12-10 11:19:25 -0800340 flowObjectiveService.next(deviceId, nextObjective);
341
342 nextHops.put(nextHop.ip(), nextId);
343
Jonathan Hartb9401902016-02-02 18:46:01 -0800344 if (routeToNextHop) {
345 // Install route to next hop
346 ForwardingObjective fob =
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700347 generateRibForwardingObj(IpPrefix.valueOf(route.nextHop(), 32), nextId).add();
Jonathan Hartb9401902016-02-02 18:46:01 -0800348 flowObjectiveService.forward(deviceId, fob);
349 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800350 }
351
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700352 nextHopsCount.add(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800353 }
354
355 /*private synchronized Group deleteNextHop(IpPrefix prefix) {
356 IpAddress nextHopIp = prefixToNextHop.remove(prefix);
357 NextHop nextHop = nextHops.get(nextHopIp);
358 if (nextHop == null) {
359 log.warn("No next hop found when removing prefix {}", prefix);
360 return null;
361 }
362
363 Group group = groupService.getGroup(deviceId,
364 new DefaultGroupKey(appKryo.
365 serialize(nextHop.group())));
366
367 // FIXME disabling group deletes for now until we verify the logic is OK
368 if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
369 // There was one or less next hops, so there are now none
370
371 log.debug("removing group for next hop {}", nextHop);
372
373 nextHops.remove(nextHopIp);
374
375 groupService.removeGroup(deviceId,
376 new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
377 appId);
378 }
379
380 return group;
381 }*/
382
383 private void processIntfFilters(boolean install, Set<Interface> intfs) {
384 log.info("Processing {} router interfaces", intfs.size());
385 for (Interface intf : intfs) {
386 if (!intf.connectPoint().deviceId().equals(deviceId)) {
387 // Ignore interfaces if they are not on the router switch
388 continue;
389 }
390
gaurav164cf6d2016-03-25 21:43:04 +0530391 createFilteringObjective(install, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700392 createMcastFilteringObjective(install, intf);
gaurav164cf6d2016-03-25 21:43:04 +0530393 }
394 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800395
gaurav164cf6d2016-03-25 21:43:04 +0530396 //process filtering objective for interface add/remove.
397 private void processIntfFilter(boolean install, Interface intf) {
398
399 if (!intf.connectPoint().deviceId().equals(deviceId)) {
400 // Ignore interfaces if they are not on the router switch
401 return;
402 }
403
404 createFilteringObjective(install, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700405 createMcastFilteringObjective(install, intf);
gaurav164cf6d2016-03-25 21:43:04 +0530406 }
407
408 //create filtering objective for interface
409 private void createFilteringObjective(boolean install, Interface intf) {
Charles Chand55e84d2016-03-30 17:54:24 -0700410 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
411 VlanId.vlanId(ASSIGNED_VLAN) :
412 egressVlan();
gaurav164cf6d2016-03-25 21:43:04 +0530413
414 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
415 // first add filter for the interface
416 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
417 .addCondition(Criteria.matchEthDst(intf.mac()))
418 .addCondition(Criteria.matchVlanId(intf.vlan()));
419 fob.withPriority(PRIORITY_OFFSET);
420 if (intf.vlan() == VlanId.NONE) {
421 TrafficTreatment tt = DefaultTrafficTreatment.builder()
Charles Chand55e84d2016-03-30 17:54:24 -0700422 .pushVlan().setVlanId(assignedVlan).build();
gaurav164cf6d2016-03-25 21:43:04 +0530423 fob.withMeta(tt);
424 }
gaurav164cf6d2016-03-25 21:43:04 +0530425 fob.permit().fromApp(routerAppId);
426 sendFilteringObjective(install, fob, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700427
gaurav164cf6d2016-03-25 21:43:04 +0530428 if (controlPlaneConnectPoint != null) {
429 // then add the same mac/vlan filters for control-plane connect point
430 fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port()));
Saurav Das49cb5a12016-01-16 22:54:07 -0800431 sendFilteringObjective(install, fob, intf);
Jonathan Hartdf207092015-12-10 11:19:25 -0800432 }
433 }
434
Charles Chand55e84d2016-03-30 17:54:24 -0700435 //create filtering objective for multicast traffic
436 private void createMcastFilteringObjective(boolean install, Interface intf) {
437 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
438 VlanId.vlanId(ASSIGNED_VLAN) :
439 egressVlan();
440
441 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
442 // first add filter for the interface
443 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
444 .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
445 MacAddress.IPV4_MULTICAST_MASK))
446 .addCondition(Criteria.matchVlanId(ingressVlan()));
447 fob.withPriority(PRIORITY_OFFSET);
448 TrafficTreatment tt = DefaultTrafficTreatment.builder()
449 .pushVlan().setVlanId(assignedVlan).build();
450 fob.withMeta(tt);
451
452 fob.permit().fromApp(routerAppId);
453 sendFilteringObjective(install, fob, intf);
454 }
455
Saurav Das49cb5a12016-01-16 22:54:07 -0800456 private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
457 Interface intf) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800458
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700459 ObjectiveContext context = new DefaultObjectiveContext(
460 (objective) -> log.info("Installed filter for interface {}", intf),
461 (objective, error) ->
462 log.error("Failed to install filter for interface {}: {}", intf, error));
gaurav164cf6d2016-03-25 21:43:04 +0530463
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700464 FilteringObjective filter = install ? fob.add(context) : fob.remove(context);
465
466 flowObjectiveService.filter(deviceId, filter);
Saurav Das49cb5a12016-01-16 22:54:07 -0800467 }
468
Charles Chand55e84d2016-03-30 17:54:24 -0700469 private VlanId ingressVlan() {
470 McastConfig mcastConfig =
471 networkConfigService.getConfig(coreAppId, McastConfig.class);
472 return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
473 }
474
475 private VlanId egressVlan() {
476 McastConfig mcastConfig =
477 networkConfigService.getConfig(coreAppId, McastConfig.class);
478 return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
479 }
480
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700481 private class InternalRouteListener implements RouteListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800482 @Override
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700483 public void event(RouteEvent event) {
484 ResolvedRoute route = event.subject();
485 switch (event.type()) {
486 case ROUTE_ADDED:
487 case ROUTE_UPDATED:
488 updateRoute(route);
489 break;
490 case ROUTE_REMOVED:
491 deleteRoute(route);
492 break;
493 default:
494 break;
495 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800496 }
497 }
498
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800499 /**
500 * Listener for device events used to trigger driver setup when a device is
501 * (re)detected.
502 */
503 private class InternalDeviceListener implements DeviceListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800504 @Override
505 public void event(DeviceEvent event) {
506 switch (event.type()) {
507 case DEVICE_ADDED:
508 case DEVICE_AVAILABILITY_CHANGED:
509 if (deviceService.isAvailable(event.subject().id())) {
510 log.info("Device connected {}", event.subject().id());
511 if (event.subject().id().equals(deviceId)) {
Charles Chanf555a732016-02-15 15:37:15 -0800512 updateDevice();
Jonathan Hartdf207092015-12-10 11:19:25 -0800513 }
514 }
515 break;
516 // TODO other cases
517 case DEVICE_UPDATED:
518 case DEVICE_REMOVED:
519 case DEVICE_SUSPENDED:
520 case PORT_ADDED:
521 case PORT_UPDATED:
522 case PORT_REMOVED:
523 default:
524 break;
525 }
526 }
527 }
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800528
529 /**
530 * Listener for network config events.
531 */
532 private class InternalNetworkConfigListener implements NetworkConfigListener {
533 @Override
534 public void event(NetworkConfigEvent event) {
535 if (event.subject().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
536 switch (event.type()) {
537 case CONFIG_ADDED:
538 case CONFIG_UPDATED:
539 updateConfig();
540 break;
541 case CONFIG_REGISTERED:
542 case CONFIG_UNREGISTERED:
543 case CONFIG_REMOVED:
544 default:
545 break;
546 }
547 }
548 }
549 }
gaurav164cf6d2016-03-25 21:43:04 +0530550
551 private class InternalInterfaceListener implements InterfaceListener {
gaurav164cf6d2016-03-25 21:43:04 +0530552 @Override
553 public void event(InterfaceEvent event) {
554 Interface intf = event.subject();
555 switch (event.type()) {
556 case INTERFACE_ADDED:
557 if (intf != null) {
558 processIntfFilter(true, intf);
559 }
560 break;
561 case INTERFACE_UPDATED:
562 break;
563 case INTERFACE_REMOVED:
564 if (intf != null) {
565 processIntfFilter(false, intf);
566 }
567 break;
568 default:
569 break;
570 }
571 }
572 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800573}