blob: 5c9d65a6c553ed57bca2c788fdfe010e343fb970 [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.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Charles Chanc6d227e2017-02-28 15:15:17 -080024import org.apache.felix.scr.annotations.Modified;
25import org.apache.felix.scr.annotations.Property;
Jonathan Hart6344f572015-12-15 08:26:25 -080026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.onlab.packet.EthType;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053029import org.onlab.packet.Ip4Address;
Pier Luigi2b1ad872017-01-31 09:35:42 -080030import org.onlab.packet.Ip6Address;
Charles Chand0fd5dc2016-02-16 23:14:49 -080031import org.onlab.packet.IpPrefix;
32import org.onlab.packet.MacAddress;
Saurav Das49cb5a12016-01-16 22:54:07 -080033import org.onlab.packet.VlanId;
Charles Chanc6d227e2017-02-28 15:15:17 -080034import org.onlab.util.Tools;
kishore786b7e42016-05-19 16:25:57 +053035import org.onosproject.app.ApplicationService;
Charles Chanc6d227e2017-02-28 15:15:17 -080036import org.onosproject.cfg.ComponentConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -080037import org.onosproject.core.ApplicationId;
38import org.onosproject.core.CoreService;
39import org.onosproject.incubator.net.intf.Interface;
40import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080041import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080042import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080043import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080044import org.onosproject.net.PortNumber;
45import org.onosproject.net.config.NetworkConfigEvent;
46import org.onosproject.net.config.NetworkConfigListener;
Jonathan Hart60e7f512017-02-10 10:24:24 -080047import org.onosproject.net.config.NetworkConfigRegistry;
Jonathan Hart6344f572015-12-15 08:26:25 -080048import org.onosproject.net.device.DeviceService;
49import org.onosproject.net.flow.DefaultTrafficSelector;
50import org.onosproject.net.flow.DefaultTrafficTreatment;
51import org.onosproject.net.flow.TrafficSelector;
52import org.onosproject.net.flow.TrafficTreatment;
53import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080054import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Hart6344f572015-12-15 08:26:25 -080055import org.onosproject.net.flowobjective.FlowObjectiveService;
56import org.onosproject.net.flowobjective.ForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080057import org.onosproject.net.flowobjective.NextObjective;
Charles Chand0fd5dc2016-02-16 23:14:49 -080058import org.onosproject.net.host.HostService;
Jonathan Hart6344f572015-12-15 08:26:25 -080059import org.onosproject.net.host.InterfaceIpAddress;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080060import org.onosproject.routing.InterfaceProvisionRequest;
61import org.onosproject.routing.Router;
Jonathan Hart60e7f512017-02-10 10:24:24 -080062import org.onosproject.routing.RouterInfo;
Jonathan Hart6344f572015-12-15 08:26:25 -080063import org.onosproject.routing.RoutingService;
Jonathan Hart60e7f512017-02-10 10:24:24 -080064import org.onosproject.routing.config.RoutingConfiguration;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080065import org.onosproject.routing.config.RoutersConfig;
Charles Chanc6d227e2017-02-28 15:15:17 -080066import org.osgi.service.component.ComponentContext;
Jonathan Hart6344f572015-12-15 08:26:25 -080067import org.slf4j.Logger;
68
Charles Chanc6d227e2017-02-28 15:15:17 -080069import java.util.Dictionary;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070070import java.util.List;
71import java.util.Map;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070072import java.util.Set;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080073import java.util.concurrent.ConcurrentHashMap;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070074
Jonathan Hartf8cd0522016-10-25 07:09:55 -070075import static org.onlab.packet.Ethernet.TYPE_ARP;
76import static org.onlab.packet.Ethernet.TYPE_IPV4;
77import static org.onlab.packet.Ethernet.TYPE_IPV6;
78import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
79import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
80import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Pier Luigi2b1ad872017-01-31 09:35:42 -080081import static org.onlab.packet.IPv6.getLinkLocalAddress;
82import static org.onlab.packet.IPv6.getSolicitNodeAddress;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070083import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080084
85/**
86 * Manages connectivity between peers redirecting control traffic to a routing
87 * control plane available on the dataplane.
88 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080089@Component(immediate = true)
Jonathan Hart6344f572015-12-15 08:26:25 -080090public class ControlPlaneRedirectManager {
91
92 private final Logger log = getLogger(getClass());
93
Jonathan Hartf4bd0482017-01-27 15:11:18 -080094 public static final short ASSIGNED_VLAN = 4094;
95
Charles Chand0fd5dc2016-02-16 23:14:49 -080096 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +053097 private static final int IPV4_PRIORITY = 2000;
98 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053099 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -0800100 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -0800101
Jonathan Hart6344f572015-12-15 08:26:25 -0800102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected CoreService coreService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected DeviceService deviceService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected InterfaceService interfaceService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected FlowObjectiveService flowObjectiveService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart60e7f512017-02-10 10:24:24 -0800115 protected NetworkConfigRegistry networkConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -0800116
Charles Chand0fd5dc2016-02-16 23:14:49 -0800117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected MastershipService mastershipService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected HostService hostService;
122
kishore786b7e42016-05-19 16:25:57 +0530123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected ApplicationService applicationService;
125
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chanc6d227e2017-02-28 15:15:17 -0800127 protected ComponentConfigService cfgService;
128
129 @Property(name = "forceUnprovision", boolValue = false,
130 label = "Force unprovision when the device goes offline")
131 private boolean forceUnprovision = false;
132
Jonathan Harte7327042017-02-02 13:11:25 -0800133 private static final String APP_NAME = "org.onosproject.cpr";
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700134 private ApplicationId appId;
135
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700136 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
137
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800138 private Map<DeviceId, Router> routers = new ConcurrentHashMap<>();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700139
Jonathan Hart6344f572015-12-15 08:26:25 -0800140 private final InternalNetworkConfigListener networkConfigListener =
141 new InternalNetworkConfigListener();
142
143 @Activate
Charles Chanc6d227e2017-02-28 15:15:17 -0800144 protected void activate(ComponentContext context) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800145 this.appId = coreService.registerApplication(APP_NAME);
146
Charles Chanc6d227e2017-02-28 15:15:17 -0800147 cfgService.registerProperties(getClass());
148 modified(context);
149
Jonathan Hart60e7f512017-02-10 10:24:24 -0800150 RoutingConfiguration.register(networkConfigService);
151
Jonathan Hart6344f572015-12-15 08:26:25 -0800152 networkConfigService.addListener(networkConfigListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700153
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800154 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800155
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800156 applicationService.registerDeactivateHook(this.appId,
157 () -> routers.forEach((d, r) -> r.cleanup()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800158 }
159
160 @Deactivate
Jonathan Harte7327042017-02-02 13:11:25 -0800161 protected void deactivate() {
Charles Chanc6d227e2017-02-28 15:15:17 -0800162 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart6344f572015-12-15 08:26:25 -0800163 networkConfigService.removeListener(networkConfigListener);
Jonathan Hart60e7f512017-02-10 10:24:24 -0800164 RoutingConfiguration.unregister(networkConfigService);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700165 }
166
Charles Chanc6d227e2017-02-28 15:15:17 -0800167 @Modified
168 protected void modified(ComponentContext context) {
169 if (context != null) {
170 readComponentConfiguration(context);
171 processRouterConfig();
172 }
173 }
174
175 private void readComponentConfiguration(ComponentContext context) {
176 Dictionary<?, ?> properties = context.getProperties();
177 Boolean flag;
178
179 flag = Tools.isPropertyEnabled(properties, "forceUnprovision");
180 if (flag == null) {
181 log.info("ForceUnprovision is not configured, " +
182 "using current value of {}", forceUnprovision);
183 } else {
184 forceUnprovision = flag;
185 log.info("Configured. ForceUnprovision is {}",
186 forceUnprovision ? "enabled" : "disabled");
187 }
188 }
189
kishore786b7e42016-05-19 16:25:57 +0530190 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700191 * Sets up the router interfaces if router config is available.
192 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800193 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800194 ApplicationId routingAppId =
195 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
196
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800197 Set<RoutersConfig.Router> routerConfigs =
Jonathan Hart60e7f512017-02-10 10:24:24 -0800198 RoutingConfiguration.getRouterConfigurations(networkConfigService, routingAppId);
Jonathan Hart6344f572015-12-15 08:26:25 -0800199
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800200 for (RoutersConfig.Router router : routerConfigs) {
201 DeviceId deviceId = router.controlPlaneConnectPoint().deviceId();
202
203 routers.compute(deviceId, (d, r) -> {
204 if (r == null) {
205 return createRouter(RouterInfo.from(router));
206 } else {
Charles Chanc6d227e2017-02-28 15:15:17 -0800207 r.changeConfiguration(RouterInfo.from(router), forceUnprovision);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800208 return r;
209 }
210 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800211 }
212
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800213 for (DeviceId deviceId : routers.keySet()) {
214 if (!configExists(deviceId, routerConfigs)) {
215 Router router = routers.remove(deviceId);
216 router.cleanup();
217 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800218 }
219 }
220
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800221 private boolean configExists(DeviceId deviceId, Set<RoutersConfig.Router> config) {
222 return config.stream()
223 .anyMatch(r -> r.controlPlaneConnectPoint().deviceId().equals(deviceId));
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800224 }
225
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800226 private Router createRouter(RouterInfo info) {
227 return new Router(info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800228 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800229 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800230 this::provisionInterface,
Charles Chanc6d227e2017-02-28 15:15:17 -0800231 this::unprovisionInterface,
232 forceUnprovision);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800233 }
234
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800235 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800236 updateInterfaceObjectives(intf, true);
237 }
238
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800239 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800240 updateInterfaceObjectives(intf, false);
241 }
242
243 /**
244 * Installs or removes flow objectives relating to a give interface.
245 *
246 * @param intf interface to change objectives for
247 * @param install true to install the objectives, false to remove them
248 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800249 private void updateInterfaceObjectives(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700250 updateInterfaceForwarding(intf, install);
251 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800252 }
253
kishore71a27532016-03-16 20:23:49 +0530254 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800255 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530256 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800257 * @param request provisioning request containing router and interface
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800258 * @param install true to install the objectives, false to remove them
259 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800260 private void updateInterfaceForwarding(InterfaceProvisionRequest request, boolean install) {
261 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800262 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800263
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700264 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800265
266 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Ray Milkey048bf9a2017-05-12 14:31:50 -0700267 for (InterfaceIpAddress ip : intf.ipAddressesList()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800268 // create nextObjectives for forwarding to this interface and the
269 // controlPlaneConnectPoint
270 int cpNextId, intfNextId;
271 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530272 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800273 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530274 true, install);
275 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800276 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530277 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800278 } else {
kishore71a27532016-03-16 20:23:49 +0530279 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
280 intf.vlan(), false, install);
281 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
282 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800283 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530284 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
285 TrafficSelector selector;
286 // IP traffic toward the router.
287 selector = buildIPDstSelector(
288 ip.ipAddress().toIpPrefix(),
289 intf.connectPoint().port(),
290 null,
291 intf.mac(),
292 intf.vlan()
293 );
294 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
295 // IP traffic from the router.
296 selector = buildIPSrcSelector(
297 ip.ipAddress().toIpPrefix(),
298 controlPlanePort,
299 intf.mac(),
300 null,
301 intf.vlan()
302 );
303 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
304 // We build the punt treatment.
305 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800306 .punt()
307 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530308 // Handling of neighbour discovery protocols.
309 // IPv4 traffic - we have to deal with the ARP protocol.
310 // IPv6 traffic - we have to deal with the NDP protocol.
311 if (ip.ipAddress().isIp4()) {
312 // ARP traffic towards the router.
313 selector = buildArpSelector(
314 intf.connectPoint().port(),
315 intf.vlan(),
316 null,
317 null
318 );
319 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
320 // ARP traffic from the router.
321 selector = buildArpSelector(
322 controlPlanePort,
323 intf.vlan(),
324 ip.ipAddress().getIp4Address(),
325 intf.mac()
326 );
327 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
328 } else {
329 // Neighbour solicitation traffic towards the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800330 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530331 selector = buildNdpSelector(
332 intf.connectPoint().port(),
333 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800334 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800335 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800336 NEIGHBOR_SOLICITATION,
337 null
338 );
339 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
340 // Neighbour solicitation traffic towards the router.
341 // This flow is for the link local address.
342 selector = buildNdpSelector(
343 intf.connectPoint().port(),
344 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800345 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800346 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800347 NEIGHBOR_SOLICITATION,
348 null
349 );
350 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
351 // Neighbour solicitation traffic towards the router.
352 // This flow is for the solicitation node address of
353 // the global unicast address.
354 selector = buildNdpSelector(
355 intf.connectPoint().port(),
356 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800357 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800358 Ip6Address.valueOf(getSolicitNodeAddress(ip.ipAddress().toOctets())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800359 NEIGHBOR_SOLICITATION,
360 null
361 );
362 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
363 // Neighbour solicitation traffic towards the router.
364 // This flow is for the solicitation node address of
365 // the link local address.
366 selector = buildNdpSelector(
367 intf.connectPoint().port(),
368 intf.vlan(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800369 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800370 Ip6Address.valueOf(
371 getSolicitNodeAddress(getLinkLocalAddress(intf.mac().toBytes()))
372 ).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530373 NEIGHBOR_SOLICITATION,
374 null
375 );
376 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
377 // Neighbour solicitation traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800378 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530379 selector = buildNdpSelector(
380 controlPlanePort,
381 intf.vlan(),
382 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800383 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530384 NEIGHBOR_SOLICITATION,
385 intf.mac()
386 );
387 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800388 // Neighbour solicitation traffic from the router.
389 // This flow is for the link local address.
390 selector = buildNdpSelector(
391 controlPlanePort,
392 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800393 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800394 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800395 NEIGHBOR_SOLICITATION,
396 intf.mac()
397 );
398 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
399 // Neighbour advertisement traffic towards the router.
400 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530401 selector = buildNdpSelector(
402 intf.connectPoint().port(),
403 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800404 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800405 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800406 NEIGHBOR_ADVERTISEMENT,
407 null
408 );
409 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
410 // Neighbour advertisement traffic towards the router.
411 // This flow is for the link local address
412 selector = buildNdpSelector(
413 intf.connectPoint().port(),
414 intf.vlan(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530415 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800416 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530417 NEIGHBOR_ADVERTISEMENT,
418 null
419 );
420 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
421 // Neighbour advertisement traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800422 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530423 selector = buildNdpSelector(
424 controlPlanePort,
425 intf.vlan(),
426 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800427 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530428 NEIGHBOR_ADVERTISEMENT,
429 intf.mac()
430 );
431 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800432 // Neighbour advertisement traffic from the router.
433 // This flow is for the link local address
434 selector = buildNdpSelector(
435 controlPlanePort,
436 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800437 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800438 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800439 NEIGHBOR_ADVERTISEMENT,
440 intf.mac()
441 );
442 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530443 }
444 // Finally we push the fwd objectives through the flow objective service.
445 fwdToSend.stream().forEach(forwardingObjective ->
446 flowObjectiveService.forward(deviceId, forwardingObjective)
447 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800448 }
449 }
450
kishore71a27532016-03-16 20:23:49 +0530451 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700452 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530453 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800454 * @param request provisioning request containing router and interface
kishore71a27532016-03-16 20:23:49 +0530455 * @param install true to create an add objective, false to create a remove
456 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800457 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800458 private void updateOspfForwarding(InterfaceProvisionRequest request, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800459 // TODO IPv6 support has not been implemented yet
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800460 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800461 log.debug("{} OSPF flows for {}", operation(install), intf);
462
Jonathan Hartea492382016-01-13 09:33:13 -0800463 // OSPF to router
464 TrafficSelector toSelector = DefaultTrafficSelector.builder()
465 .matchInPort(intf.connectPoint().port())
466 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
467 .matchVlanId(intf.vlan())
468 .matchIPProtocol((byte) OSPF_IP_PROTO)
469 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800470
Saurav Das49cb5a12016-01-16 22:54:07 -0800471 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700472 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800473 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800474 int cpNextId;
475 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530476 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800477 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530478 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800479 } else {
kishore71a27532016-03-16 20:23:49 +0530480 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
481 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800482 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700483 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800484 buildForwardingObjective(toSelector, null, cpNextId,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800485 install ? request.info().ospfEnabled() : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800486 }
487
488 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800489 * Creates a next objective for forwarding to a port. Handles metadata for
490 * some pipelines that require vlan information for egress port.
491 *
492 * @param deviceId the device on which the next objective is being created
493 * @param portNumber the egress port
494 * @param vlanId vlan information for egress port
495 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530496 * @param install true to create an add next objective, false to create a remove
497 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800498 * @return nextId of the next objective created
499 */
kishore71a27532016-03-16 20:23:49 +0530500 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
501 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800502 int nextId = flowObjectiveService.allocateNextId();
503 NextObjective.Builder nextObjBuilder = DefaultNextObjective
504 .builder().withId(nextId)
505 .withType(NextObjective.Type.SIMPLE)
506 .fromApp(appId);
507
508 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
509 if (popVlan) {
510 ttBuilder.popVlan();
511 }
512 ttBuilder.setOutput(portNumber);
513
514 // setup metadata to pass to nextObjective - indicate the vlan on egress
515 // if needed by the switch pipeline.
516 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
517 metabuilder.matchVlanId(vlanId);
518
519 nextObjBuilder.withMeta(metabuilder.build());
520 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700521 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800522 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530523 if (install) {
524 flowObjectiveService.next(deviceId, nextObjBuilder.add());
525 } else {
526 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
527 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800528 return nextId;
529 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700530
Saurav Das49cb5a12016-01-16 22:54:07 -0800531 /**
532 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800533 *
534 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800535 * @param treatment treatment to apply to packet, can be null
536 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800537 * @param add true to create an add objective, false to create a remove
538 * objective
539 * @return forwarding objective
540 */
541 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
542 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800543 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530544 boolean add,
545 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800546 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
547 fobBuilder.withSelector(selector);
548 if (treatment != null) {
549 fobBuilder.withTreatment(treatment);
550 }
551 if (nextId != -1) {
552 fobBuilder.nextStep(nextId);
553 }
554 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530555 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800556 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800557
558 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800559 }
560
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800561 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
562 MacAddress srcMac,
563 MacAddress dstMac,
564 VlanId vlanId) {
565 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
566 if (inPort != null) {
567 selectorBuilder.matchInPort(inPort);
568 }
569 if (srcMac != null) {
570 selectorBuilder.matchEthSrc(srcMac);
571 }
572 if (dstMac != null) {
573 selectorBuilder.matchEthDst(dstMac);
574 }
575 if (vlanId != null) {
576 selectorBuilder.matchVlanId(vlanId);
577 }
578 return selectorBuilder;
579 }
580
581 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
582 PortNumber inPort,
583 MacAddress srcMac,
584 MacAddress dstMac,
585 VlanId vlanId) {
586 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
587 if (dstIp.isIp4()) {
588 selector.matchEthType(TYPE_IPV4);
589 selector.matchIPDst(dstIp);
590 } else {
591 selector.matchEthType(TYPE_IPV6);
592 selector.matchIPv6Dst(dstIp);
593 }
594 return selector.build();
595 }
596
597 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
598 PortNumber inPort,
599 MacAddress srcMac,
600 MacAddress dstMac,
601 VlanId vlanId) {
602 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
603 if (srcIp.isIp4()) {
604 selector.matchEthType(TYPE_IPV4);
605 selector.matchIPSrc(srcIp);
606 } else {
607 selector.matchEthType(TYPE_IPV6);
608 selector.matchIPv6Src(srcIp);
609 }
610 return selector.build();
611 }
612
613 static TrafficSelector buildArpSelector(PortNumber inPort,
614 VlanId vlanId,
615 Ip4Address arpSpa,
616 MacAddress srcMac) {
617 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
618 selector.matchEthType(TYPE_ARP);
619 if (arpSpa != null) {
620 selector.matchArpSpa(arpSpa);
621 }
622 if (srcMac != null) {
623 selector.matchEthSrc(srcMac);
624 }
625 return selector.build();
626 }
627
628 static TrafficSelector buildNdpSelector(PortNumber inPort,
629 VlanId vlanId,
630 IpPrefix srcIp,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800631 IpPrefix dstIp,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800632 byte subProto,
633 MacAddress srcMac) {
634 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
635 selector.matchEthType(TYPE_IPV6)
636 .matchIPProtocol(PROTOCOL_ICMP6)
637 .matchIcmpv6Type(subProto);
638 if (srcIp != null) {
639 selector.matchIPv6Src(srcIp);
640 }
Pier Luigi2b1ad872017-01-31 09:35:42 -0800641 if (dstIp != null) {
Pier Luigi9f765dc2017-02-03 13:35:23 -0800642 selector.matchIPv6Dst(dstIp);
Pier Luigi2b1ad872017-01-31 09:35:42 -0800643 }
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800644 if (srcMac != null) {
645 selector.matchEthSrc(srcMac);
646 }
647 return selector.build();
648 }
649
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800650 private String operation(boolean install) {
651 return install ? "Installing" : "Removing";
652 }
653
Jonathan Hartea492382016-01-13 09:33:13 -0800654 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800655 * Listener for network config events.
656 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800657 private class InternalNetworkConfigListener implements NetworkConfigListener {
658 @Override
659 public void event(NetworkConfigEvent event) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800660 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS) ||
661 event.configClass().equals(RoutersConfig.class)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800662 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700663 case CONFIG_ADDED:
664 case CONFIG_UPDATED:
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800665 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800666 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700667 break;
668 case CONFIG_REGISTERED:
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700669 case CONFIG_UNREGISTERED:
670 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530671 default:
672 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800673 }
674 }
675 }
676 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800677}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530678