blob: 7c00613a8ecc702f83cbeec51945c139e1290688 [file] [log] [blame]
Jonathan Hart6344f572015-12-15 08:26:25 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-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
17package org.onosproject.routing.impl;
18
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;
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.ConnectPoint;
40import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080041import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080042import org.onosproject.net.PortNumber;
43import org.onosproject.net.config.NetworkConfigEvent;
44import org.onosproject.net.config.NetworkConfigListener;
45import org.onosproject.net.config.NetworkConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -080046import org.onosproject.net.device.DeviceService;
47import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.TrafficSelector;
50import org.onosproject.net.flow.TrafficTreatment;
51import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080052import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Hart6344f572015-12-15 08:26:25 -080053import org.onosproject.net.flowobjective.FlowObjectiveService;
54import org.onosproject.net.flowobjective.ForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080055import org.onosproject.net.flowobjective.NextObjective;
Charles Chand0fd5dc2016-02-16 23:14:49 -080056import org.onosproject.net.host.HostEvent;
57import org.onosproject.net.host.HostListener;
58import org.onosproject.net.host.HostService;
Jonathan Hart6344f572015-12-15 08:26:25 -080059import org.onosproject.net.host.InterfaceIpAddress;
60import org.onosproject.routing.RoutingService;
61import org.onosproject.routing.config.RouterConfig;
62import org.slf4j.Logger;
63
Jonathan Hartf04b7d92016-03-29 09:39:11 -070064import java.util.Iterator;
65import java.util.List;
66import java.util.Map;
67import java.util.Optional;
68import java.util.Set;
69
70import static com.google.common.base.Preconditions.checkState;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070071import static org.onlab.packet.Ethernet.TYPE_ARP;
72import static org.onlab.packet.Ethernet.TYPE_IPV4;
73import static org.onlab.packet.Ethernet.TYPE_IPV6;
74import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
75import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
76import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070077import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080078
79/**
80 * Manages connectivity between peers redirecting control traffic to a routing
81 * control plane available on the dataplane.
82 */
83@Component(immediate = true, enabled = false)
84public class ControlPlaneRedirectManager {
85
86 private final Logger log = getLogger(getClass());
87
Charles Chand0fd5dc2016-02-16 23:14:49 -080088 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +053089 private static final int IPV4_PRIORITY = 2000;
90 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053091 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080092 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -080093
Jonathan Hart6344f572015-12-15 08:26:25 -080094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected CoreService coreService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected DeviceService deviceService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected InterfaceService interfaceService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected FlowObjectiveService flowObjectiveService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected NetworkConfigService networkConfigService;
108
Charles Chand0fd5dc2016-02-16 23:14:49 -0800109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected MastershipService mastershipService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected HostService hostService;
114
kishore786b7e42016-05-19 16:25:57 +0530115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected ApplicationService applicationService;
117
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700118 private static final String APP_NAME = "org.onosproject.vrouter";
119 private ApplicationId appId;
120
121 private ConnectPoint controlPlaneConnectPoint;
122 private boolean ospfEnabled = false;
123 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
124
125 private RouterInterfaceManager interfaceManager;
126 private AsyncDeviceFetcher asyncDeviceFetcher;
127
Jonathan Hart6344f572015-12-15 08:26:25 -0800128 private final InternalNetworkConfigListener networkConfigListener =
129 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800130 private final InternalHostListener hostListener = new InternalHostListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800131
132 @Activate
133 public void activate() {
134 this.appId = coreService.registerApplication(APP_NAME);
135
Jonathan Hart6344f572015-12-15 08:26:25 -0800136 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800137 hostService.addListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700138
139 asyncDeviceFetcher = AsyncDeviceFetcher.create(deviceService);
Jonathan Hart6344f572015-12-15 08:26:25 -0800140
Jonathan Hartf8035d32016-06-16 16:23:26 -0700141 readConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800142
143 // FIXME There can be an issue when this component is deactivated before vRouter
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700144 applicationService.registerDeactivateHook(this.appId, () -> {
145 if (interfaceManager != null) {
146 interfaceManager.cleanup();
147 }
148 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800149 }
150
151 @Deactivate
152 public void deactivate() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800153 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800154 hostService.removeListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700155 asyncDeviceFetcher.shutdown();
156 }
157
158 private RouterInterfaceManager createRouter(DeviceId deviceId, Set<String> configuredInterfaces) {
159 return new RouterInterfaceManager(deviceId,
160 configuredInterfaces,
161 interfaceService,
162 intf -> provisionInterface(intf, true),
163 intf -> provisionInterface(intf, false)
164 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800165 }
166
kishore786b7e42016-05-19 16:25:57 +0530167 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700168 * Sets up the router interfaces if router config is available.
169 */
Jonathan Hartf8035d32016-06-16 16:23:26 -0700170 private void readConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800171 ApplicationId routingAppId =
172 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
173
174 RouterConfig config = networkConfigService.getConfig(
175 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
176
177 if (config == null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800178 log.warn("Router config not available");
Jonathan Hart6344f572015-12-15 08:26:25 -0800179 return;
180 }
181
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700182 if (interfaceManager == null) {
183 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
184 ospfEnabled = config.getOspfEnabled();
Jonathan Hart6344f572015-12-15 08:26:25 -0800185
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700186 DeviceId deviceId = config.getControlPlaneConnectPoint().deviceId();
Jonathan Hartea492382016-01-13 09:33:13 -0800187
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700188 asyncDeviceFetcher.getDevice(deviceId)
189 .thenAccept(deviceId1 ->
190 interfaceManager = createRouter(deviceId,
191 Sets.newHashSet(config.getInterfaces())));
Jonathan Hartea492382016-01-13 09:33:13 -0800192
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700193 } else {
194 interfaceManager.changeConfiguredInterfaces(Sets.newHashSet(config.getInterfaces()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800195 }
196 }
197
Jonathan Hartf8035d32016-06-16 16:23:26 -0700198 private void provisionInterface(Interface intf, boolean install) {
199 updateInterfaceForwarding(intf, install);
200 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800201 }
202
kishore71a27532016-03-16 20:23:49 +0530203 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700204 * Installs or removes the basic forwarding flows for each interface
kishore71a27532016-03-16 20:23:49 +0530205 * based on the flag used.
206 *
207 * @param intf the Interface on which event is received
208 * @param install true to create an add objective, false to create a remove
209 * objective
210 **/
Jonathan Hartf8035d32016-06-16 16:23:26 -0700211 private void updateInterfaceForwarding(Interface intf, boolean install) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800212 log.debug("Adding interface objectives for {}", intf);
213
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700214 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart6344f572015-12-15 08:26:25 -0800215 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800216 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800217 // create nextObjectives for forwarding to this interface and the
218 // controlPlaneConnectPoint
219 int cpNextId, intfNextId;
220 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530221 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800222 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530223 true, install);
224 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Saurav Das49cb5a12016-01-16 22:54:07 -0800225 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530226 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800227 } else {
kishore71a27532016-03-16 20:23:49 +0530228 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
229 intf.vlan(), false, install);
230 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
231 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800232 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530233 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
234 TrafficSelector selector;
235 // IP traffic toward the router.
236 selector = buildIPDstSelector(
237 ip.ipAddress().toIpPrefix(),
238 intf.connectPoint().port(),
239 null,
240 intf.mac(),
241 intf.vlan()
242 );
243 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
244 // IP traffic from the router.
245 selector = buildIPSrcSelector(
246 ip.ipAddress().toIpPrefix(),
247 controlPlanePort,
248 intf.mac(),
249 null,
250 intf.vlan()
251 );
252 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
253 // We build the punt treatment.
254 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800255 .punt()
256 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530257 // Handling of neighbour discovery protocols.
258 // IPv4 traffic - we have to deal with the ARP protocol.
259 // IPv6 traffic - we have to deal with the NDP protocol.
260 if (ip.ipAddress().isIp4()) {
261 // ARP traffic towards the router.
262 selector = buildArpSelector(
263 intf.connectPoint().port(),
264 intf.vlan(),
265 null,
266 null
267 );
268 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
269 // ARP traffic from the router.
270 selector = buildArpSelector(
271 controlPlanePort,
272 intf.vlan(),
273 ip.ipAddress().getIp4Address(),
274 intf.mac()
275 );
276 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
277 } else {
278 // Neighbour solicitation traffic towards the router.
279 selector = buildNdpSelector(
280 intf.connectPoint().port(),
281 intf.vlan(),
282 null,
283 NEIGHBOR_SOLICITATION,
284 null
285 );
286 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
287 // Neighbour solicitation traffic from the router.
288 selector = buildNdpSelector(
289 controlPlanePort,
290 intf.vlan(),
291 ip.ipAddress().toIpPrefix(),
292 NEIGHBOR_SOLICITATION,
293 intf.mac()
294 );
295 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
296 // Neighbour advertisement traffic towards the router.
297 selector = buildNdpSelector(
298 intf.connectPoint().port(),
299 intf.vlan(),
300 null,
301 NEIGHBOR_ADVERTISEMENT,
302 null
303 );
304 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
305 // Neighbour advertisement traffic from the router.
306 selector = buildNdpSelector(
307 controlPlanePort,
308 intf.vlan(),
309 ip.ipAddress().toIpPrefix(),
310 NEIGHBOR_ADVERTISEMENT,
311 intf.mac()
312 );
313 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
314 }
315 // Finally we push the fwd objectives through the flow objective service.
316 fwdToSend.stream().forEach(forwardingObjective ->
317 flowObjectiveService.forward(deviceId, forwardingObjective)
318 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800319 }
320 }
321
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530322 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
323 MacAddress srcMac,
324 MacAddress dstMac,
325 VlanId vlanId) {
326 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
327 if (inPort != null) {
328 selectorBuilder.matchInPort(inPort);
329 }
330 if (srcMac != null) {
331 selectorBuilder.matchEthSrc(srcMac);
332 }
333 if (dstMac != null) {
334 selectorBuilder.matchEthDst(dstMac);
335 }
336 if (vlanId != null) {
337 selectorBuilder.matchVlanId(vlanId);
338 }
339 return selectorBuilder;
340 }
341
342 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
343 PortNumber inPort,
344 MacAddress srcMac,
345 MacAddress dstMac,
346 VlanId vlanId) {
347 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
348 if (dstIp.isIp4()) {
349 selector.matchEthType(TYPE_IPV4);
350 selector.matchIPDst(dstIp);
351 } else {
352 selector.matchEthType(TYPE_IPV6);
353 selector.matchIPv6Dst(dstIp);
354 }
355 return selector.build();
356 }
357
358 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
359 PortNumber inPort,
360 MacAddress srcMac,
361 MacAddress dstMac,
362 VlanId vlanId) {
363 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
364 if (srcIp.isIp4()) {
365 selector.matchEthType(TYPE_IPV4);
366 selector.matchIPSrc(srcIp);
367 } else {
368 selector.matchEthType(TYPE_IPV6);
369 selector.matchIPv6Src(srcIp);
370 }
371 return selector.build();
372 }
373
374 static TrafficSelector buildArpSelector(PortNumber inPort,
375 VlanId vlanId,
376 Ip4Address arpSpa,
377 MacAddress srcMac) {
378 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
379 selector.matchEthType(TYPE_ARP);
380 if (arpSpa != null) {
381 selector.matchArpSpa(arpSpa);
382 }
383 if (srcMac != null) {
384 selector.matchEthSrc(srcMac);
385 }
386 return selector.build();
387 }
388
389 static TrafficSelector buildNdpSelector(PortNumber inPort,
390 VlanId vlanId,
391 IpPrefix srcIp,
392 byte subProto,
393 MacAddress srcMac) {
394 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
395 selector.matchEthType(TYPE_IPV6)
396 .matchIPProtocol(PROTOCOL_ICMP6)
397 .matchIcmpv6Type(subProto);
398 if (srcIp != null) {
399 selector.matchIPv6Src(srcIp);
400 }
401 if (srcMac != null) {
402 selector.matchEthSrc(srcMac);
403 }
404 return selector.build();
405 }
406
kishore71a27532016-03-16 20:23:49 +0530407 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700408 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530409 *
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700410 * @param intf the interface on which event is received
kishore71a27532016-03-16 20:23:49 +0530411 * @param install true to create an add objective, false to create a remove
412 * objective
413 **/
414 private void updateOspfForwarding(Interface intf, boolean install) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530415 // FIXME IPv6 support has not been implemented yet
Jonathan Hartea492382016-01-13 09:33:13 -0800416 // OSPF to router
417 TrafficSelector toSelector = DefaultTrafficSelector.builder()
418 .matchInPort(intf.connectPoint().port())
419 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
420 .matchVlanId(intf.vlan())
421 .matchIPProtocol((byte) OSPF_IP_PROTO)
422 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800423
Saurav Das49cb5a12016-01-16 22:54:07 -0800424 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700425 DeviceId deviceId = intf.connectPoint().deviceId();
426 PortNumber controlPlanePort = intf.connectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800427 int cpNextId;
428 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530429 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800430 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530431 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800432 } else {
kishore71a27532016-03-16 20:23:49 +0530433 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
434 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800435 }
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700436 log.debug("OSPF flows intf:{} nextid:{}", intf, cpNextId);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700437 log.debug("install={}", install);
438 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530439 buildForwardingObjective(toSelector, null, cpNextId, install ? ospfEnabled : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800440 }
441
442 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800443 * Creates a next objective for forwarding to a port. Handles metadata for
444 * some pipelines that require vlan information for egress port.
445 *
446 * @param deviceId the device on which the next objective is being created
447 * @param portNumber the egress port
448 * @param vlanId vlan information for egress port
449 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530450 * @param install true to create an add next objective, false to create a remove
451 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800452 * @return nextId of the next objective created
453 */
kishore71a27532016-03-16 20:23:49 +0530454 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
455 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800456 int nextId = flowObjectiveService.allocateNextId();
457 NextObjective.Builder nextObjBuilder = DefaultNextObjective
458 .builder().withId(nextId)
459 .withType(NextObjective.Type.SIMPLE)
460 .fromApp(appId);
461
462 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
463 if (popVlan) {
464 ttBuilder.popVlan();
465 }
466 ttBuilder.setOutput(portNumber);
467
468 // setup metadata to pass to nextObjective - indicate the vlan on egress
469 // if needed by the switch pipeline.
470 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
471 metabuilder.matchVlanId(vlanId);
472
473 nextObjBuilder.withMeta(metabuilder.build());
474 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700475 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800476 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530477 if (install) {
478 flowObjectiveService.next(deviceId, nextObjBuilder.add());
479 } else {
480 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
481 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800482 return nextId;
483 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700484
Saurav Das49cb5a12016-01-16 22:54:07 -0800485 /**
486 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800487 *
488 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800489 * @param treatment treatment to apply to packet, can be null
490 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800491 * @param add true to create an add objective, false to create a remove
492 * objective
493 * @return forwarding objective
494 */
495 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
496 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800497 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530498 boolean add,
499 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800500 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
501 fobBuilder.withSelector(selector);
502 if (treatment != null) {
503 fobBuilder.withTreatment(treatment);
504 }
505 if (nextId != -1) {
506 fobBuilder.nextStep(nextId);
507 }
508 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530509 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800510 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800511
512 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800513 }
514
Jonathan Hartea492382016-01-13 09:33:13 -0800515 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800516 * Listener for network config events.
517 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800518 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530519
Jonathan Hart6344f572015-12-15 08:26:25 -0800520 @Override
521 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800522 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800523 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700524 case CONFIG_ADDED:
525 case CONFIG_UPDATED:
526 readConfig();
527 break;
528 case CONFIG_REGISTERED:
529 break;
530 case CONFIG_UNREGISTERED:
531 break;
532 case CONFIG_REMOVED:
533 removeConfig();
kishore36d1c272016-09-21 15:44:10 +0530534 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530535 default:
536 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800537 }
538 }
539 }
540 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800541
542 /**
543 * Listener for host events.
544 */
545 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530546
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700547 private Optional<Interface> getPeerInterface(Host peer) {
548 return interfaceService.getInterfacesByPort(peer.location()).stream()
549 .filter(intf -> interfaceManager.configuredInterfaces().isEmpty()
550 || interfaceManager.configuredInterfaces().contains(intf.name()))
Charles Chand0fd5dc2016-02-16 23:14:49 -0800551 .filter(intf -> peer.vlan().equals(intf.vlan()))
552 .findFirst();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700553 }
554
555 private void peerAdded(HostEvent event) {
556 Host peer = event.subject();
557 if (interfaceManager == null) {
558 return;
559 }
560
561 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800562 if (!peerIntf.isPresent()) {
563 log.debug("Adding peer {}/{} on {} but the interface is not configured",
564 peer.mac(), peer.vlan(), peer.location());
565 return;
566 }
567
568 // Generate L3 Unicast groups and store it in the map
569 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700570 peer.vlan(), peer.location().deviceId(), peerIntf.get().connectPoint().port());
Charles Chand0fd5dc2016-02-16 23:14:49 -0800571 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
572 peer.vlan(), peer.location().deviceId(), peer.location().port());
573 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
574
575 // From peer to router
576 peerIntf.get().ipAddresses().forEach(routerIp -> {
577 flowObjectiveService.forward(peer.location().deviceId(),
578 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
579 });
580
581 // From router to peer
582 peer.ipAddresses().forEach(peerIp -> {
583 flowObjectiveService.forward(peer.location().deviceId(),
584 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
585 });
586 }
587
588 private void peerRemoved(HostEvent event) {
589 Host peer = event.subject();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700590 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800591 if (!peerIntf.isPresent()) {
592 log.debug("Removing peer {}/{} on {} but the interface is not configured",
593 peer.mac(), peer.vlan(), peer.location());
594 return;
595 }
596
Charles Chand0fd5dc2016-02-16 23:14:49 -0800597 checkState(peerNextId.get(peer) != null,
598 "Peer nextId should not be null");
599 checkState(peerNextId.get(peer).size() == 2,
600 "Wrong nextId associated with the peer");
601 Iterator<Integer> iter = peerNextId.get(peer).iterator();
602 int toRouterL3Unicast = iter.next();
603 int toPeerL3Unicast = iter.next();
604
605 // From peer to router
606 peerIntf.get().ipAddresses().forEach(routerIp -> {
607 flowObjectiveService.forward(peer.location().deviceId(),
608 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
609 });
610
611 // From router to peer
612 peer.ipAddresses().forEach(peerIp -> {
613 flowObjectiveService.forward(peer.location().deviceId(),
614 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
615 });
616 }
617
618 private ForwardingObjective.Builder createPeerObjBuilder(
619 int nextId, IpPrefix ipAddresses) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530620 TrafficSelector selector = buildIPDstSelector(ipAddresses, null, null, null, null);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800621 DefaultForwardingObjective.Builder builder =
622 DefaultForwardingObjective.builder()
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530623 .withSelector(selector)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800624 .fromApp(appId)
625 .withPriority(getPriorityFromPrefix(ipAddresses))
626 .withFlag(ForwardingObjective.Flag.SPECIFIC);
627 if (nextId != -1) {
628 builder.nextStep(nextId);
629 }
630 return builder;
631 }
632
633 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
634 VlanId vlanId, DeviceId deviceId, PortNumber port) {
635 int nextId = flowObjectiveService.allocateNextId();
636 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
637 .withId(nextId)
638 .withType(NextObjective.Type.SIMPLE)
639 .fromApp(appId);
640
641 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
642 ttBuilder.setEthSrc(srcMac);
643 ttBuilder.setEthDst(dstMac);
644 ttBuilder.setOutput(port);
645 nextObjBuilder.addTreatment(ttBuilder.build());
646
647 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
648 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
649 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN) :
650 vlanId;
651 metabuilder.matchVlanId(matchVlanId);
652 nextObjBuilder.withMeta(metabuilder.build());
653
654 flowObjectiveService.next(deviceId, nextObjBuilder.add());
655 return nextId;
656 }
657
658 @Override
659 public void event(HostEvent event) {
660 DeviceId deviceId = event.subject().location().deviceId();
661 if (!mastershipService.isLocalMaster(deviceId)) {
662 return;
663 }
664 switch (event.type()) {
665 case HOST_ADDED:
666 peerAdded(event);
667 break;
668 case HOST_MOVED:
669 //TODO We assume BGP peer does not move for now
670 break;
671 case HOST_REMOVED:
672 peerRemoved(event);
673 break;
674 case HOST_UPDATED:
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530675 //FIXME We assume BGP peer does not change IP for now
676 // but we can discover new address.
Charles Chand0fd5dc2016-02-16 23:14:49 -0800677 break;
678 default:
679 break;
680 }
681 }
682 }
683
684 private int getPriorityFromPrefix(IpPrefix prefix) {
685 return (prefix.isIp4()) ?
kishore36d1c272016-09-21 15:44:10 +0530686 IPV4_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY :
687 IPV6_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY;
688 }
689
kishore36d1c272016-09-21 15:44:10 +0530690 private void removeConfig() {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700691 if (interfaceManager != null) {
692 interfaceManager.cleanup();
kishore7c42cbe2016-04-26 22:49:36 +0530693 }
694 }
695
Jonathan Hart6344f572015-12-15 08:26:25 -0800696}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530697