blob: d12c6d83f48cea7ff8d2057d491d3fcebfc25ab8 [file] [log] [blame]
Jonathan Hartdf207092015-12-10 11:19:25 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
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 Hartf4bd0482017-01-27 15:11:18 -080017package org.onosproject.routing.fibinstaller;
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 Hartdf207092015-12-10 11:19:25 -080022import org.onlab.packet.Ethernet;
23import org.onlab.packet.IpAddress;
24import org.onlab.packet.IpPrefix;
Charles Chand55e84d2016-03-30 17:54:24 -070025import org.onlab.packet.MacAddress;
Jonathan Hartca47cd72015-12-13 12:31:09 -080026import org.onlab.packet.VlanId;
Jonathan Hartb9401902016-02-02 18:46:01 -080027import org.onlab.util.Tools;
gaurava2e61a52016-05-05 03:39:31 +053028import org.onosproject.app.ApplicationService;
Jonathan Hartb9401902016-02-02 18:46:01 -080029import org.onosproject.cfg.ComponentConfigService;
Jonathan Hartdf207092015-12-10 11:19:25 -080030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
Jonathan Hartdf207092015-12-10 11:19:25 -080032import org.onosproject.net.DeviceId;
Charles Chand55e84d2016-03-30 17:54:24 -070033import org.onosproject.net.config.ConfigFactory;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -080034import org.onosproject.net.config.NetworkConfigEvent;
35import org.onosproject.net.config.NetworkConfigListener;
Charles Chand55e84d2016-03-30 17:54:24 -070036import org.onosproject.net.config.NetworkConfigRegistry;
Jonathan Hartdf207092015-12-10 11:19:25 -080037import org.onosproject.net.config.NetworkConfigService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070038import org.onosproject.net.config.basics.McastConfig;
Charles Chand55e84d2016-03-30 17:54:24 -070039import org.onosproject.net.config.basics.SubjectFactories;
Jonathan Hartdf207092015-12-10 11:19:25 -080040import org.onosproject.net.device.DeviceService;
41import org.onosproject.net.flow.DefaultTrafficSelector;
42import org.onosproject.net.flow.DefaultTrafficTreatment;
43import org.onosproject.net.flow.TrafficSelector;
44import org.onosproject.net.flow.TrafficTreatment;
45import org.onosproject.net.flow.criteria.Criteria;
46import org.onosproject.net.flowobjective.DefaultFilteringObjective;
47import org.onosproject.net.flowobjective.DefaultForwardingObjective;
48import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Harta2eb9ff2016-04-13 21:27:06 -070049import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Jonathan Hartdf207092015-12-10 11:19:25 -080050import org.onosproject.net.flowobjective.FilteringObjective;
51import org.onosproject.net.flowobjective.FlowObjectiveService;
52import org.onosproject.net.flowobjective.ForwardingObjective;
53import org.onosproject.net.flowobjective.NextObjective;
Jonathan Hartdf207092015-12-10 11:19:25 -080054import org.onosproject.net.flowobjective.ObjectiveContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070055import org.onosproject.net.intf.Interface;
56import org.onosproject.net.intf.InterfaceService;
57import org.onosproject.routeservice.ResolvedRoute;
58import org.onosproject.routeservice.Route;
59import org.onosproject.routeservice.RouteEvent;
60import org.onosproject.routeservice.RouteListener;
61import org.onosproject.routeservice.RouteService;
Jonathan Hartf2e7a342017-03-20 15:43:21 -070062import org.onosproject.routing.InterfaceProvisionRequest;
Jonathan Hartf4bd0482017-01-27 15:11:18 -080063import org.onosproject.routing.NextHop;
64import org.onosproject.routing.NextHopGroupKey;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080065import org.onosproject.routing.Router;
Jonathan Hartf2e7a342017-03-20 15:43:21 -070066import org.onosproject.routing.RouterInfo;
Jonathan Hartdf207092015-12-10 11:19:25 -080067import org.onosproject.routing.RoutingService;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080068import org.onosproject.routing.config.RoutersConfig;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069import org.onosproject.routing.config.RoutingConfiguration;
Jonathan Hartb9401902016-02-02 18:46:01 -080070import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071import org.osgi.service.component.annotations.Activate;
72import org.osgi.service.component.annotations.Component;
73import org.osgi.service.component.annotations.Deactivate;
74import org.osgi.service.component.annotations.Modified;
75import org.osgi.service.component.annotations.Reference;
76import org.osgi.service.component.annotations.ReferenceCardinality;
Jonathan Hartdf207092015-12-10 11:19:25 -080077import org.slf4j.Logger;
78import org.slf4j.LoggerFactory;
79
Jonathan Hartb9401902016-02-02 18:46:01 -080080import java.util.Dictionary;
Jonathan Hartdf207092015-12-10 11:19:25 -080081import java.util.Map;
Jonathan Hartdf207092015-12-10 11:19:25 -080082import java.util.Set;
83
Ray Milkey8e406512018-10-24 15:56:50 -070084import static org.onosproject.routing.fibinstaller.OsgiPropertyConstants.ROUTE_TO_NEXT_HOP;
85import static org.onosproject.routing.fibinstaller.OsgiPropertyConstants.ROUTE_TO_NEXT_HOP_DEFAULT;
86
Jonathan Hartdf207092015-12-10 11:19:25 -080087/**
88 * Programs routes to a single OpenFlow switch.
89 */
Ray Milkey8e406512018-10-24 15:56:50 -070090@Component(
91 immediate = true,
92 property = {
93 ROUTE_TO_NEXT_HOP + ":Boolean= " + ROUTE_TO_NEXT_HOP_DEFAULT
94 }
95)
Jonathan Harte7327042017-02-02 13:11:25 -080096public class FibInstaller {
Jonathan Hartdf207092015-12-10 11:19:25 -080097
98 private final Logger log = LoggerFactory.getLogger(getClass());
Jonathan Harte7327042017-02-02 13:11:25 -080099 private static final String APP_NAME = "org.onosproject.fibinstaller";
Jonathan Hartdf207092015-12-10 11:19:25 -0800100
101 private static final int PRIORITY_OFFSET = 100;
102 private static final int PRIORITY_MULTIPLIER = 5;
103
Charles Chan03a73e02016-10-24 14:52:01 -0700104 // FIXME: This should be eliminated when we have an API in SR that
105 // programs the fabric switches for VR
Saurav Das49cb5a12016-01-16 22:54:07 -0800106 public static final short ASSIGNED_VLAN = 4094;
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800109 protected CoreService coreService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700112 protected RouteService routeService;
Jonathan Hartdf207092015-12-10 11:19:25 -0800113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800115 protected InterfaceService interfaceService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800118 protected NetworkConfigService networkConfigService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chand55e84d2016-03-30 17:54:24 -0700121 protected NetworkConfigRegistry networkConfigRegistry;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hartb9401902016-02-02 18:46:01 -0800124 protected ComponentConfigService componentConfigService;
125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800127 protected FlowObjectiveService flowObjectiveService;
128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hartdf207092015-12-10 11:19:25 -0800130 protected DeviceService deviceService;
131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
gaurava2e61a52016-05-05 03:39:31 +0530133 protected ApplicationService applicationService;
134
Ray Milkey8e406512018-10-24 15:56:50 -0700135 /** Install a /32 or /128 route to each next hop. */
136 private boolean routeToNextHop = ROUTE_TO_NEXT_HOP_DEFAULT;
Jonathan Hartb9401902016-02-02 18:46:01 -0800137
Jonathan Hartdf207092015-12-10 11:19:25 -0800138 // Device id of data-plane switch - should be learned from config
139 private DeviceId deviceId;
140
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800141 private Router interfaceManager;
Jonathan Hart883fd372016-02-10 14:36:15 -0800142
Charles Chand55e84d2016-03-30 17:54:24 -0700143 private ApplicationId coreAppId;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800144 private ApplicationId routerAppId;
Jonathan Harte7327042017-02-02 13:11:25 -0800145 private ApplicationId fibAppId;
Jonathan Hartdf207092015-12-10 11:19:25 -0800146
147 // Reference count for how many times a next hop is used by a route
148 private final Multiset<IpAddress> nextHopsCount = ConcurrentHashMultiset.create();
149
150 // Mapping from prefix to its current next hop
151 private final Map<IpPrefix, IpAddress> prefixToNextHop = Maps.newHashMap();
152
153 // Mapping from next hop IP to next hop object containing group info
154 private final Map<IpAddress, Integer> nextHops = Maps.newHashMap();
155
Jonathan Hart25bd6682016-06-03 10:45:47 -0700156 private final InternalRouteListener routeListener = new InternalRouteListener();
157 private final InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
Jonathan Hartdf207092015-12-10 11:19:25 -0800158
Charles Chand55e84d2016-03-30 17:54:24 -0700159 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
160 new ConfigFactory<ApplicationId, McastConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
161 McastConfig.class, "multicast") {
162 @Override
163 public McastConfig createConfig() {
164 return new McastConfig();
165 }
166 };
167
Jonathan Hartdf207092015-12-10 11:19:25 -0800168 @Activate
Jonathan Hartb9401902016-02-02 18:46:01 -0800169 protected void activate(ComponentContext context) {
Jonathan Hartb9401902016-02-02 18:46:01 -0800170 componentConfigService.registerProperties(getClass());
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800171 modified(context);
172
Jonathan Hart60e7f512017-02-10 10:24:24 -0800173 RoutingConfiguration.register(networkConfigRegistry);
174
Charles Chand55e84d2016-03-30 17:54:24 -0700175 coreAppId = coreService.registerApplication(CoreService.CORE_APP_NAME);
Jonathan Hart9ad777f2016-02-19 12:44:36 -0800176 routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
Jonathan Harte7327042017-02-02 13:11:25 -0800177 fibAppId = coreService.registerApplication(APP_NAME);
Jonathan Hartb9401902016-02-02 18:46:01 -0800178
Charles Chand55e84d2016-03-30 17:54:24 -0700179 networkConfigRegistry.registerConfigFactory(mcastConfigFactory);
180
Jonathan Hart25bd6682016-06-03 10:45:47 -0700181 networkConfigService.addListener(configListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700182
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800183 processRouterConfig();
Jonathan Hartdf207092015-12-10 11:19:25 -0800184
Jonathan Harte7327042017-02-02 13:11:25 -0800185 applicationService.registerDeactivateHook(fibAppId, () -> cleanUp());
gaurava2e61a52016-05-05 03:39:31 +0530186
Jonathan Hartdf207092015-12-10 11:19:25 -0800187 log.info("Started");
188 }
189
190 @Deactivate
191 protected void deactivate() {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700192 networkConfigService.removeListener(configListener);
gaurav164cf6d2016-03-25 21:43:04 +0530193
Jonathan Hart60e7f512017-02-10 10:24:24 -0800194 RoutingConfiguration.unregister(networkConfigRegistry);
195
Jonathan Hartb9401902016-02-02 18:46:01 -0800196 componentConfigService.unregisterProperties(getClass(), false);
197
Jonathan Hartdf207092015-12-10 11:19:25 -0800198 log.info("Stopped");
199 }
200
Jonathan Hartb9401902016-02-02 18:46:01 -0800201 @Modified
202 protected void modified(ComponentContext context) {
203 Dictionary<?, ?> properties = context.getProperties();
204 if (properties == null) {
205 return;
206 }
207
208 String strRouteToNextHop = Tools.get(properties, "routeToNextHop");
209 routeToNextHop = Boolean.parseBoolean(strRouteToNextHop);
210
211 log.info("routeToNextHop set to {}", routeToNextHop);
212 }
213
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800214 private void processRouterConfig() {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800215 Set<RoutersConfig.Router> routerConfigs =
Jonathan Hart60e7f512017-02-10 10:24:24 -0800216 RoutingConfiguration.getRouterConfigurations(networkConfigService, routerAppId);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800217 if (routerConfigs.isEmpty()) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800218 log.info("Router config not available");
Jonathan Hartdf207092015-12-10 11:19:25 -0800219 return;
220 }
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800221 RoutersConfig.Router routerConfig = routerConfigs.stream().findFirst().get();
Jonathan Hartdf207092015-12-10 11:19:25 -0800222
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800223 if (interfaceManager == null) {
224 deviceId = routerConfig.controlPlaneConnectPoint().deviceId();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700225 log.info("Router device ID is {}", deviceId);
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800226
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700227 routeService.addListener(routeListener);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800228
229 interfaceManager = createRouter(RouterInfo.from(routerConfig));
gaurava2e61a52016-05-05 03:39:31 +0530230 } else {
Charles Chanc6d227e2017-02-28 15:15:17 -0800231 interfaceManager.changeConfiguration(RouterInfo.from(routerConfig), false);
gaurava2e61a52016-05-05 03:39:31 +0530232 }
gaurav25118892016-08-24 05:35:03 +0530233 }
234
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800235 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800236 * Removes filtering objectives and routes before deactivate.
237 */
238 private void cleanUp() {
239 //remove the route listener
240 routeService.removeListener(routeListener);
241
242 //clean up the routes.
Jonathan Hartf2e7a342017-03-20 15:43:21 -0700243 prefixToNextHop.entrySet().stream()
244 .map(e -> new Route(Route.Source.UNDEFINED, e.getKey(), e.getValue()))
245 .forEach(this::deleteRoute);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800246
247 if (interfaceManager != null) {
248 interfaceManager.cleanup();
249 }
250 }
251
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800252 private Router createRouter(RouterInfo info) {
253 return new Router(
254 info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800255 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800256 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800257 this::provisionInterface,
Charles Chanc6d227e2017-02-28 15:15:17 -0800258 this::unprovisionInterface,
259 false);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800260 }
261
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700262 private void updateRoute(ResolvedRoute route) {
263 addNextHop(route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800264
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700265 Integer nextId;
266 synchronized (this) {
267 nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800268 }
269
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700270 flowObjectiveService.forward(deviceId,
271 generateRibForwardingObj(route.prefix(), nextId).add());
272 log.trace("Sending forwarding objective {} -> nextId:{}", route, nextId);
Jonathan Hartdf207092015-12-10 11:19:25 -0800273 }
274
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700275 private synchronized void deleteRoute(ResolvedRoute route) {
Jonathan Hart10dbafd2017-05-18 15:53:03 -0700276 deleteRoute(route.route());
Jonathan Hartf2e7a342017-03-20 15:43:21 -0700277 }
278
279 private void deleteRoute(Route route) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700280 //Integer nextId = nextHops.get(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800281
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700282 /* Group group = deleteNextHop(route.prefix());
283 if (group == null) {
284 log.warn("Group not found when deleting {}", route);
285 return;
286 }*/
Jonathan Hartdf207092015-12-10 11:19:25 -0800287
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700288 flowObjectiveService.forward(deviceId,
289 generateRibForwardingObj(route.prefix(), null).remove());
Jonathan Hartdf207092015-12-10 11:19:25 -0800290 }
291
292 private ForwardingObjective.Builder generateRibForwardingObj(IpPrefix prefix,
293 Integer nextId) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530294 TrafficSelector selector = buildIpSelectorFromIpPrefix(prefix).build();
Jonathan Hartdf207092015-12-10 11:19:25 -0800295 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
296
297 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
Jonathan Harte7327042017-02-02 13:11:25 -0800298 .fromApp(fibAppId)
Jonathan Hartdf207092015-12-10 11:19:25 -0800299 .makePermanent()
300 .withSelector(selector)
301 .withPriority(priority)
302 .withFlag(ForwardingObjective.Flag.SPECIFIC);
303
304 if (nextId == null) {
305 // Route withdraws are not specified with next hops. Generating
306 // dummy treatment as there is no equivalent nextId info.
307 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
308 } else {
309 fwdBuilder.nextStep(nextId);
310 }
311 return fwdBuilder;
312 }
313
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530314 /**
315 * Method to build IPv4 or IPv6 selector.
316 *
317 * @param prefixToMatch the prefix to match
318 * @return the traffic selector builder
319 */
320 private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
321 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
322 // If the prefix is IPv4
323 if (prefixToMatch.isIp4()) {
324 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
325 selectorBuilder.matchIPDst(prefixToMatch);
326 return selectorBuilder;
327 }
328 // If the prefix is IPv6
329 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
330 selectorBuilder.matchIPv6Dst(prefixToMatch);
331 return selectorBuilder;
332 }
333
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700334 private synchronized void addNextHop(ResolvedRoute route) {
335 prefixToNextHop.put(route.prefix(), route.nextHop());
336 if (nextHopsCount.count(route.nextHop()) == 0) {
Jonathan Hartdf207092015-12-10 11:19:25 -0800337 // There was no next hop in the multiset
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700338 Interface egressIntf = interfaceService.getMatchingInterface(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800339 if (egressIntf == null) {
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700340 log.warn("no egress interface found for {}", route);
Jonathan Hartdf207092015-12-10 11:19:25 -0800341 return;
342 }
343
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700344 NextHopGroupKey groupKey = new NextHopGroupKey(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800345
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700346 NextHop nextHop = new NextHop(route.nextHop(), route.nextHopMac(), groupKey);
Jonathan Hartdf207092015-12-10 11:19:25 -0800347
Jonathan Hartca47cd72015-12-13 12:31:09 -0800348 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800349 .setEthSrc(egressIntf.mac())
Jonathan Hartca47cd72015-12-13 12:31:09 -0800350 .setEthDst(nextHop.mac());
351
Saurav Das49cb5a12016-01-16 22:54:07 -0800352 TrafficSelector.Builder metabuilder = null;
Jonathan Hartca47cd72015-12-13 12:31:09 -0800353 if (!egressIntf.vlan().equals(VlanId.NONE)) {
354 treatment.pushVlan()
355 .setVlanId(egressIntf.vlan())
356 .setVlanPcp((byte) 0);
Saurav Das49cb5a12016-01-16 22:54:07 -0800357 } else {
358 // untagged outgoing port may require internal vlan in some pipelines
359 metabuilder = DefaultTrafficSelector.builder();
360 metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
Jonathan Hartca47cd72015-12-13 12:31:09 -0800361 }
362
363 treatment.setOutput(egressIntf.connectPoint().port());
Jonathan Hartdf207092015-12-10 11:19:25 -0800364
365 int nextId = flowObjectiveService.allocateNextId();
Saurav Das49cb5a12016-01-16 22:54:07 -0800366 NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
Jonathan Hartdf207092015-12-10 11:19:25 -0800367 .withId(nextId)
Jonathan Hartca47cd72015-12-13 12:31:09 -0800368 .addTreatment(treatment.build())
Jonathan Hartdf207092015-12-10 11:19:25 -0800369 .withType(NextObjective.Type.SIMPLE)
Jonathan Harte7327042017-02-02 13:11:25 -0800370 .fromApp(fibAppId);
Saurav Das49cb5a12016-01-16 22:54:07 -0800371 if (metabuilder != null) {
372 nextBuilder.withMeta(metabuilder.build());
373 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800374
Saurav Das49cb5a12016-01-16 22:54:07 -0800375 NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
Jonathan Hartdf207092015-12-10 11:19:25 -0800376 flowObjectiveService.next(deviceId, nextObjective);
377
378 nextHops.put(nextHop.ip(), nextId);
379
Jonathan Hartb9401902016-02-02 18:46:01 -0800380 if (routeToNextHop) {
381 // Install route to next hop
382 ForwardingObjective fob =
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700383 generateRibForwardingObj(IpPrefix.valueOf(route.nextHop(), 32), nextId).add();
Jonathan Hartb9401902016-02-02 18:46:01 -0800384 flowObjectiveService.forward(deviceId, fob);
385 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800386 }
387
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700388 nextHopsCount.add(route.nextHop());
Jonathan Hartdf207092015-12-10 11:19:25 -0800389 }
390
391 /*private synchronized Group deleteNextHop(IpPrefix prefix) {
392 IpAddress nextHopIp = prefixToNextHop.remove(prefix);
393 NextHop nextHop = nextHops.get(nextHopIp);
394 if (nextHop == null) {
395 log.warn("No next hop found when removing prefix {}", prefix);
396 return null;
397 }
398
399 Group group = groupService.getGroup(deviceId,
400 new DefaultGroupKey(appKryo.
401 serialize(nextHop.group())));
402
403 // FIXME disabling group deletes for now until we verify the logic is OK
404 if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
405 // There was one or less next hops, so there are now none
406
407 log.debug("removing group for next hop {}", nextHop);
408
409 nextHops.remove(nextHopIp);
410
411 groupService.removeGroup(deviceId,
412 new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
413 appId);
414 }
415
416 return group;
417 }*/
418
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800419 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800420 updateInterfaceFilters(intf, true);
gaurav164cf6d2016-03-25 21:43:04 +0530421 }
422
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800423 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800424 updateInterfaceFilters(intf, false);
425 }
426
427 /**
428 * Installs or removes flow objectives relating to an interface.
429 *
430 * @param intf interface to update objectives for
431 * @param install true to install the objectives, false to remove them
432 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800433 private void updateInterfaceFilters(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800434 updateFilteringObjective(intf, install);
435 updateMcastFilteringObjective(intf, install);
436 }
437
438 /**
439 * Installs or removes unicast filtering objectives relating to an interface.
440 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800441 * @param routerIntf interface to update objectives for
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800442 * @param install true to install the objectives, false to remove them
443 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800444 private void updateFilteringObjective(InterfaceProvisionRequest routerIntf, boolean install) {
445 Interface intf = routerIntf.intf();
Charles Chand55e84d2016-03-30 17:54:24 -0700446 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
447 VlanId.vlanId(ASSIGNED_VLAN) :
448 egressVlan();
gaurav164cf6d2016-03-25 21:43:04 +0530449
450 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
451 // first add filter for the interface
452 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
453 .addCondition(Criteria.matchEthDst(intf.mac()))
454 .addCondition(Criteria.matchVlanId(intf.vlan()));
455 fob.withPriority(PRIORITY_OFFSET);
456 if (intf.vlan() == VlanId.NONE) {
457 TrafficTreatment tt = DefaultTrafficTreatment.builder()
Charles Chand55e84d2016-03-30 17:54:24 -0700458 .pushVlan().setVlanId(assignedVlan).build();
gaurav164cf6d2016-03-25 21:43:04 +0530459 fob.withMeta(tt);
460 }
Jonathan Harte7327042017-02-02 13:11:25 -0800461 fob.permit().fromApp(fibAppId);
gaurav164cf6d2016-03-25 21:43:04 +0530462 sendFilteringObjective(install, fob, intf);
Charles Chand55e84d2016-03-30 17:54:24 -0700463
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800464 // then add the same mac/vlan filters for control-plane connect point
465 fob.withKey(Criteria.matchInPort(routerIntf.controlPlaneConnectPoint().port()));
466 sendFilteringObjective(install, fob, intf);
Jonathan Hartdf207092015-12-10 11:19:25 -0800467 }
468
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800469 /**
470 * Installs or removes multicast filtering objectives relating to an interface.
471 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800472 * @param routerIntf interface to update objectives for
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800473 * @param install true to install the objectives, false to remove them
474 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800475 private void updateMcastFilteringObjective(InterfaceProvisionRequest routerIntf, boolean install) {
476 Interface intf = routerIntf.intf();
Charles Chand55e84d2016-03-30 17:54:24 -0700477 VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ?
478 VlanId.vlanId(ASSIGNED_VLAN) :
479 egressVlan();
480
481 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
482 // first add filter for the interface
483 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
484 .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
485 MacAddress.IPV4_MULTICAST_MASK))
486 .addCondition(Criteria.matchVlanId(ingressVlan()));
487 fob.withPriority(PRIORITY_OFFSET);
488 TrafficTreatment tt = DefaultTrafficTreatment.builder()
489 .pushVlan().setVlanId(assignedVlan).build();
490 fob.withMeta(tt);
491
Jonathan Harte7327042017-02-02 13:11:25 -0800492 fob.permit().fromApp(fibAppId);
Charles Chand55e84d2016-03-30 17:54:24 -0700493 sendFilteringObjective(install, fob, intf);
494 }
495
Saurav Das49cb5a12016-01-16 22:54:07 -0800496 private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
497 Interface intf) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800498
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700499 ObjectiveContext context = new DefaultObjectiveContext(
500 (objective) -> log.info("Installed filter for interface {}", intf),
501 (objective, error) ->
502 log.error("Failed to install filter for interface {}: {}", intf, error));
gaurav164cf6d2016-03-25 21:43:04 +0530503
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700504 FilteringObjective filter = install ? fob.add(context) : fob.remove(context);
505
506 flowObjectiveService.filter(deviceId, filter);
Saurav Das49cb5a12016-01-16 22:54:07 -0800507 }
508
Charles Chand55e84d2016-03-30 17:54:24 -0700509 private VlanId ingressVlan() {
510 McastConfig mcastConfig =
511 networkConfigService.getConfig(coreAppId, McastConfig.class);
512 return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
513 }
514
515 private VlanId egressVlan() {
516 McastConfig mcastConfig =
517 networkConfigService.getConfig(coreAppId, McastConfig.class);
518 return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
519 }
520
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800521 /**
522 * Listener for route changes.
523 */
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700524 private class InternalRouteListener implements RouteListener {
Jonathan Hartdf207092015-12-10 11:19:25 -0800525 @Override
Jonathan Harta2eb9ff2016-04-13 21:27:06 -0700526 public void event(RouteEvent event) {
527 ResolvedRoute route = event.subject();
528 switch (event.type()) {
529 case ROUTE_ADDED:
530 case ROUTE_UPDATED:
531 updateRoute(route);
532 break;
533 case ROUTE_REMOVED:
534 deleteRoute(route);
535 break;
536 default:
537 break;
538 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800539 }
540 }
541
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800542 /**
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800543 * Listener for network config events.
544 */
545 private class InternalNetworkConfigListener implements NetworkConfigListener {
546 @Override
547 public void event(NetworkConfigEvent event) {
Jonathan Hart25bd6682016-06-03 10:45:47 -0700548 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800549 switch (event.type()) {
550 case CONFIG_ADDED:
551 case CONFIG_UPDATED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800552 processRouterConfig();
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800553 break;
554 case CONFIG_REGISTERED:
gaurav25118892016-08-24 05:35:03 +0530555 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800556 case CONFIG_UNREGISTERED:
gaurav25118892016-08-24 05:35:03 +0530557 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800558 case CONFIG_REMOVED:
gaurav25118892016-08-24 05:35:03 +0530559 cleanUp();
560 break;
Jonathan Hartb3fa42c2016-01-13 09:50:43 -0800561 default:
562 break;
563 }
564 }
565 }
566 }
Jonathan Hartdf207092015-12-10 11:19:25 -0800567}