blob: 79c3b491566f876dfb88fda0d9b6d0e8bc71ecaf [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 Hartf8cd0522016-10-25 07:09:55 -070022import com.google.common.collect.Sets;
Jonathan Hart6344f572015-12-15 08:26:25 -080023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import 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;
kishore786b7e42016-05-19 16:25:57 +053034import org.onosproject.app.ApplicationService;
Jonathan Hart6344f572015-12-15 08:26:25 -080035import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.incubator.net.intf.Interface;
38import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080039import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080040import org.onosproject.net.ConnectPoint;
41import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080042import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080043import org.onosproject.net.PortNumber;
44import org.onosproject.net.config.NetworkConfigEvent;
45import org.onosproject.net.config.NetworkConfigListener;
46import org.onosproject.net.config.NetworkConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -080047import org.onosproject.net.device.DeviceService;
48import org.onosproject.net.flow.DefaultTrafficSelector;
49import org.onosproject.net.flow.DefaultTrafficTreatment;
50import org.onosproject.net.flow.TrafficSelector;
51import org.onosproject.net.flow.TrafficTreatment;
52import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080053import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Hart6344f572015-12-15 08:26:25 -080054import org.onosproject.net.flowobjective.FlowObjectiveService;
55import org.onosproject.net.flowobjective.ForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080056import org.onosproject.net.flowobjective.NextObjective;
Charles Chand0fd5dc2016-02-16 23:14:49 -080057import org.onosproject.net.host.HostEvent;
58import org.onosproject.net.host.HostListener;
59import org.onosproject.net.host.HostService;
Jonathan Hart6344f572015-12-15 08:26:25 -080060import org.onosproject.net.host.InterfaceIpAddress;
Jonathan Hartf4bd0482017-01-27 15:11:18 -080061import org.onosproject.routing.AsyncDeviceFetcher;
62import org.onosproject.routing.RouterInterfaceManager;
Jonathan Hart6344f572015-12-15 08:26:25 -080063import org.onosproject.routing.RoutingService;
64import org.onosproject.routing.config.RouterConfig;
65import org.slf4j.Logger;
66
Jonathan Hartf04b7d92016-03-29 09:39:11 -070067import java.util.Iterator;
68import java.util.List;
69import java.util.Map;
70import java.util.Optional;
71import java.util.Set;
72
73import static com.google.common.base.Preconditions.checkState;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070074import static org.onlab.packet.Ethernet.TYPE_ARP;
75import static org.onlab.packet.Ethernet.TYPE_IPV4;
76import static org.onlab.packet.Ethernet.TYPE_IPV6;
77import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
78import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
79import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Pier Luigi2b1ad872017-01-31 09:35:42 -080080import static org.onlab.packet.IPv6.getLinkLocalAddress;
81import static org.onlab.packet.IPv6.getSolicitNodeAddress;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070082import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080083
84/**
85 * Manages connectivity between peers redirecting control traffic to a routing
86 * control plane available on the dataplane.
87 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080088@Component(immediate = true)
Jonathan Hart6344f572015-12-15 08:26:25 -080089public class ControlPlaneRedirectManager {
90
91 private final Logger log = getLogger(getClass());
92
Jonathan Hartf4bd0482017-01-27 15:11:18 -080093 public static final short ASSIGNED_VLAN = 4094;
94
Charles Chand0fd5dc2016-02-16 23:14:49 -080095 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +053096 private static final int IPV4_PRIORITY = 2000;
97 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053098 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080099 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -0800100
Jonathan Hart6344f572015-12-15 08:26:25 -0800101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected CoreService coreService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected DeviceService deviceService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected InterfaceService interfaceService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected FlowObjectiveService flowObjectiveService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected NetworkConfigService networkConfigService;
115
Charles Chand0fd5dc2016-02-16 23:14:49 -0800116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected MastershipService mastershipService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected HostService hostService;
121
kishore786b7e42016-05-19 16:25:57 +0530122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected ApplicationService applicationService;
124
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700125 private static final String APP_NAME = "org.onosproject.vrouter";
126 private ApplicationId appId;
127
128 private ConnectPoint controlPlaneConnectPoint;
129 private boolean ospfEnabled = false;
130 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
131
132 private RouterInterfaceManager interfaceManager;
133 private AsyncDeviceFetcher asyncDeviceFetcher;
134
Jonathan Hart6344f572015-12-15 08:26:25 -0800135 private final InternalNetworkConfigListener networkConfigListener =
136 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800137 private final InternalHostListener hostListener = new InternalHostListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800138
139 @Activate
140 public void activate() {
141 this.appId = coreService.registerApplication(APP_NAME);
142
Jonathan Hart6344f572015-12-15 08:26:25 -0800143 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800144 hostService.addListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700145
146 asyncDeviceFetcher = AsyncDeviceFetcher.create(deviceService);
Jonathan Hart6344f572015-12-15 08:26:25 -0800147
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800148 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800149
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800150
Charles Chan00d8b5f2016-12-04 17:17:39 -0800151 // FIXME There can be an issue when this component is deactivated before vRouter
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700152 applicationService.registerDeactivateHook(this.appId, () -> {
153 if (interfaceManager != null) {
154 interfaceManager.cleanup();
155 }
156 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800157 }
158
159 @Deactivate
160 public void deactivate() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800161 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800162 hostService.removeListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700163 asyncDeviceFetcher.shutdown();
164 }
165
kishore786b7e42016-05-19 16:25:57 +0530166 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700167 * Sets up the router interfaces if router config is available.
168 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800169 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800170 ApplicationId routingAppId =
171 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
172
173 RouterConfig config = networkConfigService.getConfig(
174 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
175
176 if (config == null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800177 log.warn("Router config not available");
Jonathan Hart6344f572015-12-15 08:26:25 -0800178 return;
179 }
180
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700181 if (interfaceManager == null) {
182 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
183 ospfEnabled = config.getOspfEnabled();
Jonathan Hart6344f572015-12-15 08:26:25 -0800184
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700185 DeviceId deviceId = config.getControlPlaneConnectPoint().deviceId();
Jonathan Hartea492382016-01-13 09:33:13 -0800186
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700187 asyncDeviceFetcher.getDevice(deviceId)
188 .thenAccept(deviceId1 ->
189 interfaceManager = createRouter(deviceId,
190 Sets.newHashSet(config.getInterfaces())));
Jonathan Hartea492382016-01-13 09:33:13 -0800191
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700192 } else {
193 interfaceManager.changeConfiguredInterfaces(Sets.newHashSet(config.getInterfaces()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800194 }
195 }
196
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800197 /**
198 * Cleans up after router config was removed.
199 */
200 private void removeRouterConfig() {
201 if (interfaceManager != null) {
202 interfaceManager.cleanup();
203 }
204 }
205
206 private RouterInterfaceManager createRouter(DeviceId deviceId, Set<String> configuredInterfaces) {
207 return new RouterInterfaceManager(deviceId,
208 configuredInterfaces,
209 interfaceService,
210 this::provisionInterface,
211 this::unprovisionInterface);
212 }
213
214 private void provisionInterface(Interface intf) {
215 updateInterfaceObjectives(intf, true);
216 }
217
218 private void unprovisionInterface(Interface intf) {
219 updateInterfaceObjectives(intf, false);
220 }
221
222 /**
223 * Installs or removes flow objectives relating to a give interface.
224 *
225 * @param intf interface to change objectives for
226 * @param install true to install the objectives, false to remove them
227 */
228 private void updateInterfaceObjectives(Interface intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700229 updateInterfaceForwarding(intf, install);
230 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800231 }
232
kishore71a27532016-03-16 20:23:49 +0530233 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800234 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530235 *
236 * @param intf the Interface on which event is received
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800237 * @param install true to install the objectives, false to remove them
238 */
Jonathan Hartf8035d32016-06-16 16:23:26 -0700239 private void updateInterfaceForwarding(Interface intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800240 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800241
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700242 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart6344f572015-12-15 08:26:25 -0800243 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800244 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800245 // create nextObjectives for forwarding to this interface and the
246 // controlPlaneConnectPoint
247 int cpNextId, intfNextId;
248 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530249 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800250 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530251 true, install);
252 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800253 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530254 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800255 } else {
kishore71a27532016-03-16 20:23:49 +0530256 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
257 intf.vlan(), false, install);
258 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
259 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800260 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530261 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
262 TrafficSelector selector;
263 // IP traffic toward the router.
264 selector = buildIPDstSelector(
265 ip.ipAddress().toIpPrefix(),
266 intf.connectPoint().port(),
267 null,
268 intf.mac(),
269 intf.vlan()
270 );
271 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
272 // IP traffic from the router.
273 selector = buildIPSrcSelector(
274 ip.ipAddress().toIpPrefix(),
275 controlPlanePort,
276 intf.mac(),
277 null,
278 intf.vlan()
279 );
280 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
281 // We build the punt treatment.
282 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800283 .punt()
284 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530285 // Handling of neighbour discovery protocols.
286 // IPv4 traffic - we have to deal with the ARP protocol.
287 // IPv6 traffic - we have to deal with the NDP protocol.
288 if (ip.ipAddress().isIp4()) {
289 // ARP traffic towards the router.
290 selector = buildArpSelector(
291 intf.connectPoint().port(),
292 intf.vlan(),
293 null,
294 null
295 );
296 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
297 // ARP traffic from the router.
298 selector = buildArpSelector(
299 controlPlanePort,
300 intf.vlan(),
301 ip.ipAddress().getIp4Address(),
302 intf.mac()
303 );
304 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
305 } else {
306 // Neighbour solicitation traffic towards the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800307 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530308 selector = buildNdpSelector(
309 intf.connectPoint().port(),
310 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800311 ip.ipAddress().toIpPrefix(),
312 null,
313 NEIGHBOR_SOLICITATION,
314 null
315 );
316 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
317 // Neighbour solicitation traffic towards the router.
318 // This flow is for the link local address.
319 selector = buildNdpSelector(
320 intf.connectPoint().port(),
321 intf.vlan(),
322 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
323 null,
324 NEIGHBOR_SOLICITATION,
325 null
326 );
327 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
328 // Neighbour solicitation traffic towards the router.
329 // This flow is for the solicitation node address of
330 // the global unicast address.
331 selector = buildNdpSelector(
332 intf.connectPoint().port(),
333 intf.vlan(),
334 Ip6Address.valueOf(getSolicitNodeAddress(ip.ipAddress().toOctets())).toIpPrefix(),
335 null,
336 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 solicitation node address of
342 // the link local address.
343 selector = buildNdpSelector(
344 intf.connectPoint().port(),
345 intf.vlan(),
346 Ip6Address.valueOf(
347 getSolicitNodeAddress(getLinkLocalAddress(intf.mac().toBytes()))
348 ).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530349 null,
350 NEIGHBOR_SOLICITATION,
351 null
352 );
353 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
354 // Neighbour solicitation traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800355 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530356 selector = buildNdpSelector(
357 controlPlanePort,
358 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800359 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530360 ip.ipAddress().toIpPrefix(),
361 NEIGHBOR_SOLICITATION,
362 intf.mac()
363 );
364 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800365 // Neighbour solicitation traffic from the router.
366 // This flow is for the link local address.
367 selector = buildNdpSelector(
368 controlPlanePort,
369 intf.vlan(),
370 null,
371 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
372 NEIGHBOR_SOLICITATION,
373 intf.mac()
374 );
375 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
376 // Neighbour advertisement traffic towards the router.
377 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530378 selector = buildNdpSelector(
379 intf.connectPoint().port(),
380 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800381 ip.ipAddress().toIpPrefix(),
382 null,
383 NEIGHBOR_ADVERTISEMENT,
384 null
385 );
386 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
387 // Neighbour advertisement traffic towards the router.
388 // This flow is for the link local address
389 selector = buildNdpSelector(
390 intf.connectPoint().port(),
391 intf.vlan(),
392 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530393 null,
394 NEIGHBOR_ADVERTISEMENT,
395 null
396 );
397 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
398 // Neighbour advertisement traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800399 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530400 selector = buildNdpSelector(
401 controlPlanePort,
402 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800403 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530404 ip.ipAddress().toIpPrefix(),
405 NEIGHBOR_ADVERTISEMENT,
406 intf.mac()
407 );
408 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800409 // Neighbour advertisement traffic from the router.
410 // This flow is for the link local address
411 selector = buildNdpSelector(
412 controlPlanePort,
413 intf.vlan(),
414 null,
415 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
416 NEIGHBOR_ADVERTISEMENT,
417 intf.mac()
418 );
419 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530420 }
421 // Finally we push the fwd objectives through the flow objective service.
422 fwdToSend.stream().forEach(forwardingObjective ->
423 flowObjectiveService.forward(deviceId, forwardingObjective)
424 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800425 }
426 }
427
kishore71a27532016-03-16 20:23:49 +0530428 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700429 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530430 *
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700431 * @param intf the interface on which event is received
kishore71a27532016-03-16 20:23:49 +0530432 * @param install true to create an add objective, false to create a remove
433 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800434 */
kishore71a27532016-03-16 20:23:49 +0530435 private void updateOspfForwarding(Interface intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800436 // TODO IPv6 support has not been implemented yet
437
438 log.debug("{} OSPF flows for {}", operation(install), intf);
439
Jonathan Hartea492382016-01-13 09:33:13 -0800440 // OSPF to router
441 TrafficSelector toSelector = DefaultTrafficSelector.builder()
442 .matchInPort(intf.connectPoint().port())
443 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
444 .matchVlanId(intf.vlan())
445 .matchIPProtocol((byte) OSPF_IP_PROTO)
446 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800447
Saurav Das49cb5a12016-01-16 22:54:07 -0800448 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700449 DeviceId deviceId = intf.connectPoint().deviceId();
450 PortNumber controlPlanePort = intf.connectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800451 int cpNextId;
452 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530453 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800454 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530455 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800456 } else {
kishore71a27532016-03-16 20:23:49 +0530457 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
458 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800459 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700460 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800461 buildForwardingObjective(toSelector, null, cpNextId,
462 install ? ospfEnabled : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800463 }
464
465 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800466 * Creates a next objective for forwarding to a port. Handles metadata for
467 * some pipelines that require vlan information for egress port.
468 *
469 * @param deviceId the device on which the next objective is being created
470 * @param portNumber the egress port
471 * @param vlanId vlan information for egress port
472 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530473 * @param install true to create an add next objective, false to create a remove
474 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800475 * @return nextId of the next objective created
476 */
kishore71a27532016-03-16 20:23:49 +0530477 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
478 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800479 int nextId = flowObjectiveService.allocateNextId();
480 NextObjective.Builder nextObjBuilder = DefaultNextObjective
481 .builder().withId(nextId)
482 .withType(NextObjective.Type.SIMPLE)
483 .fromApp(appId);
484
485 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
486 if (popVlan) {
487 ttBuilder.popVlan();
488 }
489 ttBuilder.setOutput(portNumber);
490
491 // setup metadata to pass to nextObjective - indicate the vlan on egress
492 // if needed by the switch pipeline.
493 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
494 metabuilder.matchVlanId(vlanId);
495
496 nextObjBuilder.withMeta(metabuilder.build());
497 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700498 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800499 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530500 if (install) {
501 flowObjectiveService.next(deviceId, nextObjBuilder.add());
502 } else {
503 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
504 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800505 return nextId;
506 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700507
Saurav Das49cb5a12016-01-16 22:54:07 -0800508 /**
509 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800510 *
511 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800512 * @param treatment treatment to apply to packet, can be null
513 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800514 * @param add true to create an add objective, false to create a remove
515 * objective
516 * @return forwarding objective
517 */
518 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
519 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800520 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530521 boolean add,
522 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800523 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
524 fobBuilder.withSelector(selector);
525 if (treatment != null) {
526 fobBuilder.withTreatment(treatment);
527 }
528 if (nextId != -1) {
529 fobBuilder.nextStep(nextId);
530 }
531 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530532 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800533 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800534
535 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800536 }
537
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800538 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
539 MacAddress srcMac,
540 MacAddress dstMac,
541 VlanId vlanId) {
542 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
543 if (inPort != null) {
544 selectorBuilder.matchInPort(inPort);
545 }
546 if (srcMac != null) {
547 selectorBuilder.matchEthSrc(srcMac);
548 }
549 if (dstMac != null) {
550 selectorBuilder.matchEthDst(dstMac);
551 }
552 if (vlanId != null) {
553 selectorBuilder.matchVlanId(vlanId);
554 }
555 return selectorBuilder;
556 }
557
558 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
559 PortNumber inPort,
560 MacAddress srcMac,
561 MacAddress dstMac,
562 VlanId vlanId) {
563 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
564 if (dstIp.isIp4()) {
565 selector.matchEthType(TYPE_IPV4);
566 selector.matchIPDst(dstIp);
567 } else {
568 selector.matchEthType(TYPE_IPV6);
569 selector.matchIPv6Dst(dstIp);
570 }
571 return selector.build();
572 }
573
574 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
575 PortNumber inPort,
576 MacAddress srcMac,
577 MacAddress dstMac,
578 VlanId vlanId) {
579 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
580 if (srcIp.isIp4()) {
581 selector.matchEthType(TYPE_IPV4);
582 selector.matchIPSrc(srcIp);
583 } else {
584 selector.matchEthType(TYPE_IPV6);
585 selector.matchIPv6Src(srcIp);
586 }
587 return selector.build();
588 }
589
590 static TrafficSelector buildArpSelector(PortNumber inPort,
591 VlanId vlanId,
592 Ip4Address arpSpa,
593 MacAddress srcMac) {
594 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
595 selector.matchEthType(TYPE_ARP);
596 if (arpSpa != null) {
597 selector.matchArpSpa(arpSpa);
598 }
599 if (srcMac != null) {
600 selector.matchEthSrc(srcMac);
601 }
602 return selector.build();
603 }
604
605 static TrafficSelector buildNdpSelector(PortNumber inPort,
606 VlanId vlanId,
607 IpPrefix srcIp,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800608 IpPrefix dstIp,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800609 byte subProto,
610 MacAddress srcMac) {
611 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
612 selector.matchEthType(TYPE_IPV6)
613 .matchIPProtocol(PROTOCOL_ICMP6)
614 .matchIcmpv6Type(subProto);
615 if (srcIp != null) {
616 selector.matchIPv6Src(srcIp);
617 }
Pier Luigi2b1ad872017-01-31 09:35:42 -0800618 if (dstIp != null) {
619 selector.matchIPv6Dst(srcIp);
620 }
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800621 if (srcMac != null) {
622 selector.matchEthSrc(srcMac);
623 }
624 return selector.build();
625 }
626
627 private int getPriorityFromPrefix(IpPrefix prefix) {
628 return (prefix.isIp4()) ?
629 IPV4_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY :
630 IPV6_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY;
631 }
632
633 private String operation(boolean install) {
634 return install ? "Installing" : "Removing";
635 }
636
637
Jonathan Hartea492382016-01-13 09:33:13 -0800638 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800639 * Listener for network config events.
640 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800641 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530642
Jonathan Hart6344f572015-12-15 08:26:25 -0800643 @Override
644 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800645 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800646 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700647 case CONFIG_ADDED:
648 case CONFIG_UPDATED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800649 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700650 break;
651 case CONFIG_REGISTERED:
652 break;
653 case CONFIG_UNREGISTERED:
654 break;
655 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800656 removeRouterConfig();
kishore36d1c272016-09-21 15:44:10 +0530657 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530658 default:
659 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800660 }
661 }
662 }
663 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800664
665 /**
666 * Listener for host events.
667 */
668 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530669
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700670 private Optional<Interface> getPeerInterface(Host peer) {
671 return interfaceService.getInterfacesByPort(peer.location()).stream()
672 .filter(intf -> interfaceManager.configuredInterfaces().isEmpty()
673 || interfaceManager.configuredInterfaces().contains(intf.name()))
Charles Chand0fd5dc2016-02-16 23:14:49 -0800674 .filter(intf -> peer.vlan().equals(intf.vlan()))
675 .findFirst();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700676 }
677
678 private void peerAdded(HostEvent event) {
679 Host peer = event.subject();
680 if (interfaceManager == null) {
681 return;
682 }
683
684 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800685 if (!peerIntf.isPresent()) {
686 log.debug("Adding peer {}/{} on {} but the interface is not configured",
687 peer.mac(), peer.vlan(), peer.location());
688 return;
689 }
690
691 // Generate L3 Unicast groups and store it in the map
692 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700693 peer.vlan(), peer.location().deviceId(), peerIntf.get().connectPoint().port());
Charles Chand0fd5dc2016-02-16 23:14:49 -0800694 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
695 peer.vlan(), peer.location().deviceId(), peer.location().port());
696 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
697
698 // From peer to router
699 peerIntf.get().ipAddresses().forEach(routerIp -> {
700 flowObjectiveService.forward(peer.location().deviceId(),
701 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
702 });
703
704 // From router to peer
705 peer.ipAddresses().forEach(peerIp -> {
706 flowObjectiveService.forward(peer.location().deviceId(),
707 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
708 });
709 }
710
711 private void peerRemoved(HostEvent event) {
712 Host peer = event.subject();
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