blob: 8e793e2dd673598b4bd650127aa405edee3f267e [file] [log] [blame]
Jonathan Hart6344f572015-12-15 08:26:25 -08001/*
Jonathan Hartf4bd0482017-01-27 15:11:18 -08002 * Copyright 2017-present Open Networking Laboratory
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;
47import org.onosproject.net.config.NetworkConfigService;
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.RouterInfo;
61import org.onosproject.routing.InterfaceProvisionRequest;
62import org.onosproject.routing.Router;
Jonathan Hart6344f572015-12-15 08:26:25 -080063import org.onosproject.routing.RoutingService;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080064import org.onosproject.routing.config.RouterConfigHelper;
65import org.onosproject.routing.config.RoutersConfig;
66import org.onosproject.routing.config.RoutingConfigurationService;
Charles Chanc6d227e2017-02-28 15:15:17 -080067import org.osgi.service.component.ComponentContext;
Jonathan Hart6344f572015-12-15 08:26:25 -080068import org.slf4j.Logger;
69
Charles Chanc6d227e2017-02-28 15:15:17 -080070import java.util.Dictionary;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070071import java.util.List;
72import java.util.Map;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070073import java.util.Set;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080074import java.util.concurrent.ConcurrentHashMap;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070075
Jonathan Hartf8cd0522016-10-25 07:09:55 -070076import static org.onlab.packet.Ethernet.TYPE_ARP;
77import static org.onlab.packet.Ethernet.TYPE_IPV4;
78import static org.onlab.packet.Ethernet.TYPE_IPV6;
79import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
80import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
81import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Pier Luigi2b1ad872017-01-31 09:35:42 -080082import static org.onlab.packet.IPv6.getLinkLocalAddress;
83import static org.onlab.packet.IPv6.getSolicitNodeAddress;
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 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080090@Component(immediate = true)
Jonathan Hart6344f572015-12-15 08:26:25 -080091public class ControlPlaneRedirectManager {
92
93 private final Logger log = getLogger(getClass());
94
Jonathan Hartf4bd0482017-01-27 15:11:18 -080095 public static final short ASSIGNED_VLAN = 4094;
96
Charles Chand0fd5dc2016-02-16 23:14:49 -080097 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +053098 private static final int IPV4_PRIORITY = 2000;
99 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530100 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -0800101 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -0800102
Jonathan Hart6344f572015-12-15 08:26:25 -0800103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected CoreService coreService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected DeviceService deviceService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected InterfaceService interfaceService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected FlowObjectiveService flowObjectiveService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected NetworkConfigService networkConfigService;
117
Charles Chand0fd5dc2016-02-16 23:14:49 -0800118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected MastershipService mastershipService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected HostService hostService;
123
kishore786b7e42016-05-19 16:25:57 +0530124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected ApplicationService applicationService;
126
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected RoutingConfigurationService rs;
129
Charles Chanc6d227e2017-02-28 15:15:17 -0800130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected ComponentConfigService cfgService;
132
133 @Property(name = "forceUnprovision", boolValue = false,
134 label = "Force unprovision when the device goes offline")
135 private boolean forceUnprovision = false;
136
Jonathan Harte7327042017-02-02 13:11:25 -0800137 private static final String APP_NAME = "org.onosproject.cpr";
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700138 private ApplicationId appId;
139
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700140 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
141
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800142 private Map<DeviceId, Router> routers = new ConcurrentHashMap<>();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700143
Jonathan Hart6344f572015-12-15 08:26:25 -0800144 private final InternalNetworkConfigListener networkConfigListener =
145 new InternalNetworkConfigListener();
146
147 @Activate
Charles Chanc6d227e2017-02-28 15:15:17 -0800148 protected void activate(ComponentContext context) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800149 this.appId = coreService.registerApplication(APP_NAME);
150
Charles Chanc6d227e2017-02-28 15:15:17 -0800151 cfgService.registerProperties(getClass());
152 modified(context);
153
Jonathan Hart6344f572015-12-15 08:26:25 -0800154 networkConfigService.addListener(networkConfigListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700155
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800156 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800157
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800158 applicationService.registerDeactivateHook(this.appId,
159 () -> routers.forEach((d, r) -> r.cleanup()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800160 }
161
162 @Deactivate
Jonathan Harte7327042017-02-02 13:11:25 -0800163 protected void deactivate() {
Charles Chanc6d227e2017-02-28 15:15:17 -0800164 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart6344f572015-12-15 08:26:25 -0800165 networkConfigService.removeListener(networkConfigListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700166 }
167
Charles Chanc6d227e2017-02-28 15:15:17 -0800168 @Modified
169 protected void modified(ComponentContext context) {
170 if (context != null) {
171 readComponentConfiguration(context);
172 processRouterConfig();
173 }
174 }
175
176 private void readComponentConfiguration(ComponentContext context) {
177 Dictionary<?, ?> properties = context.getProperties();
178 Boolean flag;
179
180 flag = Tools.isPropertyEnabled(properties, "forceUnprovision");
181 if (flag == null) {
182 log.info("ForceUnprovision is not configured, " +
183 "using current value of {}", forceUnprovision);
184 } else {
185 forceUnprovision = flag;
186 log.info("Configured. ForceUnprovision is {}",
187 forceUnprovision ? "enabled" : "disabled");
188 }
189 }
190
kishore786b7e42016-05-19 16:25:57 +0530191 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700192 * Sets up the router interfaces if router config is available.
193 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800194 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800195 ApplicationId routingAppId =
196 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
197
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800198 Set<RoutersConfig.Router> routerConfigs =
199 RouterConfigHelper.getRouterConfigurations(networkConfigService, routingAppId);
Jonathan Hart6344f572015-12-15 08:26:25 -0800200
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800201 for (RoutersConfig.Router router : routerConfigs) {
202 DeviceId deviceId = router.controlPlaneConnectPoint().deviceId();
203
204 routers.compute(deviceId, (d, r) -> {
205 if (r == null) {
206 return createRouter(RouterInfo.from(router));
207 } else {
Charles Chanc6d227e2017-02-28 15:15:17 -0800208 r.changeConfiguration(RouterInfo.from(router), forceUnprovision);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800209 return r;
210 }
211 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800212 }
213
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800214 for (DeviceId deviceId : routers.keySet()) {
215 if (!configExists(deviceId, routerConfigs)) {
216 Router router = routers.remove(deviceId);
217 router.cleanup();
218 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800219 }
220 }
221
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800222 private boolean configExists(DeviceId deviceId, Set<RoutersConfig.Router> config) {
223 return config.stream()
224 .anyMatch(r -> r.controlPlaneConnectPoint().deviceId().equals(deviceId));
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800225 }
226
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800227 private Router createRouter(RouterInfo info) {
228 return new Router(info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800229 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800230 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800231 this::provisionInterface,
Charles Chanc6d227e2017-02-28 15:15:17 -0800232 this::unprovisionInterface,
233 forceUnprovision);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800234 }
235
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800236 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800237 updateInterfaceObjectives(intf, true);
238 }
239
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800240 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800241 updateInterfaceObjectives(intf, false);
242 }
243
244 /**
245 * Installs or removes flow objectives relating to a give interface.
246 *
247 * @param intf interface to change objectives for
248 * @param install true to install the objectives, false to remove them
249 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800250 private void updateInterfaceObjectives(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700251 updateInterfaceForwarding(intf, install);
252 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800253 }
254
kishore71a27532016-03-16 20:23:49 +0530255 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800256 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530257 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800258 * @param request provisioning request containing router and interface
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800259 * @param install true to install the objectives, false to remove them
260 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800261 private void updateInterfaceForwarding(InterfaceProvisionRequest request, boolean install) {
262 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800263 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800264
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700265 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800266
267 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Ray Milkey048bf9a2017-05-12 14:31:50 -0700268 for (InterfaceIpAddress ip : intf.ipAddressesList()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800269 // create nextObjectives for forwarding to this interface and the
270 // controlPlaneConnectPoint
271 int cpNextId, intfNextId;
272 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530273 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800274 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530275 true, install);
276 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800277 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530278 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800279 } else {
kishore71a27532016-03-16 20:23:49 +0530280 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
281 intf.vlan(), false, install);
282 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
283 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800284 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530285 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
286 TrafficSelector selector;
287 // IP traffic toward the router.
288 selector = buildIPDstSelector(
289 ip.ipAddress().toIpPrefix(),
290 intf.connectPoint().port(),
291 null,
292 intf.mac(),
293 intf.vlan()
294 );
295 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
296 // IP traffic from the router.
297 selector = buildIPSrcSelector(
298 ip.ipAddress().toIpPrefix(),
299 controlPlanePort,
300 intf.mac(),
301 null,
302 intf.vlan()
303 );
304 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
305 // We build the punt treatment.
306 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800307 .punt()
308 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530309 // Handling of neighbour discovery protocols.
310 // IPv4 traffic - we have to deal with the ARP protocol.
311 // IPv6 traffic - we have to deal with the NDP protocol.
312 if (ip.ipAddress().isIp4()) {
313 // ARP traffic towards the router.
314 selector = buildArpSelector(
315 intf.connectPoint().port(),
316 intf.vlan(),
317 null,
318 null
319 );
320 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
321 // ARP traffic from the router.
322 selector = buildArpSelector(
323 controlPlanePort,
324 intf.vlan(),
325 ip.ipAddress().getIp4Address(),
326 intf.mac()
327 );
328 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
329 } else {
330 // Neighbour solicitation traffic towards the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800331 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530332 selector = buildNdpSelector(
333 intf.connectPoint().port(),
334 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800335 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800336 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800337 NEIGHBOR_SOLICITATION,
338 null
339 );
340 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
341 // Neighbour solicitation traffic towards the router.
342 // This flow is for the link local address.
343 selector = buildNdpSelector(
344 intf.connectPoint().port(),
345 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800346 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800347 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800348 NEIGHBOR_SOLICITATION,
349 null
350 );
351 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
352 // Neighbour solicitation traffic towards the router.
353 // This flow is for the solicitation node address of
354 // the global unicast address.
355 selector = buildNdpSelector(
356 intf.connectPoint().port(),
357 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800358 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800359 Ip6Address.valueOf(getSolicitNodeAddress(ip.ipAddress().toOctets())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800360 NEIGHBOR_SOLICITATION,
361 null
362 );
363 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
364 // Neighbour solicitation traffic towards the router.
365 // This flow is for the solicitation node address of
366 // the link local address.
367 selector = buildNdpSelector(
368 intf.connectPoint().port(),
369 intf.vlan(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800370 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800371 Ip6Address.valueOf(
372 getSolicitNodeAddress(getLinkLocalAddress(intf.mac().toBytes()))
373 ).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530374 NEIGHBOR_SOLICITATION,
375 null
376 );
377 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
378 // Neighbour solicitation traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800379 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530380 selector = buildNdpSelector(
381 controlPlanePort,
382 intf.vlan(),
383 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800384 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530385 NEIGHBOR_SOLICITATION,
386 intf.mac()
387 );
388 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800389 // Neighbour solicitation traffic from the router.
390 // This flow is for the link local address.
391 selector = buildNdpSelector(
392 controlPlanePort,
393 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800394 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800395 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800396 NEIGHBOR_SOLICITATION,
397 intf.mac()
398 );
399 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
400 // Neighbour advertisement traffic towards the router.
401 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530402 selector = buildNdpSelector(
403 intf.connectPoint().port(),
404 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800405 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800406 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800407 NEIGHBOR_ADVERTISEMENT,
408 null
409 );
410 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
411 // Neighbour advertisement traffic towards the router.
412 // This flow is for the link local address
413 selector = buildNdpSelector(
414 intf.connectPoint().port(),
415 intf.vlan(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530416 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800417 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530418 NEIGHBOR_ADVERTISEMENT,
419 null
420 );
421 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
422 // Neighbour advertisement traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800423 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530424 selector = buildNdpSelector(
425 controlPlanePort,
426 intf.vlan(),
427 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800428 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530429 NEIGHBOR_ADVERTISEMENT,
430 intf.mac()
431 );
432 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800433 // Neighbour advertisement traffic from the router.
434 // This flow is for the link local address
435 selector = buildNdpSelector(
436 controlPlanePort,
437 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800438 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800439 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800440 NEIGHBOR_ADVERTISEMENT,
441 intf.mac()
442 );
443 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530444 }
445 // Finally we push the fwd objectives through the flow objective service.
446 fwdToSend.stream().forEach(forwardingObjective ->
447 flowObjectiveService.forward(deviceId, forwardingObjective)
448 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800449 }
450 }
451
kishore71a27532016-03-16 20:23:49 +0530452 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700453 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530454 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800455 * @param request provisioning request containing router and interface
kishore71a27532016-03-16 20:23:49 +0530456 * @param install true to create an add objective, false to create a remove
457 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800458 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800459 private void updateOspfForwarding(InterfaceProvisionRequest request, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800460 // TODO IPv6 support has not been implemented yet
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800461 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800462 log.debug("{} OSPF flows for {}", operation(install), intf);
463
Jonathan Hartea492382016-01-13 09:33:13 -0800464 // OSPF to router
465 TrafficSelector toSelector = DefaultTrafficSelector.builder()
466 .matchInPort(intf.connectPoint().port())
467 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
468 .matchVlanId(intf.vlan())
469 .matchIPProtocol((byte) OSPF_IP_PROTO)
470 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800471
Saurav Das49cb5a12016-01-16 22:54:07 -0800472 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700473 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800474 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800475 int cpNextId;
476 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530477 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800478 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530479 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800480 } else {
kishore71a27532016-03-16 20:23:49 +0530481 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
482 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800483 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700484 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800485 buildForwardingObjective(toSelector, null, cpNextId,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800486 install ? request.info().ospfEnabled() : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800487 }
488
489 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800490 * Creates a next objective for forwarding to a port. Handles metadata for
491 * some pipelines that require vlan information for egress port.
492 *
493 * @param deviceId the device on which the next objective is being created
494 * @param portNumber the egress port
495 * @param vlanId vlan information for egress port
496 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530497 * @param install true to create an add next objective, false to create a remove
498 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800499 * @return nextId of the next objective created
500 */
kishore71a27532016-03-16 20:23:49 +0530501 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
502 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800503 int nextId = flowObjectiveService.allocateNextId();
504 NextObjective.Builder nextObjBuilder = DefaultNextObjective
505 .builder().withId(nextId)
506 .withType(NextObjective.Type.SIMPLE)
507 .fromApp(appId);
508
509 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
510 if (popVlan) {
511 ttBuilder.popVlan();
512 }
513 ttBuilder.setOutput(portNumber);
514
515 // setup metadata to pass to nextObjective - indicate the vlan on egress
516 // if needed by the switch pipeline.
517 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
518 metabuilder.matchVlanId(vlanId);
519
520 nextObjBuilder.withMeta(metabuilder.build());
521 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700522 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800523 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530524 if (install) {
525 flowObjectiveService.next(deviceId, nextObjBuilder.add());
526 } else {
527 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
528 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800529 return nextId;
530 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700531
Saurav Das49cb5a12016-01-16 22:54:07 -0800532 /**
533 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800534 *
535 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800536 * @param treatment treatment to apply to packet, can be null
537 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800538 * @param add true to create an add objective, false to create a remove
539 * objective
540 * @return forwarding objective
541 */
542 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
543 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800544 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530545 boolean add,
546 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800547 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
548 fobBuilder.withSelector(selector);
549 if (treatment != null) {
550 fobBuilder.withTreatment(treatment);
551 }
552 if (nextId != -1) {
553 fobBuilder.nextStep(nextId);
554 }
555 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530556 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800557 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800558
559 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800560 }
561
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800562 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
563 MacAddress srcMac,
564 MacAddress dstMac,
565 VlanId vlanId) {
566 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
567 if (inPort != null) {
568 selectorBuilder.matchInPort(inPort);
569 }
570 if (srcMac != null) {
571 selectorBuilder.matchEthSrc(srcMac);
572 }
573 if (dstMac != null) {
574 selectorBuilder.matchEthDst(dstMac);
575 }
576 if (vlanId != null) {
577 selectorBuilder.matchVlanId(vlanId);
578 }
579 return selectorBuilder;
580 }
581
582 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
583 PortNumber inPort,
584 MacAddress srcMac,
585 MacAddress dstMac,
586 VlanId vlanId) {
587 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
588 if (dstIp.isIp4()) {
589 selector.matchEthType(TYPE_IPV4);
590 selector.matchIPDst(dstIp);
591 } else {
592 selector.matchEthType(TYPE_IPV6);
593 selector.matchIPv6Dst(dstIp);
594 }
595 return selector.build();
596 }
597
598 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
599 PortNumber inPort,
600 MacAddress srcMac,
601 MacAddress dstMac,
602 VlanId vlanId) {
603 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
604 if (srcIp.isIp4()) {
605 selector.matchEthType(TYPE_IPV4);
606 selector.matchIPSrc(srcIp);
607 } else {
608 selector.matchEthType(TYPE_IPV6);
609 selector.matchIPv6Src(srcIp);
610 }
611 return selector.build();
612 }
613
614 static TrafficSelector buildArpSelector(PortNumber inPort,
615 VlanId vlanId,
616 Ip4Address arpSpa,
617 MacAddress srcMac) {
618 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
619 selector.matchEthType(TYPE_ARP);
620 if (arpSpa != null) {
621 selector.matchArpSpa(arpSpa);
622 }
623 if (srcMac != null) {
624 selector.matchEthSrc(srcMac);
625 }
626 return selector.build();
627 }
628
629 static TrafficSelector buildNdpSelector(PortNumber inPort,
630 VlanId vlanId,
631 IpPrefix srcIp,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800632 IpPrefix dstIp,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800633 byte subProto,
634 MacAddress srcMac) {
635 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
636 selector.matchEthType(TYPE_IPV6)
637 .matchIPProtocol(PROTOCOL_ICMP6)
638 .matchIcmpv6Type(subProto);
639 if (srcIp != null) {
640 selector.matchIPv6Src(srcIp);
641 }
Pier Luigi2b1ad872017-01-31 09:35:42 -0800642 if (dstIp != null) {
Pier Luigi9f765dc2017-02-03 13:35:23 -0800643 selector.matchIPv6Dst(dstIp);
Pier Luigi2b1ad872017-01-31 09:35:42 -0800644 }
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800645 if (srcMac != null) {
646 selector.matchEthSrc(srcMac);
647 }
648 return selector.build();
649 }
650
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800651 private String operation(boolean install) {
652 return install ? "Installing" : "Removing";
653 }
654
Jonathan Hartea492382016-01-13 09:33:13 -0800655 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800656 * Listener for network config events.
657 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800658 private class InternalNetworkConfigListener implements NetworkConfigListener {
659 @Override
660 public void event(NetworkConfigEvent event) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800661 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS) ||
662 event.configClass().equals(RoutersConfig.class)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800663 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700664 case CONFIG_ADDED:
665 case CONFIG_UPDATED:
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800666 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800667 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700668 break;
669 case CONFIG_REGISTERED:
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700670 case CONFIG_UNREGISTERED:
671 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530672 default:
673 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800674 }
675 }
676 }
677 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800678}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530679