blob: 0d7adf5abfac2980e800ed69a10486821df7cfd9 [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;
Ray Milkey4694e062018-10-31 13:17:18 -070082import static org.onosproject.routing.cpr.OsgiPropertyConstants.FORCE_UNPROVISION;
83import static org.onosproject.routing.cpr.OsgiPropertyConstants.FORCE_UNPROVISION_DEFAULT;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070084import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080085
86/**
87 * Manages connectivity between peers redirecting control traffic to a routing
88 * control plane available on the dataplane.
89 */
Ray Milkey4694e062018-10-31 13:17:18 -070090@Component(
91 immediate = true,
92 property = {
93 FORCE_UNPROVISION + ":Boolean=" + FORCE_UNPROVISION_DEFAULT
94 }
95)
Jonathan Hart6344f572015-12-15 08:26:25 -080096public class ControlPlaneRedirectManager {
97
98 private final Logger log = getLogger(getClass());
99
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800100 public static final short ASSIGNED_VLAN = 4094;
101
Charles Chand0fd5dc2016-02-16 23:14:49 -0800102 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +0530103 private static final int IPV4_PRIORITY = 2000;
104 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530105 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -0800106 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -0800107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6344f572015-12-15 08:26:25 -0800109 protected CoreService coreService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6344f572015-12-15 08:26:25 -0800112 protected DeviceService deviceService;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6344f572015-12-15 08:26:25 -0800115 protected InterfaceService interfaceService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6344f572015-12-15 08:26:25 -0800118 protected FlowObjectiveService flowObjectiveService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart60e7f512017-02-10 10:24:24 -0800121 protected NetworkConfigRegistry networkConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -0800122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800124 protected MastershipService mastershipService;
125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800127 protected HostService hostService;
128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kishore786b7e42016-05-19 16:25:57 +0530130 protected ApplicationService applicationService;
131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Charles Chanc6d227e2017-02-28 15:15:17 -0800133 protected ComponentConfigService cfgService;
134
Ray Milkey4694e062018-10-31 13:17:18 -0700135 /** Force unprovision when the device goes offline. */
136 private boolean forceUnprovision = FORCE_UNPROVISION_DEFAULT;
Charles Chanc6d227e2017-02-28 15:15:17 -0800137
Jonathan Harte7327042017-02-02 13:11:25 -0800138 private static final String APP_NAME = "org.onosproject.cpr";
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700139 private ApplicationId appId;
140
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700141 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
142
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800143 private Map<DeviceId, Router> routers = new ConcurrentHashMap<>();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700144
Jonathan Hart6344f572015-12-15 08:26:25 -0800145 private final InternalNetworkConfigListener networkConfigListener =
146 new InternalNetworkConfigListener();
147
148 @Activate
Charles Chanc6d227e2017-02-28 15:15:17 -0800149 protected void activate(ComponentContext context) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800150 this.appId = coreService.registerApplication(APP_NAME);
151
Charles Chanc6d227e2017-02-28 15:15:17 -0800152 cfgService.registerProperties(getClass());
153 modified(context);
154
Jonathan Hart60e7f512017-02-10 10:24:24 -0800155 RoutingConfiguration.register(networkConfigService);
156
Jonathan Hart6344f572015-12-15 08:26:25 -0800157 networkConfigService.addListener(networkConfigListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700158
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800159 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800160
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800161 applicationService.registerDeactivateHook(this.appId,
162 () -> routers.forEach((d, r) -> r.cleanup()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800163 }
164
165 @Deactivate
Jonathan Harte7327042017-02-02 13:11:25 -0800166 protected void deactivate() {
Charles Chanc6d227e2017-02-28 15:15:17 -0800167 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart6344f572015-12-15 08:26:25 -0800168 networkConfigService.removeListener(networkConfigListener);
Jonathan Hart60e7f512017-02-10 10:24:24 -0800169 RoutingConfiguration.unregister(networkConfigService);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700170 }
171
Charles Chanc6d227e2017-02-28 15:15:17 -0800172 @Modified
173 protected void modified(ComponentContext context) {
174 if (context != null) {
175 readComponentConfiguration(context);
176 processRouterConfig();
177 }
178 }
179
180 private void readComponentConfiguration(ComponentContext context) {
181 Dictionary<?, ?> properties = context.getProperties();
182 Boolean flag;
183
Ray Milkey4694e062018-10-31 13:17:18 -0700184 flag = Tools.isPropertyEnabled(properties, FORCE_UNPROVISION);
Charles Chanc6d227e2017-02-28 15:15:17 -0800185 if (flag == null) {
186 log.info("ForceUnprovision is not configured, " +
187 "using current value of {}", forceUnprovision);
188 } else {
189 forceUnprovision = flag;
190 log.info("Configured. ForceUnprovision is {}",
191 forceUnprovision ? "enabled" : "disabled");
192 }
193 }
194
kishore786b7e42016-05-19 16:25:57 +0530195 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700196 * Sets up the router interfaces if router config is available.
197 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800198 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800199 ApplicationId routingAppId =
200 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
201
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800202 Set<RoutersConfig.Router> routerConfigs =
Jonathan Hart60e7f512017-02-10 10:24:24 -0800203 RoutingConfiguration.getRouterConfigurations(networkConfigService, routingAppId);
Jonathan Hart6344f572015-12-15 08:26:25 -0800204
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800205 for (RoutersConfig.Router router : routerConfigs) {
206 DeviceId deviceId = router.controlPlaneConnectPoint().deviceId();
207
208 routers.compute(deviceId, (d, r) -> {
209 if (r == null) {
210 return createRouter(RouterInfo.from(router));
211 } else {
Charles Chanc6d227e2017-02-28 15:15:17 -0800212 r.changeConfiguration(RouterInfo.from(router), forceUnprovision);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800213 return r;
214 }
215 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800216 }
217
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800218 for (DeviceId deviceId : routers.keySet()) {
219 if (!configExists(deviceId, routerConfigs)) {
220 Router router = routers.remove(deviceId);
221 router.cleanup();
222 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800223 }
224 }
225
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800226 private boolean configExists(DeviceId deviceId, Set<RoutersConfig.Router> config) {
227 return config.stream()
228 .anyMatch(r -> r.controlPlaneConnectPoint().deviceId().equals(deviceId));
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800229 }
230
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800231 private Router createRouter(RouterInfo info) {
232 return new Router(info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800233 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800234 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800235 this::provisionInterface,
Charles Chanc6d227e2017-02-28 15:15:17 -0800236 this::unprovisionInterface,
237 forceUnprovision);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800238 }
239
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800240 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800241 updateInterfaceObjectives(intf, true);
242 }
243
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800244 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800245 updateInterfaceObjectives(intf, false);
246 }
247
248 /**
249 * Installs or removes flow objectives relating to a give interface.
250 *
251 * @param intf interface to change objectives for
252 * @param install true to install the objectives, false to remove them
253 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800254 private void updateInterfaceObjectives(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700255 updateInterfaceForwarding(intf, install);
256 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800257 }
258
kishore71a27532016-03-16 20:23:49 +0530259 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800260 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530261 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800262 * @param request provisioning request containing router and interface
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800263 * @param install true to install the objectives, false to remove them
264 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800265 private void updateInterfaceForwarding(InterfaceProvisionRequest request, boolean install) {
266 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800267 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800268
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700269 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800270
271 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Ray Milkey048bf9a2017-05-12 14:31:50 -0700272 for (InterfaceIpAddress ip : intf.ipAddressesList()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800273 // create nextObjectives for forwarding to this interface and the
274 // controlPlaneConnectPoint
275 int cpNextId, intfNextId;
276 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530277 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800278 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530279 true, install);
280 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800281 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530282 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800283 } else {
kishore71a27532016-03-16 20:23:49 +0530284 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
285 intf.vlan(), false, install);
286 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
287 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800288 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530289 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
290 TrafficSelector selector;
291 // IP traffic toward the router.
292 selector = buildIPDstSelector(
293 ip.ipAddress().toIpPrefix(),
294 intf.connectPoint().port(),
295 null,
296 intf.mac(),
297 intf.vlan()
298 );
299 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
300 // IP traffic from the router.
301 selector = buildIPSrcSelector(
302 ip.ipAddress().toIpPrefix(),
303 controlPlanePort,
304 intf.mac(),
305 null,
306 intf.vlan()
307 );
308 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
309 // We build the punt treatment.
310 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800311 .punt()
312 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530313 // Handling of neighbour discovery protocols.
314 // IPv4 traffic - we have to deal with the ARP protocol.
315 // IPv6 traffic - we have to deal with the NDP protocol.
316 if (ip.ipAddress().isIp4()) {
317 // ARP traffic towards the router.
318 selector = buildArpSelector(
319 intf.connectPoint().port(),
320 intf.vlan(),
321 null,
322 null
323 );
324 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
325 // ARP traffic from the router.
326 selector = buildArpSelector(
327 controlPlanePort,
328 intf.vlan(),
329 ip.ipAddress().getIp4Address(),
330 intf.mac()
331 );
332 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
333 } else {
334 // Neighbour solicitation traffic towards the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800335 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530336 selector = buildNdpSelector(
337 intf.connectPoint().port(),
338 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800339 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800340 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800341 NEIGHBOR_SOLICITATION,
342 null
343 );
344 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
345 // Neighbour solicitation traffic towards the router.
346 // This flow is for the link local address.
347 selector = buildNdpSelector(
348 intf.connectPoint().port(),
349 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800350 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800351 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800352 NEIGHBOR_SOLICITATION,
353 null
354 );
355 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
356 // Neighbour solicitation traffic towards the router.
357 // This flow is for the solicitation node address of
358 // the global unicast address.
359 selector = buildNdpSelector(
360 intf.connectPoint().port(),
361 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800362 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800363 Ip6Address.valueOf(getSolicitNodeAddress(ip.ipAddress().toOctets())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800364 NEIGHBOR_SOLICITATION,
365 null
366 );
367 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
368 // Neighbour solicitation traffic towards the router.
369 // This flow is for the solicitation node address of
370 // the link local address.
371 selector = buildNdpSelector(
372 intf.connectPoint().port(),
373 intf.vlan(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800374 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800375 Ip6Address.valueOf(
376 getSolicitNodeAddress(getLinkLocalAddress(intf.mac().toBytes()))
377 ).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530378 NEIGHBOR_SOLICITATION,
379 null
380 );
381 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
382 // Neighbour solicitation traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800383 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530384 selector = buildNdpSelector(
385 controlPlanePort,
386 intf.vlan(),
387 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800388 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530389 NEIGHBOR_SOLICITATION,
390 intf.mac()
391 );
392 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800393 // Neighbour solicitation traffic from the router.
394 // This flow is for the link local address.
395 selector = buildNdpSelector(
396 controlPlanePort,
397 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800398 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800399 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800400 NEIGHBOR_SOLICITATION,
401 intf.mac()
402 );
403 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
404 // Neighbour advertisement traffic towards the router.
405 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530406 selector = buildNdpSelector(
407 intf.connectPoint().port(),
408 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800409 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800410 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800411 NEIGHBOR_ADVERTISEMENT,
412 null
413 );
414 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
415 // Neighbour advertisement traffic towards the router.
416 // This flow is for the link local address
417 selector = buildNdpSelector(
418 intf.connectPoint().port(),
419 intf.vlan(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530420 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800421 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530422 NEIGHBOR_ADVERTISEMENT,
423 null
424 );
425 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
426 // Neighbour advertisement traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800427 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530428 selector = buildNdpSelector(
429 controlPlanePort,
430 intf.vlan(),
431 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800432 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530433 NEIGHBOR_ADVERTISEMENT,
434 intf.mac()
435 );
436 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800437 // Neighbour advertisement traffic from the router.
438 // This flow is for the link local address
439 selector = buildNdpSelector(
440 controlPlanePort,
441 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800442 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800443 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800444 NEIGHBOR_ADVERTISEMENT,
445 intf.mac()
446 );
447 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530448 }
449 // Finally we push the fwd objectives through the flow objective service.
450 fwdToSend.stream().forEach(forwardingObjective ->
451 flowObjectiveService.forward(deviceId, forwardingObjective)
452 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800453 }
454 }
455
kishore71a27532016-03-16 20:23:49 +0530456 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700457 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530458 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800459 * @param request provisioning request containing router and interface
kishore71a27532016-03-16 20:23:49 +0530460 * @param install true to create an add objective, false to create a remove
461 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800462 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800463 private void updateOspfForwarding(InterfaceProvisionRequest request, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800464 // TODO IPv6 support has not been implemented yet
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800465 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800466 log.debug("{} OSPF flows for {}", operation(install), intf);
467
Jonathan Hartea492382016-01-13 09:33:13 -0800468 // OSPF to router
469 TrafficSelector toSelector = DefaultTrafficSelector.builder()
470 .matchInPort(intf.connectPoint().port())
471 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
472 .matchVlanId(intf.vlan())
473 .matchIPProtocol((byte) OSPF_IP_PROTO)
474 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800475
Saurav Das49cb5a12016-01-16 22:54:07 -0800476 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700477 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800478 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800479 int cpNextId;
480 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530481 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800482 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530483 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800484 } else {
kishore71a27532016-03-16 20:23:49 +0530485 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
486 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800487 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700488 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800489 buildForwardingObjective(toSelector, null, cpNextId,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800490 install ? request.info().ospfEnabled() : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800491 }
492
493 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800494 * Creates a next objective for forwarding to a port. Handles metadata for
495 * some pipelines that require vlan information for egress port.
496 *
497 * @param deviceId the device on which the next objective is being created
498 * @param portNumber the egress port
499 * @param vlanId vlan information for egress port
500 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530501 * @param install true to create an add next objective, false to create a remove
502 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800503 * @return nextId of the next objective created
504 */
kishore71a27532016-03-16 20:23:49 +0530505 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
506 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800507 int nextId = flowObjectiveService.allocateNextId();
508 NextObjective.Builder nextObjBuilder = DefaultNextObjective
509 .builder().withId(nextId)
510 .withType(NextObjective.Type.SIMPLE)
511 .fromApp(appId);
512
513 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
514 if (popVlan) {
515 ttBuilder.popVlan();
516 }
517 ttBuilder.setOutput(portNumber);
518
519 // setup metadata to pass to nextObjective - indicate the vlan on egress
520 // if needed by the switch pipeline.
521 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
522 metabuilder.matchVlanId(vlanId);
523
524 nextObjBuilder.withMeta(metabuilder.build());
525 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700526 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800527 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530528 if (install) {
529 flowObjectiveService.next(deviceId, nextObjBuilder.add());
530 } else {
531 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
532 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800533 return nextId;
534 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700535
Saurav Das49cb5a12016-01-16 22:54:07 -0800536 /**
537 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800538 *
539 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800540 * @param treatment treatment to apply to packet, can be null
541 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800542 * @param add true to create an add objective, false to create a remove
543 * objective
544 * @return forwarding objective
545 */
546 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
547 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800548 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530549 boolean add,
550 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800551 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
552 fobBuilder.withSelector(selector);
553 if (treatment != null) {
554 fobBuilder.withTreatment(treatment);
555 }
556 if (nextId != -1) {
557 fobBuilder.nextStep(nextId);
558 }
559 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530560 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800561 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800562
563 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800564 }
565
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800566 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
567 MacAddress srcMac,
568 MacAddress dstMac,
569 VlanId vlanId) {
570 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
571 if (inPort != null) {
572 selectorBuilder.matchInPort(inPort);
573 }
574 if (srcMac != null) {
575 selectorBuilder.matchEthSrc(srcMac);
576 }
577 if (dstMac != null) {
578 selectorBuilder.matchEthDst(dstMac);
579 }
580 if (vlanId != null) {
581 selectorBuilder.matchVlanId(vlanId);
582 }
583 return selectorBuilder;
584 }
585
586 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
587 PortNumber inPort,
588 MacAddress srcMac,
589 MacAddress dstMac,
590 VlanId vlanId) {
591 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
592 if (dstIp.isIp4()) {
593 selector.matchEthType(TYPE_IPV4);
594 selector.matchIPDst(dstIp);
595 } else {
596 selector.matchEthType(TYPE_IPV6);
597 selector.matchIPv6Dst(dstIp);
598 }
599 return selector.build();
600 }
601
602 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
603 PortNumber inPort,
604 MacAddress srcMac,
605 MacAddress dstMac,
606 VlanId vlanId) {
607 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
608 if (srcIp.isIp4()) {
609 selector.matchEthType(TYPE_IPV4);
610 selector.matchIPSrc(srcIp);
611 } else {
612 selector.matchEthType(TYPE_IPV6);
613 selector.matchIPv6Src(srcIp);
614 }
615 return selector.build();
616 }
617
618 static TrafficSelector buildArpSelector(PortNumber inPort,
619 VlanId vlanId,
620 Ip4Address arpSpa,
621 MacAddress srcMac) {
622 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
623 selector.matchEthType(TYPE_ARP);
624 if (arpSpa != null) {
625 selector.matchArpSpa(arpSpa);
626 }
627 if (srcMac != null) {
628 selector.matchEthSrc(srcMac);
629 }
630 return selector.build();
631 }
632
633 static TrafficSelector buildNdpSelector(PortNumber inPort,
634 VlanId vlanId,
635 IpPrefix srcIp,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800636 IpPrefix dstIp,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800637 byte subProto,
638 MacAddress srcMac) {
639 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
640 selector.matchEthType(TYPE_IPV6)
641 .matchIPProtocol(PROTOCOL_ICMP6)
642 .matchIcmpv6Type(subProto);
643 if (srcIp != null) {
644 selector.matchIPv6Src(srcIp);
645 }
Pier Luigi2b1ad872017-01-31 09:35:42 -0800646 if (dstIp != null) {
Pier Luigi9f765dc2017-02-03 13:35:23 -0800647 selector.matchIPv6Dst(dstIp);
Pier Luigi2b1ad872017-01-31 09:35:42 -0800648 }
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800649 if (srcMac != null) {
650 selector.matchEthSrc(srcMac);
651 }
652 return selector.build();
653 }
654
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800655 private String operation(boolean install) {
656 return install ? "Installing" : "Removing";
657 }
658
Jonathan Hartea492382016-01-13 09:33:13 -0800659 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800660 * Listener for network config events.
661 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800662 private class InternalNetworkConfigListener implements NetworkConfigListener {
663 @Override
664 public void event(NetworkConfigEvent event) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800665 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS) ||
666 event.configClass().equals(RoutersConfig.class)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800667 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700668 case CONFIG_ADDED:
669 case CONFIG_UPDATED:
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800670 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800671 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700672 break;
673 case CONFIG_REGISTERED:
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700674 case CONFIG_UNREGISTERED:
675 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530676 default:
677 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800678 }
679 }
680 }
681 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800682}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530683