blob: 0c97bb1a35d01303c13afd29fde8614f3cfc0b37 [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
Jonathan Hartf04b7d92016-03-29 09:39:11 -070019import com.google.common.collect.ImmutableSortedSet;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053020import com.google.common.collect.Lists;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070021import com.google.common.collect.Maps;
Jonathan Hart6344f572015-12-15 08:26:25 -080022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.onlab.packet.EthType;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053028import org.onlab.packet.Ip4Address;
Pier Luigi2b1ad872017-01-31 09:35:42 -080029import org.onlab.packet.Ip6Address;
Charles Chand0fd5dc2016-02-16 23:14:49 -080030import org.onlab.packet.IpPrefix;
31import org.onlab.packet.MacAddress;
Saurav Das49cb5a12016-01-16 22:54:07 -080032import org.onlab.packet.VlanId;
kishore786b7e42016-05-19 16:25:57 +053033import org.onosproject.app.ApplicationService;
Jonathan Hart6344f572015-12-15 08:26:25 -080034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
36import org.onosproject.incubator.net.intf.Interface;
37import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080038import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080039import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080040import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080041import org.onosproject.net.PortNumber;
42import org.onosproject.net.config.NetworkConfigEvent;
43import org.onosproject.net.config.NetworkConfigListener;
44import org.onosproject.net.config.NetworkConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -080045import org.onosproject.net.device.DeviceService;
46import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
50import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080051import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Hart6344f572015-12-15 08:26:25 -080052import org.onosproject.net.flowobjective.FlowObjectiveService;
53import org.onosproject.net.flowobjective.ForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080054import org.onosproject.net.flowobjective.NextObjective;
Charles Chand0fd5dc2016-02-16 23:14:49 -080055import org.onosproject.net.host.HostEvent;
56import org.onosproject.net.host.HostListener;
57import org.onosproject.net.host.HostService;
Jonathan Hart6344f572015-12-15 08:26:25 -080058import org.onosproject.net.host.InterfaceIpAddress;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080059import org.onosproject.routing.RouterInfo;
60import org.onosproject.routing.InterfaceProvisionRequest;
61import org.onosproject.routing.Router;
Jonathan Hart6344f572015-12-15 08:26:25 -080062import org.onosproject.routing.RoutingService;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080063import org.onosproject.routing.config.RouterConfigHelper;
64import org.onosproject.routing.config.RoutersConfig;
65import org.onosproject.routing.config.RoutingConfigurationService;
Jonathan Hart6344f572015-12-15 08:26:25 -080066import org.slf4j.Logger;
67
Jonathan Hartf04b7d92016-03-29 09:39:11 -070068import java.util.Iterator;
69import java.util.List;
70import java.util.Map;
71import java.util.Optional;
72import java.util.Set;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080073import java.util.concurrent.ConcurrentHashMap;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070074
75import static com.google.common.base.Preconditions.checkState;
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
Jonathan Harte7327042017-02-02 13:11:25 -0800130 private static final String APP_NAME = "org.onosproject.cpr";
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700131 private ApplicationId appId;
132
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700133 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
134
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800135 private Map<DeviceId, Router> routers = new ConcurrentHashMap<>();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700136
Jonathan Hart6344f572015-12-15 08:26:25 -0800137 private final InternalNetworkConfigListener networkConfigListener =
138 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800139 private final InternalHostListener hostListener = new InternalHostListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800140
141 @Activate
Jonathan Harte7327042017-02-02 13:11:25 -0800142 protected void activate() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800143 this.appId = coreService.registerApplication(APP_NAME);
144
Jonathan Hart6344f572015-12-15 08:26:25 -0800145 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800146 hostService.addListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700147
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800148 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800149
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800150 applicationService.registerDeactivateHook(this.appId,
151 () -> routers.forEach((d, r) -> r.cleanup()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800152 }
153
154 @Deactivate
Jonathan Harte7327042017-02-02 13:11:25 -0800155 protected void deactivate() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800156 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800157 hostService.removeListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700158 }
159
kishore786b7e42016-05-19 16:25:57 +0530160 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700161 * Sets up the router interfaces if router config is available.
162 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800163 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800164 ApplicationId routingAppId =
165 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
166
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800167 Set<RoutersConfig.Router> routerConfigs =
168 RouterConfigHelper.getRouterConfigurations(networkConfigService, routingAppId);
Jonathan Hart6344f572015-12-15 08:26:25 -0800169
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800170 for (RoutersConfig.Router router : routerConfigs) {
171 DeviceId deviceId = router.controlPlaneConnectPoint().deviceId();
172
173 routers.compute(deviceId, (d, r) -> {
174 if (r == null) {
175 return createRouter(RouterInfo.from(router));
176 } else {
177 r.changeConfiguration(RouterInfo.from(router));
178 return r;
179 }
180 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800181 }
182
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800183 for (DeviceId deviceId : routers.keySet()) {
184 if (!configExists(deviceId, routerConfigs)) {
185 Router router = routers.remove(deviceId);
186 router.cleanup();
187 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800188 }
189 }
190
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800191 private boolean configExists(DeviceId deviceId, Set<RoutersConfig.Router> config) {
192 return config.stream()
193 .anyMatch(r -> r.controlPlaneConnectPoint().deviceId().equals(deviceId));
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800194 }
195
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800196 private Router createRouter(RouterInfo info) {
197 return new Router(info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800198 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800199 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800200 this::provisionInterface,
201 this::unprovisionInterface);
202 }
203
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800204 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800205 updateInterfaceObjectives(intf, true);
206 }
207
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800208 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800209 updateInterfaceObjectives(intf, false);
210 }
211
212 /**
213 * Installs or removes flow objectives relating to a give interface.
214 *
215 * @param intf interface to change objectives for
216 * @param install true to install the objectives, false to remove them
217 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800218 private void updateInterfaceObjectives(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700219 updateInterfaceForwarding(intf, install);
220 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800221 }
222
kishore71a27532016-03-16 20:23:49 +0530223 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800224 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530225 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800226 * @param request provisioning request containing router and interface
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800227 * @param install true to install the objectives, false to remove them
228 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800229 private void updateInterfaceForwarding(InterfaceProvisionRequest request, boolean install) {
230 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800231 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800232
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700233 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800234
235 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800236 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800237 // create nextObjectives for forwarding to this interface and the
238 // controlPlaneConnectPoint
239 int cpNextId, intfNextId;
240 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530241 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800242 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530243 true, install);
244 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800245 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530246 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800247 } else {
kishore71a27532016-03-16 20:23:49 +0530248 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
249 intf.vlan(), false, install);
250 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
251 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800252 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530253 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
254 TrafficSelector selector;
255 // IP traffic toward the router.
256 selector = buildIPDstSelector(
257 ip.ipAddress().toIpPrefix(),
258 intf.connectPoint().port(),
259 null,
260 intf.mac(),
261 intf.vlan()
262 );
263 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
264 // IP traffic from the router.
265 selector = buildIPSrcSelector(
266 ip.ipAddress().toIpPrefix(),
267 controlPlanePort,
268 intf.mac(),
269 null,
270 intf.vlan()
271 );
272 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
273 // We build the punt treatment.
274 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800275 .punt()
276 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530277 // Handling of neighbour discovery protocols.
278 // IPv4 traffic - we have to deal with the ARP protocol.
279 // IPv6 traffic - we have to deal with the NDP protocol.
280 if (ip.ipAddress().isIp4()) {
281 // ARP traffic towards the router.
282 selector = buildArpSelector(
283 intf.connectPoint().port(),
284 intf.vlan(),
285 null,
286 null
287 );
288 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
289 // ARP traffic from the router.
290 selector = buildArpSelector(
291 controlPlanePort,
292 intf.vlan(),
293 ip.ipAddress().getIp4Address(),
294 intf.mac()
295 );
296 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
297 } else {
298 // Neighbour solicitation traffic towards the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800299 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530300 selector = buildNdpSelector(
301 intf.connectPoint().port(),
302 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800303 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800304 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800305 NEIGHBOR_SOLICITATION,
306 null
307 );
308 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
309 // Neighbour solicitation traffic towards the router.
310 // This flow is for the link local address.
311 selector = buildNdpSelector(
312 intf.connectPoint().port(),
313 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800314 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800315 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800316 NEIGHBOR_SOLICITATION,
317 null
318 );
319 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
320 // Neighbour solicitation traffic towards the router.
321 // This flow is for the solicitation node address of
322 // the global unicast address.
323 selector = buildNdpSelector(
324 intf.connectPoint().port(),
325 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800326 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800327 Ip6Address.valueOf(getSolicitNodeAddress(ip.ipAddress().toOctets())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800328 NEIGHBOR_SOLICITATION,
329 null
330 );
331 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
332 // Neighbour solicitation traffic towards the router.
333 // This flow is for the solicitation node address of
334 // the link local address.
335 selector = buildNdpSelector(
336 intf.connectPoint().port(),
337 intf.vlan(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800338 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800339 Ip6Address.valueOf(
340 getSolicitNodeAddress(getLinkLocalAddress(intf.mac().toBytes()))
341 ).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530342 NEIGHBOR_SOLICITATION,
343 null
344 );
345 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
346 // Neighbour solicitation traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800347 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530348 selector = buildNdpSelector(
349 controlPlanePort,
350 intf.vlan(),
351 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800352 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530353 NEIGHBOR_SOLICITATION,
354 intf.mac()
355 );
356 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800357 // Neighbour solicitation traffic from the router.
358 // This flow is for the link local address.
359 selector = buildNdpSelector(
360 controlPlanePort,
361 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800362 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800363 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800364 NEIGHBOR_SOLICITATION,
365 intf.mac()
366 );
367 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
368 // Neighbour advertisement traffic towards the router.
369 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530370 selector = buildNdpSelector(
371 intf.connectPoint().port(),
372 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800373 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800374 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800375 NEIGHBOR_ADVERTISEMENT,
376 null
377 );
378 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
379 // Neighbour advertisement traffic towards the router.
380 // This flow is for the link local address
381 selector = buildNdpSelector(
382 intf.connectPoint().port(),
383 intf.vlan(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530384 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800385 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530386 NEIGHBOR_ADVERTISEMENT,
387 null
388 );
389 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
390 // Neighbour advertisement traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800391 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530392 selector = buildNdpSelector(
393 controlPlanePort,
394 intf.vlan(),
395 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800396 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530397 NEIGHBOR_ADVERTISEMENT,
398 intf.mac()
399 );
400 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800401 // Neighbour advertisement traffic from the router.
402 // This flow is for the link local address
403 selector = buildNdpSelector(
404 controlPlanePort,
405 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800406 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800407 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800408 NEIGHBOR_ADVERTISEMENT,
409 intf.mac()
410 );
411 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530412 }
413 // Finally we push the fwd objectives through the flow objective service.
414 fwdToSend.stream().forEach(forwardingObjective ->
415 flowObjectiveService.forward(deviceId, forwardingObjective)
416 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800417 }
418 }
419
kishore71a27532016-03-16 20:23:49 +0530420 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700421 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530422 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800423 * @param request provisioning request containing router and interface
kishore71a27532016-03-16 20:23:49 +0530424 * @param install true to create an add objective, false to create a remove
425 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800426 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800427 private void updateOspfForwarding(InterfaceProvisionRequest request, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800428 // TODO IPv6 support has not been implemented yet
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800429 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800430 log.debug("{} OSPF flows for {}", operation(install), intf);
431
Jonathan Hartea492382016-01-13 09:33:13 -0800432 // OSPF to router
433 TrafficSelector toSelector = DefaultTrafficSelector.builder()
434 .matchInPort(intf.connectPoint().port())
435 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
436 .matchVlanId(intf.vlan())
437 .matchIPProtocol((byte) OSPF_IP_PROTO)
438 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800439
Saurav Das49cb5a12016-01-16 22:54:07 -0800440 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700441 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800442 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800443 int cpNextId;
444 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530445 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800446 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530447 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800448 } else {
kishore71a27532016-03-16 20:23:49 +0530449 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
450 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800451 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700452 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800453 buildForwardingObjective(toSelector, null, cpNextId,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800454 install ? request.info().ospfEnabled() : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800455 }
456
457 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800458 * Creates a next objective for forwarding to a port. Handles metadata for
459 * some pipelines that require vlan information for egress port.
460 *
461 * @param deviceId the device on which the next objective is being created
462 * @param portNumber the egress port
463 * @param vlanId vlan information for egress port
464 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530465 * @param install true to create an add next objective, false to create a remove
466 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800467 * @return nextId of the next objective created
468 */
kishore71a27532016-03-16 20:23:49 +0530469 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
470 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800471 int nextId = flowObjectiveService.allocateNextId();
472 NextObjective.Builder nextObjBuilder = DefaultNextObjective
473 .builder().withId(nextId)
474 .withType(NextObjective.Type.SIMPLE)
475 .fromApp(appId);
476
477 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
478 if (popVlan) {
479 ttBuilder.popVlan();
480 }
481 ttBuilder.setOutput(portNumber);
482
483 // setup metadata to pass to nextObjective - indicate the vlan on egress
484 // if needed by the switch pipeline.
485 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
486 metabuilder.matchVlanId(vlanId);
487
488 nextObjBuilder.withMeta(metabuilder.build());
489 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700490 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800491 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530492 if (install) {
493 flowObjectiveService.next(deviceId, nextObjBuilder.add());
494 } else {
495 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
496 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800497 return nextId;
498 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700499
Saurav Das49cb5a12016-01-16 22:54:07 -0800500 /**
501 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800502 *
503 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800504 * @param treatment treatment to apply to packet, can be null
505 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800506 * @param add true to create an add objective, false to create a remove
507 * objective
508 * @return forwarding objective
509 */
510 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
511 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800512 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530513 boolean add,
514 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800515 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
516 fobBuilder.withSelector(selector);
517 if (treatment != null) {
518 fobBuilder.withTreatment(treatment);
519 }
520 if (nextId != -1) {
521 fobBuilder.nextStep(nextId);
522 }
523 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530524 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800525 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800526
527 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800528 }
529
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800530 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
531 MacAddress srcMac,
532 MacAddress dstMac,
533 VlanId vlanId) {
534 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
535 if (inPort != null) {
536 selectorBuilder.matchInPort(inPort);
537 }
538 if (srcMac != null) {
539 selectorBuilder.matchEthSrc(srcMac);
540 }
541 if (dstMac != null) {
542 selectorBuilder.matchEthDst(dstMac);
543 }
544 if (vlanId != null) {
545 selectorBuilder.matchVlanId(vlanId);
546 }
547 return selectorBuilder;
548 }
549
550 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
551 PortNumber inPort,
552 MacAddress srcMac,
553 MacAddress dstMac,
554 VlanId vlanId) {
555 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
556 if (dstIp.isIp4()) {
557 selector.matchEthType(TYPE_IPV4);
558 selector.matchIPDst(dstIp);
559 } else {
560 selector.matchEthType(TYPE_IPV6);
561 selector.matchIPv6Dst(dstIp);
562 }
563 return selector.build();
564 }
565
566 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
567 PortNumber inPort,
568 MacAddress srcMac,
569 MacAddress dstMac,
570 VlanId vlanId) {
571 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
572 if (srcIp.isIp4()) {
573 selector.matchEthType(TYPE_IPV4);
574 selector.matchIPSrc(srcIp);
575 } else {
576 selector.matchEthType(TYPE_IPV6);
577 selector.matchIPv6Src(srcIp);
578 }
579 return selector.build();
580 }
581
582 static TrafficSelector buildArpSelector(PortNumber inPort,
583 VlanId vlanId,
584 Ip4Address arpSpa,
585 MacAddress srcMac) {
586 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
587 selector.matchEthType(TYPE_ARP);
588 if (arpSpa != null) {
589 selector.matchArpSpa(arpSpa);
590 }
591 if (srcMac != null) {
592 selector.matchEthSrc(srcMac);
593 }
594 return selector.build();
595 }
596
597 static TrafficSelector buildNdpSelector(PortNumber inPort,
598 VlanId vlanId,
599 IpPrefix srcIp,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800600 IpPrefix dstIp,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800601 byte subProto,
602 MacAddress srcMac) {
603 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
604 selector.matchEthType(TYPE_IPV6)
605 .matchIPProtocol(PROTOCOL_ICMP6)
606 .matchIcmpv6Type(subProto);
607 if (srcIp != null) {
608 selector.matchIPv6Src(srcIp);
609 }
Pier Luigi2b1ad872017-01-31 09:35:42 -0800610 if (dstIp != null) {
Pier Luigi9f765dc2017-02-03 13:35:23 -0800611 selector.matchIPv6Dst(dstIp);
Pier Luigi2b1ad872017-01-31 09:35:42 -0800612 }
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800613 if (srcMac != null) {
614 selector.matchEthSrc(srcMac);
615 }
616 return selector.build();
617 }
618
619 private int getPriorityFromPrefix(IpPrefix prefix) {
620 return (prefix.isIp4()) ?
621 IPV4_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY :
622 IPV6_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY;
623 }
624
625 private String operation(boolean install) {
626 return install ? "Installing" : "Removing";
627 }
628
629
Jonathan Hartea492382016-01-13 09:33:13 -0800630 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800631 * Listener for network config events.
632 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800633 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530634
Jonathan Hart6344f572015-12-15 08:26:25 -0800635 @Override
636 public void event(NetworkConfigEvent event) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800637 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS) ||
638 event.configClass().equals(RoutersConfig.class)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800639 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700640 case CONFIG_ADDED:
641 case CONFIG_UPDATED:
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800642 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800643 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700644 break;
645 case CONFIG_REGISTERED:
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700646 case CONFIG_UNREGISTERED:
647 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530648 default:
649 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800650 }
651 }
652 }
653 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800654
655 /**
656 * Listener for host events.
657 */
658 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530659
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700660 private Optional<Interface> getPeerInterface(Host peer) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800661 Router router = routers.get(peer.location().deviceId());
662
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700663 return interfaceService.getInterfacesByPort(peer.location()).stream()
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800664 .filter(intf -> router.info().interfaces().isEmpty()
665 || router.info().interfaces().contains(intf.name()))
Charles Chand0fd5dc2016-02-16 23:14:49 -0800666 .filter(intf -> peer.vlan().equals(intf.vlan()))
667 .findFirst();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700668 }
669
670 private void peerAdded(HostEvent event) {
671 Host peer = event.subject();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800672 Router routerInfo = routers.get(peer.location().deviceId());
673 if (routerInfo == null) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700674 return;
675 }
676
677 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800678 if (!peerIntf.isPresent()) {
679 log.debug("Adding peer {}/{} on {} but the interface is not configured",
680 peer.mac(), peer.vlan(), peer.location());
681 return;
682 }
683
Pier Luigi9f765dc2017-02-03 13:35:23 -0800684 // Generate L3 Unicast group for the traffic towards vRouter
685 // XXX This approach will change with the HA design
Charles Chand0fd5dc2016-02-16 23:14:49 -0800686 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800687 peer.vlan(), peer.location().deviceId(), routerInfo.info().controlPlaneConnectPoint().port());
Pier Luigi9f765dc2017-02-03 13:35:23 -0800688 // Generate L3 Unicast group for the traffic towards the upStream
689 // XXX This approach will change with the HA design
Charles Chand0fd5dc2016-02-16 23:14:49 -0800690 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
691 peer.vlan(), peer.location().deviceId(), peer.location().port());
Pier Luigi9f765dc2017-02-03 13:35:23 -0800692 // Store the next objectives in the map
Charles Chand0fd5dc2016-02-16 23:14:49 -0800693 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
694
695 // From peer to router
696 peerIntf.get().ipAddresses().forEach(routerIp -> {
697 flowObjectiveService.forward(peer.location().deviceId(),
698 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
699 });
700
701 // From router to peer
702 peer.ipAddresses().forEach(peerIp -> {
703 flowObjectiveService.forward(peer.location().deviceId(),
704 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
705 });
706 }
707
708 private void peerRemoved(HostEvent event) {
709 Host peer = event.subject();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800710 if (routers.get(peer.location().deviceId()) == null) {
711 return;
712 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700713 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800714 if (!peerIntf.isPresent()) {
715 log.debug("Removing peer {}/{} on {} but the interface is not configured",
716 peer.mac(), peer.vlan(), peer.location());
717 return;
718 }
719
Charles Chand0fd5dc2016-02-16 23:14:49 -0800720 checkState(peerNextId.get(peer) != null,
721 "Peer nextId should not be null");
722 checkState(peerNextId.get(peer).size() == 2,
723 "Wrong nextId associated with the peer");
724 Iterator<Integer> iter = peerNextId.get(peer).iterator();
725 int toRouterL3Unicast = iter.next();
726 int toPeerL3Unicast = iter.next();
727
728 // From peer to router
729 peerIntf.get().ipAddresses().forEach(routerIp -> {
730 flowObjectiveService.forward(peer.location().deviceId(),
731 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
732 });
733
734 // From router to peer
735 peer.ipAddresses().forEach(peerIp -> {
736 flowObjectiveService.forward(peer.location().deviceId(),
737 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
738 });
739 }
740
741 private ForwardingObjective.Builder createPeerObjBuilder(
742 int nextId, IpPrefix ipAddresses) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530743 TrafficSelector selector = buildIPDstSelector(ipAddresses, null, null, null, null);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800744 DefaultForwardingObjective.Builder builder =
745 DefaultForwardingObjective.builder()
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530746 .withSelector(selector)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800747 .fromApp(appId)
748 .withPriority(getPriorityFromPrefix(ipAddresses))
749 .withFlag(ForwardingObjective.Flag.SPECIFIC);
750 if (nextId != -1) {
751 builder.nextStep(nextId);
752 }
753 return builder;
754 }
755
756 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
757 VlanId vlanId, DeviceId deviceId, PortNumber port) {
758 int nextId = flowObjectiveService.allocateNextId();
759 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
760 .withId(nextId)
761 .withType(NextObjective.Type.SIMPLE)
762 .fromApp(appId);
763
764 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
765 ttBuilder.setEthSrc(srcMac);
766 ttBuilder.setEthDst(dstMac);
767 ttBuilder.setOutput(port);
768 nextObjBuilder.addTreatment(ttBuilder.build());
769
770 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
771 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800772 VlanId.vlanId(ASSIGNED_VLAN) :
Charles Chand0fd5dc2016-02-16 23:14:49 -0800773 vlanId;
774 metabuilder.matchVlanId(matchVlanId);
775 nextObjBuilder.withMeta(metabuilder.build());
776
777 flowObjectiveService.next(deviceId, nextObjBuilder.add());
778 return nextId;
779 }
780
781 @Override
782 public void event(HostEvent event) {
783 DeviceId deviceId = event.subject().location().deviceId();
784 if (!mastershipService.isLocalMaster(deviceId)) {
785 return;
786 }
787 switch (event.type()) {
788 case HOST_ADDED:
789 peerAdded(event);
790 break;
791 case HOST_MOVED:
792 //TODO We assume BGP peer does not move for now
793 break;
794 case HOST_REMOVED:
795 peerRemoved(event);
796 break;
797 case HOST_UPDATED:
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530798 //FIXME We assume BGP peer does not change IP for now
799 // but we can discover new address.
Charles Chand0fd5dc2016-02-16 23:14:49 -0800800 break;
801 default:
802 break;
803 }
804 }
805 }
806
Jonathan Hart6344f572015-12-15 08:26:25 -0800807}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530808