blob: 4d4141bd34aebbeeca200ced9bc34ca24e7ac280 [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 Hartb3fa42c2016-01-13 09:50:43 -0800175 updateConfig();
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
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700184 private RouterInterfaceManager createRouter(DeviceId deviceId, Set<String> configuredInterfaces) {
185 return new RouterInterfaceManager(deviceId,
186 configuredInterfaces,
187 interfaceService,
188 intf -> processIntfFilter(true, intf),
189 intf -> processIntfFilter(false, intf)
190 );
191 }
192
Jonathan Hartdf207092015-12-10 11:19:25 -0800193 @Deactivate
194 protected void deactivate() {
Charles Chan00d8b5f2016-12-04 17:17:39 -0800195 // FIXME: This will also remove flows when an instance goes down.
196 // This is a temporary solution and should be addressed in CORD-710.
197 cleanUp();
198
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700199 asyncDeviceFetcher.shutdown();
Jonathan Hart25bd6682016-06-03 10:45:47 -0700200 networkConfigService.removeListener(configListener);
gaurav164cf6d2016-03-25 21:43:04 +0530201
Jonathan Hartb9401902016-02-02 18:46:01 -0800202 componentConfigService.unregisterProperties(getClass(), false);
203
Jonathan Hartdf207092015-12-10 11:19:25 -0800204 log.info("Stopped");
205 }
206
Jonathan Hartb9401902016-02-02 18:46:01 -0800207 @Modified
208 protected void modified(ComponentContext context) {
209 Dictionary<?, ?> properties = context.getProperties();
210 if (properties == null) {
211 return;
212 }
213
214 String strRouteToNextHop = Tools.get(properties, "routeToNextHop");
215 routeToNextHop = Boolean.parseBoolean(strRouteToNextHop);
216
217 log.info("routeToNextHop set to {}", routeToNextHop);
218 }
219
gaurava2e61a52016-05-05 03:39:31 +0530220 //remove filtering objectives and routes before deactivate.
221 private void cleanUp() {
gaurav25118892016-08-24 05:35:03 +0530222 //remove the route listener
223 routeService.removeListener(routeListener);
224
gaurava2e61a52016-05-05 03:39:31 +0530225 //clean up the routes.
226 for (Map.Entry<IpPrefix, IpAddress> routes: prefixToNextHop.entrySet()) {
Charles Chan8fe9f4c2016-10-24 16:46:25 -0700227 deleteRoute(new ResolvedRoute(routes.getKey(), null, null, null));
gaurava2e61a52016-05-05 03:39:31 +0530228 }
gaurav25118892016-08-24 05:35:03 +0530229
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700230 if (interfaceManager != null) {
231 interfaceManager.cleanup();
gaurav25118892016-08-24 05:35:03 +0530232 }
gaurava2e61a52016-05-05 03:39:31 +0530233 }
234
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800235 private void updateConfig() {
236 RouterConfig routerConfig =
237 networkConfigService.getConfig(routerAppId, RoutingService.ROUTER_CONFIG_CLASS);
Jonathan Hartdf207092015-12-10 11:19:25 -0800238
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800239 if (routerConfig == null) {
240 log.info("Router config not available");
Jonathan Hartdf207092015-12-10 11:19:25 -0800241 return;
242 }
243
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700244 Set<String> interfaces = Sets.newHashSet(routerConfig.getInterfaces());
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800245
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700246 if (deviceId == null) {
247 controlPlaneConnectPoint = routerConfig.getControlPlaneConnectPoint();
248 log.info("Control Plane Connect Point: {}", controlPlaneConnectPoint);
Jonathan Hart883fd372016-02-10 14:36:15 -0800249
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700250 deviceId = routerConfig.getControlPlaneConnectPoint().deviceId();
251 log.info("Router device ID is {}", deviceId);
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800252
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700253 routeService.addListener(routeListener);
254 asyncDeviceFetcher.getDevice(deviceId).whenComplete((deviceId, e) ->
255 interfaceManager = createRouter(deviceId, interfaces));
gaurava2e61a52016-05-05 03:39:31 +0530256 } else {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700257 interfaceManager.changeConfiguredInterfaces(interfaces);
gaurava2e61a52016-05-05 03:39:31 +0530258 }
gaurav25118892016-08-24 05:35:03 +0530259 }
260
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700261 private void updateRoute(ResolvedRoute route) {
262 addNextHop(route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800263
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700264 Integer nextId;
265 synchronized (this) {
266 nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800267 }
268
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700269 flowObjectiveService.forward(deviceId,
270 generateRibForwardingObj(route.prefix(), nextId).add());
271 log.trace("Sending forwarding objective {} -> nextId:{}", route, nextId);
Jonathan Hartdf207092015-12-10 11:19:25 -0800272 }
273
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700274 private synchronized void deleteRoute(ResolvedRoute route) {
275 //Integer nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800276
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700277 /* Group group = deleteNextHop(route.prefix());
278 if (group == null) {
279 log.warn("Group not found when deleting {}", route);
280 return;
281 }*/
Jonathan Hartdf207092015-12-10 11:19:25 -0800282
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700283 flowObjectiveService.forward(deviceId,
284 generateRibForwardingObj(route.prefix(), null).remove());
Jonathan Hartdf207092015-12-10 11:19:25 -0800285 }
286
287 private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
288 Integer nextId) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530289 TrafficSelector selector = buildIpSelectorFromIpPrefix(prefix).build();
Jonathan Hartdf207092015-12-10 11:19:25 -0800290 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
291
292 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
Saurav Das49cb5a12016-01-16 22:54:07 -0800293 .fromApp(routerAppId)
Jonathan Hartdf207092015-12-10 11:19:25 -0800294 .makePermanent()
295 .withSelector(selector)
296 .withPriority(priority)
297 .withFlag(ForwardingObjective.Flag.SPECIFIC);
298
299 if (nextId == null) {
300 // Route withdraws are not specified with next hops. Generating
301 // dummy treatment as there is no equivalent nextId info.
302 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
303 } else {
304 fwdBuilder.nextStep(nextId);
305 }
306 return fwdBuilder;
307 }
308
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530309 /**
310 * Method to build IPv4 or IPv6 selector.
311 *
312 * @param prefixToMatch the prefix to match
313 * @return the traffic selector builder
314 */
315 private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
316 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
317 // If the prefix is IPv4
318 if (prefixToMatch.isIp4()) {
319 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
320 selectorBuilder.matchIPDst(prefixToMatch);
321 return selectorBuilder;
322 }
323 // If the prefix is IPv6
324 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
325 selectorBuilder.matchIPv6Dst(prefixToMatch);
326 return selectorBuilder;
327 }
328
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700329 private synchronized void addNextHop(ResolvedRoute route) {
330 prefixToNextHop.put(route.prefix(), route.nextHop());
331 if (nextHopsCount.count(route.nextHop()) == 0) {
Jonathan Hartdf207092015-12-10 11:19:25 -0800332 // There was no next hop in the multiset
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700333 Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800334 if (egressIntf == null) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700335 log.warn("no egress interface found for {}", route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800336 return;
337 }
338
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700339 NextHopGroupKey groupKey = new NextHopGroupKey(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800340
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700341 NextHop nextHop = new NextHop(route.nextHop(), route.nextHopMac(), groupKey);
Jonathan Hartdf207092015-12-10 11:19:25 -0800342
Jonathan Hartca47cd72015-12-13 12:31:09 -0800343 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800344 .setEthSrc(egressIntf.mac())
Jonathan Hartca47cd72015-12-13 12:31:09 -0800345 .setEthDst(nextHop.mac());
346
Saurav Das49cb5a12016-01-16 22:54:07 -0800347 TrafficSelector.Builder metabuilder = null;
Jonathan Hartca47cd72015-12-13 12:31:09 -0800348 if (!egressIntf.vlan().equals(VlanId.NONE)) {
349 treatment.pushVlan()
350 .setVlanId(egressIntf.vlan())
351 .setVlanPcp((byte) 0);
Saurav Das49cb5a12016-01-16 22:54:07 -0800352 } else {
353 // untagged outgoing port may require internal vlan in some pipelines
354 metabuilder = DefaultTrafficSelector.builder();
355 metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
Jonathan Hartca47cd72015-12-13 12:31:09 -0800356 }
357
358 treatment.setOutput(egressIntf.connectPoint().port());
Jonathan Hartdf207092015-12-10 11:19:25 -0800359
360 int nextId = flowObjectiveService.allocateNextId();
Saurav Das49cb5a12016-01-16 22:54:07 -0800361 NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800362 .withId(nextId)
Jonathan Hartca47cd72015-12-13 12:31:09 -0800363 .addTreatment(treatment.build())
Jonathan Hartdf207092015-12-10 11:19:25 -0800364 .withType(NextObjective.Type.SIMPLE)
Saurav Das49cb5a12016-01-16 22:54:07 -0800365 .fromApp(routerAppId);
366 if (metabuilder != null) {
367 nextBuilder.withMeta(metabuilder.build());
368 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800369
Saurav Das49cb5a12016-01-16 22:54:07 -0800370 NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
Jonathan Hartdf207092015-12-10 11:19:25 -0800371 flowObjectiveService.next(deviceId, nextObjective);
372
373 nextHops.put(nextHop.ip(), nextId);
374
Jonathan Hartb9401902016-02-02 18:46:01 -0800375 if (routeToNextHop) {
376 // Install route to next hop
377 ForwardingObjective fob =
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700378 generateRibForwardingObj(IpPrefix.valueOf(route.nextHop(), 32), nextId).add();
Jonathan Hartb9401902016-02-02 18:46:01 -0800379 flowObjectiveService.forward(deviceId, fob);
380 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800381 }
382
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700383 nextHopsCount.add(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800384 }
385
386 /*private synchronized Group deleteNextHop(IpPrefix prefix) {
387 IpAddress nextHopIp = prefixToNextHop.remove(prefix);
388 NextHop nextHop = nextHops.get(nextHopIp);
389 if (nextHop == null) {
390 log.warn("No next hop found when removing prefix {}", prefix);
391 return null;
392 }
393
394 Group group = groupService.getGroup(deviceId,
395 new DefaultGroupKey(appKryo.
396 serialize(nextHop.group())));
397
398 // FIXME disabling group deletes for now until we verify the logic is OK
399 if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
400 // There was one or less next hops, so there are now none
401
402 log.debug("removing group for next hop {}", nextHop);
403
404 nextHops.remove(nextHopIp);
405
406 groupService.removeGroup(deviceId,
407 new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
408 appId);
409 }
410
411 return group;
412 }*/
413
gaurav164cf6d2016-03-25 21:43:04 +0530414 //process filtering objective for interface add/remove.
415 private void processIntfFilter(boolean install, Interface intf) {
gaurav164cf6d2016-03-25 21:43:04 +0530416 createFilteringObjective(install, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700417 createMcastFilteringObjective(install, intf);
gaurav164cf6d2016-03-25 21:43:04 +0530418 }
419
420 //create filtering objective for interface
421 private void createFilteringObjective(boolean install, Interface intf) {
Charles Chand55e84d2016-03-30 17:54:24 -0700422 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
423 VlanId.vlanId(ASSIGNED_VLAN) :
424 egressVlan();
gaurav164cf6d2016-03-25 21:43:04 +0530425
426 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
427 // first add filter for the interface
428 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
429 .addCondition(Criteria.matchEthDst(intf.mac()))
430 .addCondition(Criteria.matchVlanId(intf.vlan()));
431 fob.withPriority(PRIORITY_OFFSET);
432 if (intf.vlan() == VlanId.NONE) {
433 TrafficTreatment tt = DefaultTrafficTreatment.builder()
Charles Chand55e84d2016-03-30 17:54:24 -0700434 .pushVlan().setVlanId(assignedVlan).build();
gaurav164cf6d2016-03-25 21:43:04 +0530435 fob.withMeta(tt);
436 }
gaurav164cf6d2016-03-25 21:43:04 +0530437 fob.permit().fromApp(routerAppId);
438 sendFilteringObjective(install, fob, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700439
gaurav164cf6d2016-03-25 21:43:04 +0530440 if (controlPlaneConnectPoint != null) {
441 // then add the same mac/vlan filters for control-plane connect point
442 fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port()));
Saurav Das49cb5a12016-01-16 22:54:07 -0800443 sendFilteringObjective(install, fob, intf);
Jonathan Hartdf207092015-12-10 11:19:25 -0800444 }
445 }
446
Charles Chand55e84d2016-03-30 17:54:24 -0700447 //create filtering objective for multicast traffic
448 private void createMcastFilteringObjective(boolean install, Interface intf) {
449 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
450 VlanId.vlanId(ASSIGNED_VLAN) :
451 egressVlan();
452
453 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
454 // first add filter for the interface
455 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
456 .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
457 MacAddress.IPV4_MULTICAST_MASK))
458 .addCondition(Criteria.matchVlanId(ingressVlan()));
459 fob.withPriority(PRIORITY_OFFSET);
460 TrafficTreatment tt = DefaultTrafficTreatment.builder()
461 .pushVlan().setVlanId(assignedVlan).build();
462 fob.withMeta(tt);
463
464 fob.permit().fromApp(routerAppId);
465 sendFilteringObjective(install, fob, intf);
466 }
467
Saurav Das49cb5a12016-01-16 22:54:07 -0800468 private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
469 Interface intf) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800470
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700471 ObjectiveContext context = new DefaultObjectiveContext(
472 (objective) -> log.info("Installed filter for interface {}", intf),
473 (objective, error) ->
474 log.error("Failed to install filter for interface {}: {}", intf, error));
gaurav164cf6d2016-03-25 21:43:04 +0530475
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700476 FilteringObjective filter = install ? fob.add(context) : fob.remove(context);
477
478 flowObjectiveService.filter(deviceId, filter);
Saurav Das49cb5a12016-01-16 22:54:07 -0800479 }
480
Charles Chand55e84d2016-03-30 17:54:24 -0700481 private VlanId ingressVlan() {
482 McastConfig mcastConfig =
483 networkConfigService.getConfig(coreAppId, McastConfig.class);
484 return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
485 }
486
487 private VlanId egressVlan() {
488 McastConfig mcastConfig =
489 networkConfigService.getConfig(coreAppId, McastConfig.class);
490 return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
491 }
492
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700493 private class InternalRouteListener implements RouteListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800494 @Override
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700495 public void event(RouteEvent event) {
496 ResolvedRoute route = event.subject();
497 switch (event.type()) {
498 case ROUTE_ADDED:
499 case ROUTE_UPDATED:
500 updateRoute(route);
501 break;
502 case ROUTE_REMOVED:
503 deleteRoute(route);
504 break;
505 default:
506 break;
507 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800508 }
509 }
510
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800511 /**
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800512 * Listener for network config events.
513 */
514 private class InternalNetworkConfigListener implements NetworkConfigListener {
515 @Override
516 public void event(NetworkConfigEvent event) {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700517 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800518 switch (event.type()) {
519 case CONFIG_ADDED:
520 case CONFIG_UPDATED:
521 updateConfig();
522 break;
523 case CONFIG_REGISTERED:
gaurav25118892016-08-24 05:35:03 +0530524 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800525 case CONFIG_UNREGISTERED:
gaurav25118892016-08-24 05:35:03 +0530526 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800527 case CONFIG_REMOVED:
gaurav25118892016-08-24 05:35:03 +0530528 cleanUp();
529 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800530 default:
531 break;
532 }
533 }
534 }
535 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800536}