blob: 679d33ef20695629d9572d561bb51c799c0b71a9 [file] [log] [blame]
Jonathan Hart6344f572015-12-15 08:26:25 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Jonathan Hart6344f572015-12-15 08:26: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.cpr;
Jonathan Hart6344f572015-12-15 08:26:25 -080018
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053019import com.google.common.collect.Lists;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070020import com.google.common.collect.Maps;
Jonathan Hart6344f572015-12-15 08:26:25 -080021import org.onlab.packet.EthType;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053022import org.onlab.packet.Ip4Address;
Pier Luigi2b1ad872017-01-31 09:35:42 -080023import org.onlab.packet.Ip6Address;
Charles Chand0fd5dc2016-02-16 23:14:49 -080024import org.onlab.packet.IpPrefix;
25import org.onlab.packet.MacAddress;
Saurav Das49cb5a12016-01-16 22:54:07 -080026import org.onlab.packet.VlanId;
Charles Chanc6d227e2017-02-28 15:15:17 -080027import org.onlab.util.Tools;
kishore786b7e42016-05-19 16:25:57 +053028import org.onosproject.app.ApplicationService;
Charles Chanc6d227e2017-02-28 15:15:17 -080029import org.onosproject.cfg.ComponentConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -080030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080032import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080033import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080034import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080035import org.onosproject.net.PortNumber;
36import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
Jonathan Hart60e7f512017-02-10 10:24:24 -080038import org.onosproject.net.config.NetworkConfigRegistry;
Jonathan Hart6344f572015-12-15 08:26:25 -080039import org.onosproject.net.device.DeviceService;
40import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
44import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080045import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Hart6344f572015-12-15 08:26:25 -080046import org.onosproject.net.flowobjective.FlowObjectiveService;
47import org.onosproject.net.flowobjective.ForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080048import org.onosproject.net.flowobjective.NextObjective;
Charles Chand0fd5dc2016-02-16 23:14:49 -080049import org.onosproject.net.host.HostService;
Jonathan Hart6344f572015-12-15 08:26:25 -080050import org.onosproject.net.host.InterfaceIpAddress;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070051import org.onosproject.net.intf.Interface;
52import org.onosproject.net.intf.InterfaceService;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080053import org.onosproject.routing.InterfaceProvisionRequest;
54import org.onosproject.routing.Router;
Jonathan Hart60e7f512017-02-10 10:24:24 -080055import org.onosproject.routing.RouterInfo;
Jonathan Hart6344f572015-12-15 08:26:25 -080056import org.onosproject.routing.RoutingService;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080057import org.onosproject.routing.config.RoutersConfig;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070058import org.onosproject.routing.config.RoutingConfiguration;
Charles Chanc6d227e2017-02-28 15:15:17 -080059import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070060import org.osgi.service.component.annotations.Activate;
61import org.osgi.service.component.annotations.Component;
62import org.osgi.service.component.annotations.Deactivate;
63import org.osgi.service.component.annotations.Modified;
64import org.osgi.service.component.annotations.Reference;
65import org.osgi.service.component.annotations.ReferenceCardinality;
Jonathan Hart6344f572015-12-15 08:26:25 -080066import org.slf4j.Logger;
67
Charles Chanc6d227e2017-02-28 15:15:17 -080068import java.util.Dictionary;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070069import java.util.List;
70import java.util.Map;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070071import java.util.Set;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080072import java.util.concurrent.ConcurrentHashMap;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070073
Jonathan Hartf8cd0522016-10-25 07:09:55 -070074import static org.onlab.packet.Ethernet.TYPE_ARP;
75import static org.onlab.packet.Ethernet.TYPE_IPV4;
76import static org.onlab.packet.Ethernet.TYPE_IPV6;
77import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
78import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
79import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Pier Luigi2b1ad872017-01-31 09:35:42 -080080import static org.onlab.packet.IPv6.getLinkLocalAddress;
81import static org.onlab.packet.IPv6.getSolicitNodeAddress;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070082import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080083
84/**
85 * Manages connectivity between peers redirecting control traffic to a routing
86 * control plane available on the dataplane.
87 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080088@Component(immediate = true)
Jonathan Hart6344f572015-12-15 08:26:25 -080089public class ControlPlaneRedirectManager {
90
91 private final Logger log = getLogger(getClass());
92
Jonathan Hartf4bd0482017-01-27 15:11:18 -080093 public static final short ASSIGNED_VLAN = 4094;
94
Charles Chand0fd5dc2016-02-16 23:14:49 -080095 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +053096 private static final int IPV4_PRIORITY = 2000;
97 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053098 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080099 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -0800100
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700101 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6344f572015-12-15 08:26:25 -0800102 protected CoreService coreService;
103
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6344f572015-12-15 08:26:25 -0800105 protected DeviceService deviceService;
106
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6344f572015-12-15 08:26:25 -0800108 protected InterfaceService interfaceService;
109
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6344f572015-12-15 08:26:25 -0800111 protected FlowObjectiveService flowObjectiveService;
112
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart60e7f512017-02-10 10:24:24 -0800114 protected NetworkConfigRegistry networkConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -0800115
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800117 protected MastershipService mastershipService;
118
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800120 protected HostService hostService;
121
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kishore786b7e42016-05-19 16:25:57 +0530123 protected ApplicationService applicationService;
124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chanc6d227e2017-02-28 15:15:17 -0800126 protected ComponentConfigService cfgService;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 //@Property(name = "forceUnprovision", boolValue = false,
129 // label = "Force unprovision when the device goes offline")
Charles Chanc6d227e2017-02-28 15:15:17 -0800130 private boolean forceUnprovision = false;
131
Jonathan Harte7327042017-02-02 13:11:25 -0800132 private static final String APP_NAME = "org.onosproject.cpr";
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700133 private ApplicationId appId;
134
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700135 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
136
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800137 private Map<DeviceId, Router> routers = new ConcurrentHashMap<>();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700138
Jonathan Hart6344f572015-12-15 08:26:25 -0800139 private final InternalNetworkConfigListener networkConfigListener =
140 new InternalNetworkConfigListener();
141
142 @Activate
Charles Chanc6d227e2017-02-28 15:15:17 -0800143 protected void activate(ComponentContext context) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800144 this.appId = coreService.registerApplication(APP_NAME);
145
Charles Chanc6d227e2017-02-28 15:15:17 -0800146 cfgService.registerProperties(getClass());
147 modified(context);
148
Jonathan Hart60e7f512017-02-10 10:24:24 -0800149 RoutingConfiguration.register(networkConfigService);
150
Jonathan Hart6344f572015-12-15 08:26:25 -0800151 networkConfigService.addListener(networkConfigListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700152
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800153 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800154
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800155 applicationService.registerDeactivateHook(this.appId,
156 () -> routers.forEach((d, r) -> r.cleanup()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800157 }
158
159 @Deactivate
Jonathan Harte7327042017-02-02 13:11:25 -0800160 protected void deactivate() {
Charles Chanc6d227e2017-02-28 15:15:17 -0800161 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart6344f572015-12-15 08:26:25 -0800162 networkConfigService.removeListener(networkConfigListener);
Jonathan Hart60e7f512017-02-10 10:24:24 -0800163 RoutingConfiguration.unregister(networkConfigService);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700164 }
165
Charles Chanc6d227e2017-02-28 15:15:17 -0800166 @Modified
167 protected void modified(ComponentContext context) {
168 if (context != null) {
169 readComponentConfiguration(context);
170 processRouterConfig();
171 }
172 }
173
174 private void readComponentConfiguration(ComponentContext context) {
175 Dictionary<?, ?> properties = context.getProperties();
176 Boolean flag;
177
178 flag = Tools.isPropertyEnabled(properties, "forceUnprovision");
179 if (flag == null) {
180 log.info("ForceUnprovision is not configured, " +
181 "using current value of {}", forceUnprovision);
182 } else {
183 forceUnprovision = flag;
184 log.info("Configured. ForceUnprovision is {}",
185 forceUnprovision ? "enabled" : "disabled");
186 }
187 }
188
kishore786b7e42016-05-19 16:25:57 +0530189 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700190 * Sets up the router interfaces if router config is available.
191 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800192 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800193 ApplicationId routingAppId =
194 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
195
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800196 Set<RoutersConfig.Router> routerConfigs =
Jonathan Hart60e7f512017-02-10 10:24:24 -0800197 RoutingConfiguration.getRouterConfigurations(networkConfigService, routingAppId);
Jonathan Hart6344f572015-12-15 08:26:25 -0800198
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800199 for (RoutersConfig.Router router : routerConfigs) {
200 DeviceId deviceId = router.controlPlaneConnectPoint().deviceId();
201
202 routers.compute(deviceId, (d, r) -> {
203 if (r == null) {
204 return createRouter(RouterInfo.from(router));
205 } else {
Charles Chanc6d227e2017-02-28 15:15:17 -0800206 r.changeConfiguration(RouterInfo.from(router), forceUnprovision);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800207 return r;
208 }
209 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800210 }
211
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800212 for (DeviceId deviceId : routers.keySet()) {
213 if (!configExists(deviceId, routerConfigs)) {
214 Router router = routers.remove(deviceId);
215 router.cleanup();
216 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800217 }
218 }
219
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800220 private boolean configExists(DeviceId deviceId, Set<RoutersConfig.Router> config) {
221 return config.stream()
222 .anyMatch(r -> r.controlPlaneConnectPoint().deviceId().equals(deviceId));
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800223 }
224
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800225 private Router createRouter(RouterInfo info) {
226 return new Router(info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800227 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800228 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800229 this::provisionInterface,
Charles Chanc6d227e2017-02-28 15:15:17 -0800230 this::unprovisionInterface,
231 forceUnprovision);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800232 }
233
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800234 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800235 updateInterfaceObjectives(intf, true);
236 }
237
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800238 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800239 updateInterfaceObjectives(intf, false);
240 }
241
242 /**
243 * Installs or removes flow objectives relating to a give interface.
244 *
245 * @param intf interface to change objectives for
246 * @param install true to install the objectives, false to remove them
247 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800248 private void updateInterfaceObjectives(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700249 updateInterfaceForwarding(intf, install);
250 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800251 }
252
kishore71a27532016-03-16 20:23:49 +0530253 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800254 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530255 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800256 * @param request provisioning request containing router and interface
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800257 * @param install true to install the objectives, false to remove them
258 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800259 private void updateInterfaceForwarding(InterfaceProvisionRequest request, boolean install) {
260 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800261 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800262
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700263 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800264
265 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Ray Milkey048bf9a2017-05-12 14:31:50 -0700266 for (InterfaceIpAddress ip : intf.ipAddressesList()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800267 // create nextObjectives for forwarding to this interface and the
268 // controlPlaneConnectPoint
269 int cpNextId, intfNextId;
270 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530271 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800272 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530273 true, install);
274 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800275 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530276 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800277 } else {
kishore71a27532016-03-16 20:23:49 +0530278 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
279 intf.vlan(), false, install);
280 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
281 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800282 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530283 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
284 TrafficSelector selector;
285 // IP traffic toward the router.
286 selector = buildIPDstSelector(
287 ip.ipAddress().toIpPrefix(),
288 intf.connectPoint().port(),
289 null,
290 intf.mac(),
291 intf.vlan()
292 );
293 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
294 // IP traffic from the router.
295 selector = buildIPSrcSelector(
296 ip.ipAddress().toIpPrefix(),
297 controlPlanePort,
298 intf.mac(),
299 null,
300 intf.vlan()
301 );
302 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
303 // We build the punt treatment.
304 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800305 .punt()
306 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530307 // Handling of neighbour discovery protocols.
308 // IPv4 traffic - we have to deal with the ARP protocol.
309 // IPv6 traffic - we have to deal with the NDP protocol.
310 if (ip.ipAddress().isIp4()) {
311 // ARP traffic towards the router.
312 selector = buildArpSelector(
313 intf.connectPoint().port(),
314 intf.vlan(),
315 null,
316 null
317 );
318 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
319 // ARP traffic from the router.
320 selector = buildArpSelector(
321 controlPlanePort,
322 intf.vlan(),
323 ip.ipAddress().getIp4Address(),
324 intf.mac()
325 );
326 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
327 } else {
328 // Neighbour solicitation traffic towards the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800329 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530330 selector = buildNdpSelector(
331 intf.connectPoint().port(),
332 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800333 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800334 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800335 NEIGHBOR_SOLICITATION,
336 null
337 );
338 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
339 // Neighbour solicitation traffic towards the router.
340 // This flow is for the link local address.
341 selector = buildNdpSelector(
342 intf.connectPoint().port(),
343 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800344 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800345 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800346 NEIGHBOR_SOLICITATION,
347 null
348 );
349 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
350 // Neighbour solicitation traffic towards the router.
351 // This flow is for the solicitation node address of
352 // the global unicast address.
353 selector = buildNdpSelector(
354 intf.connectPoint().port(),
355 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800356 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800357 Ip6Address.valueOf(getSolicitNodeAddress(ip.ipAddress().toOctets())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800358 NEIGHBOR_SOLICITATION,
359 null
360 );
361 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
362 // Neighbour solicitation traffic towards the router.
363 // This flow is for the solicitation node address of
364 // the link local address.
365 selector = buildNdpSelector(
366 intf.connectPoint().port(),
367 intf.vlan(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800368 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800369 Ip6Address.valueOf(
370 getSolicitNodeAddress(getLinkLocalAddress(intf.mac().toBytes()))
371 ).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530372 NEIGHBOR_SOLICITATION,
373 null
374 );
375 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
376 // Neighbour solicitation traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800377 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530378 selector = buildNdpSelector(
379 controlPlanePort,
380 intf.vlan(),
381 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800382 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530383 NEIGHBOR_SOLICITATION,
384 intf.mac()
385 );
386 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800387 // Neighbour solicitation traffic from the router.
388 // This flow is for the link local address.
389 selector = buildNdpSelector(
390 controlPlanePort,
391 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800392 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800393 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800394 NEIGHBOR_SOLICITATION,
395 intf.mac()
396 );
397 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
398 // Neighbour advertisement traffic towards the router.
399 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530400 selector = buildNdpSelector(
401 intf.connectPoint().port(),
402 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800403 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800404 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800405 NEIGHBOR_ADVERTISEMENT,
406 null
407 );
408 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
409 // Neighbour advertisement traffic towards the router.
410 // This flow is for the link local address
411 selector = buildNdpSelector(
412 intf.connectPoint().port(),
413 intf.vlan(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530414 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800415 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530416 NEIGHBOR_ADVERTISEMENT,
417 null
418 );
419 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
420 // Neighbour advertisement traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800421 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530422 selector = buildNdpSelector(
423 controlPlanePort,
424 intf.vlan(),
425 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800426 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530427 NEIGHBOR_ADVERTISEMENT,
428 intf.mac()
429 );
430 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800431 // Neighbour advertisement traffic from the router.
432 // This flow is for the link local address
433 selector = buildNdpSelector(
434 controlPlanePort,
435 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800436 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800437 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800438 NEIGHBOR_ADVERTISEMENT,
439 intf.mac()
440 );
441 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530442 }
443 // Finally we push the fwd objectives through the flow objective service.
444 fwdToSend.stream().forEach(forwardingObjective ->
445 flowObjectiveService.forward(deviceId, forwardingObjective)
446 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800447 }
448 }
449
kishore71a27532016-03-16 20:23:49 +0530450 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700451 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530452 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800453 * @param request provisioning request containing router and interface
kishore71a27532016-03-16 20:23:49 +0530454 * @param install true to create an add objective, false to create a remove
455 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800456 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800457 private void updateOspfForwarding(InterfaceProvisionRequest request, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800458 // TODO IPv6 support has not been implemented yet
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800459 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800460 log.debug("{} OSPF flows for {}", operation(install), intf);
461
Jonathan Hartea492382016-01-13 09:33:13 -0800462 // OSPF to router
463 TrafficSelector toSelector = DefaultTrafficSelector.builder()
464 .matchInPort(intf.connectPoint().port())
465 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
466 .matchVlanId(intf.vlan())
467 .matchIPProtocol((byte) OSPF_IP_PROTO)
468 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800469
Saurav Das49cb5a12016-01-16 22:54:07 -0800470 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700471 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800472 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800473 int cpNextId;
474 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530475 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800476 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530477 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800478 } else {
kishore71a27532016-03-16 20:23:49 +0530479 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
480 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800481 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700482 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800483 buildForwardingObjective(toSelector, null, cpNextId,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800484 install ? request.info().ospfEnabled() : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800485 }
486
487 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800488 * Creates a next objective for forwarding to a port. Handles metadata for
489 * some pipelines that require vlan information for egress port.
490 *
491 * @param deviceId the device on which the next objective is being created
492 * @param portNumber the egress port
493 * @param vlanId vlan information for egress port
494 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530495 * @param install true to create an add next objective, false to create a remove
496 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800497 * @return nextId of the next objective created
498 */
kishore71a27532016-03-16 20:23:49 +0530499 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
500 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800501 int nextId = flowObjectiveService.allocateNextId();
502 NextObjective.Builder nextObjBuilder = DefaultNextObjective
503 .builder().withId(nextId)
504 .withType(NextObjective.Type.SIMPLE)
505 .fromApp(appId);
506
507 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
508 if (popVlan) {
509 ttBuilder.popVlan();
510 }
511 ttBuilder.setOutput(portNumber);
512
513 // setup metadata to pass to nextObjective - indicate the vlan on egress
514 // if needed by the switch pipeline.
515 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
516 metabuilder.matchVlanId(vlanId);
517
518 nextObjBuilder.withMeta(metabuilder.build());
519 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700520 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800521 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530522 if (install) {
523 flowObjectiveService.next(deviceId, nextObjBuilder.add());
524 } else {
525 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
526 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800527 return nextId;
528 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700529
Saurav Das49cb5a12016-01-16 22:54:07 -0800530 /**
531 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800532 *
533 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800534 * @param treatment treatment to apply to packet, can be null
535 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800536 * @param add true to create an add objective, false to create a remove
537 * objective
538 * @return forwarding objective
539 */
540 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
541 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800542 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530543 boolean add,
544 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800545 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
546 fobBuilder.withSelector(selector);
547 if (treatment != null) {
548 fobBuilder.withTreatment(treatment);
549 }
550 if (nextId != -1) {
551 fobBuilder.nextStep(nextId);
552 }
553 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530554 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800555 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800556
557 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800558 }
559
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800560 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
561 MacAddress srcMac,
562 MacAddress dstMac,
563 VlanId vlanId) {
564 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
565 if (inPort != null) {
566 selectorBuilder.matchInPort(inPort);
567 }
568 if (srcMac != null) {
569 selectorBuilder.matchEthSrc(srcMac);
570 }
571 if (dstMac != null) {
572 selectorBuilder.matchEthDst(dstMac);
573 }
574 if (vlanId != null) {
575 selectorBuilder.matchVlanId(vlanId);
576 }
577 return selectorBuilder;
578 }
579
580 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
581 PortNumber inPort,
582 MacAddress srcMac,
583 MacAddress dstMac,
584 VlanId vlanId) {
585 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
586 if (dstIp.isIp4()) {
587 selector.matchEthType(TYPE_IPV4);
588 selector.matchIPDst(dstIp);
589 } else {
590 selector.matchEthType(TYPE_IPV6);
591 selector.matchIPv6Dst(dstIp);
592 }
593 return selector.build();
594 }
595
596 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
597 PortNumber inPort,
598 MacAddress srcMac,
599 MacAddress dstMac,
600 VlanId vlanId) {
601 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
602 if (srcIp.isIp4()) {
603 selector.matchEthType(TYPE_IPV4);
604 selector.matchIPSrc(srcIp);
605 } else {
606 selector.matchEthType(TYPE_IPV6);
607 selector.matchIPv6Src(srcIp);
608 }
609 return selector.build();
610 }
611
612 static TrafficSelector buildArpSelector(PortNumber inPort,
613 VlanId vlanId,
614 Ip4Address arpSpa,
615 MacAddress srcMac) {
616 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
617 selector.matchEthType(TYPE_ARP);
618 if (arpSpa != null) {
619 selector.matchArpSpa(arpSpa);
620 }
621 if (srcMac != null) {
622 selector.matchEthSrc(srcMac);
623 }
624 return selector.build();
625 }
626
627 static TrafficSelector buildNdpSelector(PortNumber inPort,
628 VlanId vlanId,
629 IpPrefix srcIp,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800630 IpPrefix dstIp,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800631 byte subProto,
632 MacAddress srcMac) {
633 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
634 selector.matchEthType(TYPE_IPV6)
635 .matchIPProtocol(PROTOCOL_ICMP6)
636 .matchIcmpv6Type(subProto);
637 if (srcIp != null) {
638 selector.matchIPv6Src(srcIp);
639 }
Pier Luigi2b1ad872017-01-31 09:35:42 -0800640 if (dstIp != null) {
Pier Luigi9f765dc2017-02-03 13:35:23 -0800641 selector.matchIPv6Dst(dstIp);
Pier Luigi2b1ad872017-01-31 09:35:42 -0800642 }
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800643 if (srcMac != null) {
644 selector.matchEthSrc(srcMac);
645 }
646 return selector.build();
647 }
648
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800649 private String operation(boolean install) {
650 return install ? "Installing" : "Removing";
651 }
652
Jonathan Hartea492382016-01-13 09:33:13 -0800653 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800654 * Listener for network config events.
655 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800656 private class InternalNetworkConfigListener implements NetworkConfigListener {
657 @Override
658 public void event(NetworkConfigEvent event) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800659 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS) ||
660 event.configClass().equals(RoutersConfig.class)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800661 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700662 case CONFIG_ADDED:
663 case CONFIG_UPDATED:
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800664 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800665 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700666 break;
667 case CONFIG_REGISTERED:
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700668 case CONFIG_UNREGISTERED:
669 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530670 default:
671 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800672 }
673 }
674 }
675 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800676}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530677