blob: 4430f5efd33abf1283dd34d72fd2bc98c1d51606 [file] [log] [blame]
Jonathan Hart6344f572015-12-15 08:26:25 -08001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
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;
20import com.google.common.collect.Maps;
Jonathan Hart6344f572015-12-15 08:26:25 -080021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.onlab.packet.EthType;
Charles Chand0fd5dc2016-02-16 23:14:49 -080027import org.onlab.packet.IpPrefix;
28import org.onlab.packet.MacAddress;
Saurav Das49cb5a12016-01-16 22:54:07 -080029import org.onlab.packet.VlanId;
Jonathan Hart6344f572015-12-15 08:26:25 -080030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.incubator.net.intf.Interface;
kishore71a27532016-03-16 20:23:49 +053033import org.onosproject.incubator.net.intf.InterfaceEvent;
34import org.onosproject.incubator.net.intf.InterfaceListener;
Jonathan Hart6344f572015-12-15 08:26:25 -080035import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080036import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080037import org.onosproject.net.ConnectPoint;
38import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080039import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080040import org.onosproject.net.PortNumber;
41import org.onosproject.net.config.NetworkConfigEvent;
42import org.onosproject.net.config.NetworkConfigListener;
43import org.onosproject.net.config.NetworkConfigService;
44import org.onosproject.net.device.DeviceEvent;
45import org.onosproject.net.device.DeviceListener;
46import 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.Collections;
65import java.util.Iterator;
66import java.util.List;
67import java.util.Map;
68import java.util.Optional;
69import java.util.Set;
70
71import static com.google.common.base.Preconditions.checkState;
72import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080073
74/**
75 * Manages connectivity between peers redirecting control traffic to a routing
76 * control plane available on the dataplane.
77 */
78@Component(immediate = true, enabled = false)
79public class ControlPlaneRedirectManager {
80
81 private final Logger log = getLogger(getClass());
82
Charles Chand0fd5dc2016-02-16 23:14:49 -080083 private static final int MIN_IP_PRIORITY = 10;
84 private static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080085 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -080086
87 private static final String APP_NAME = "org.onosproject.cpredirect";
88 private ApplicationId appId;
89
90 private ConnectPoint controlPlaneConnectPoint;
Jonathan Hartea492382016-01-13 09:33:13 -080091 private boolean ospfEnabled = false;
Jonathan Hart883fd372016-02-10 14:36:15 -080092 private List<String> interfaces = Collections.emptyList();
Charles Chand0fd5dc2016-02-16 23:14:49 -080093 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
Jonathan Hart6344f572015-12-15 08:26:25 -080094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected CoreService coreService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected DeviceService deviceService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected InterfaceService interfaceService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected FlowObjectiveService flowObjectiveService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected NetworkConfigService networkConfigService;
109
Charles Chand0fd5dc2016-02-16 23:14:49 -0800110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected MastershipService mastershipService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected HostService hostService;
115
Jonathan Hart6344f572015-12-15 08:26:25 -0800116 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
117 private final InternalNetworkConfigListener networkConfigListener =
118 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800119 private final InternalHostListener hostListener = new InternalHostListener();
kishore71a27532016-03-16 20:23:49 +0530120 private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800121
122 @Activate
123 public void activate() {
124 this.appId = coreService.registerApplication(APP_NAME);
125
126 deviceService.addListener(deviceListener);
127 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800128 hostService.addListener(hostListener);
kishore71a27532016-03-16 20:23:49 +0530129 interfaceService.addListener(interfaceListener);
Jonathan Hart6344f572015-12-15 08:26:25 -0800130
131 updateConfig();
132 }
133
134 @Deactivate
135 public void deactivate() {
136 deviceService.removeListener(deviceListener);
137 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800138 hostService.removeListener(hostListener);
kishore71a27532016-03-16 20:23:49 +0530139 interfaceService.removeListener(interfaceListener);
Jonathan Hart6344f572015-12-15 08:26:25 -0800140 }
141
142 private void updateConfig() {
143 ApplicationId routingAppId =
144 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
145
146 RouterConfig config = networkConfigService.getConfig(
147 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
148
149 if (config == null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800150 log.warn("Router config not available");
Jonathan Hart6344f572015-12-15 08:26:25 -0800151 return;
152 }
153
Jonathan Hartea492382016-01-13 09:33:13 -0800154 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
155 ospfEnabled = config.getOspfEnabled();
Jonathan Hart883fd372016-02-10 14:36:15 -0800156 interfaces = config.getInterfaces();
Jonathan Hart6344f572015-12-15 08:26:25 -0800157
Jonathan Hartea492382016-01-13 09:33:13 -0800158 updateDevice();
159 }
160
161 private void updateDevice() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800162 if (controlPlaneConnectPoint != null &&
163 deviceService.isAvailable(controlPlaneConnectPoint.deviceId())) {
Jonathan Hartea492382016-01-13 09:33:13 -0800164 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
165
166 interfaceService.getInterfaces().stream()
167 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
Jonathan Hart883fd372016-02-10 14:36:15 -0800168 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
Jonathan Hartea492382016-01-13 09:33:13 -0800169 .forEach(this::provisionInterface);
170
171 log.info("Set up interfaces on {}", controlPlaneConnectPoint.deviceId());
Jonathan Hart6344f572015-12-15 08:26:25 -0800172 }
173 }
174
kishore71a27532016-03-16 20:23:49 +0530175 private void removeInterface(Interface intf) {
176 modifyBasicInterfaceForwarding(intf, false);
177 updateOspfForwarding(intf, false);
Jonathan Hart6344f572015-12-15 08:26:25 -0800178 }
179
kishore71a27532016-03-16 20:23:49 +0530180 private void provisionInterface(Interface intf) {
181 modifyBasicInterfaceForwarding(intf, true);
182 updateOspfForwarding(intf, true);
183 }
184 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700185 * Installs or removes the basic forwarding flows for each interface
kishore71a27532016-03-16 20:23:49 +0530186 * based on the flag used.
187 *
188 * @param intf the Interface on which event is received
189 * @param install true to create an add objective, false to create a remove
190 * objective
191 **/
192 private void modifyBasicInterfaceForwarding(Interface intf, boolean install) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800193 log.debug("Adding interface objectives for {}", intf);
194
195 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
196 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800197 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800198 // create nextObjectives for forwarding to this interface and the
199 // controlPlaneConnectPoint
200 int cpNextId, intfNextId;
201 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530202 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800203 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530204 true, install);
205 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Saurav Das49cb5a12016-01-16 22:54:07 -0800206 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530207 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800208 } else {
kishore71a27532016-03-16 20:23:49 +0530209 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
210 intf.vlan(), false, install);
211 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
212 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800213 }
214
Jonathan Hart6344f572015-12-15 08:26:25 -0800215 // IPv4 to router
216 TrafficSelector toSelector = DefaultTrafficSelector.builder()
217 .matchInPort(intf.connectPoint().port())
218 .matchEthDst(intf.mac())
219 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
220 .matchVlanId(intf.vlan())
221 .matchIPDst(ip.ipAddress().toIpPrefix())
222 .build();
223
Jonathan Hart6344f572015-12-15 08:26:25 -0800224 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530225 buildForwardingObjective(toSelector, null, cpNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800226
227 // IPv4 from router
228 TrafficSelector fromSelector = DefaultTrafficSelector.builder()
229 .matchInPort(controlPlanePort)
230 .matchEthSrc(intf.mac())
231 .matchVlanId(intf.vlan())
232 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
233 .matchIPSrc(ip.ipAddress().toIpPrefix())
234 .build();
235
Jonathan Hart6344f572015-12-15 08:26:25 -0800236 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530237 buildForwardingObjective(fromSelector, null, intfNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800238
239 // ARP to router
240 toSelector = DefaultTrafficSelector.builder()
241 .matchInPort(intf.connectPoint().port())
242 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
243 .matchVlanId(intf.vlan())
244 .build();
245
Saurav Das49cb5a12016-01-16 22:54:07 -0800246 TrafficTreatment puntTreatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800247 .punt()
248 .build();
249
250 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530251 buildForwardingObjective(toSelector, puntTreatment, cpNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800252
253 // ARP from router
254 fromSelector = DefaultTrafficSelector.builder()
255 .matchInPort(controlPlanePort)
256 .matchEthSrc(intf.mac())
257 .matchVlanId(intf.vlan())
258 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
Saurav Das49cb5a12016-01-16 22:54:07 -0800259 .matchArpSpa(ip.ipAddress().getIp4Address())
Jonathan Hart6344f572015-12-15 08:26:25 -0800260 .build();
261
262 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530263 buildForwardingObjective(fromSelector, puntTreatment, intfNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800264 }
265 }
266
kishore71a27532016-03-16 20:23:49 +0530267 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700268 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530269 *
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700270 * @param intf the interface on which event is received
kishore71a27532016-03-16 20:23:49 +0530271 * @param install true to create an add objective, false to create a remove
272 * objective
273 **/
274 private void updateOspfForwarding(Interface intf, boolean install) {
Jonathan Hartea492382016-01-13 09:33:13 -0800275 // OSPF to router
276 TrafficSelector toSelector = DefaultTrafficSelector.builder()
277 .matchInPort(intf.connectPoint().port())
278 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
279 .matchVlanId(intf.vlan())
280 .matchIPProtocol((byte) OSPF_IP_PROTO)
281 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800282
Saurav Das49cb5a12016-01-16 22:54:07 -0800283 // create nextObjectives for forwarding to the controlPlaneConnectPoint
284 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
285 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
286 int cpNextId;
287 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530288 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800289 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530290 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800291 } else {
kishore71a27532016-03-16 20:23:49 +0530292 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
293 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800294 }
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700295 log.debug("OSPF flows intf:{} nextid:{}", intf, cpNextId);
Jonathan Hartea492382016-01-13 09:33:13 -0800296 flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(),
kishore71a27532016-03-16 20:23:49 +0530297 buildForwardingObjective(toSelector, null, cpNextId, install ? ospfEnabled : install));
Jonathan Hartea492382016-01-13 09:33:13 -0800298 }
299
300 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800301 * Creates a next objective for forwarding to a port. Handles metadata for
302 * some pipelines that require vlan information for egress port.
303 *
304 * @param deviceId the device on which the next objective is being created
305 * @param portNumber the egress port
306 * @param vlanId vlan information for egress port
307 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530308 * @param install true to create an add next objective, false to create a remove
309 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800310 * @return nextId of the next objective created
311 */
kishore71a27532016-03-16 20:23:49 +0530312 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
313 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800314 int nextId = flowObjectiveService.allocateNextId();
315 NextObjective.Builder nextObjBuilder = DefaultNextObjective
316 .builder().withId(nextId)
317 .withType(NextObjective.Type.SIMPLE)
318 .fromApp(appId);
319
320 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
321 if (popVlan) {
322 ttBuilder.popVlan();
323 }
324 ttBuilder.setOutput(portNumber);
325
326 // setup metadata to pass to nextObjective - indicate the vlan on egress
327 // if needed by the switch pipeline.
328 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
329 metabuilder.matchVlanId(vlanId);
330
331 nextObjBuilder.withMeta(metabuilder.build());
332 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700333 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800334 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530335 if (install) {
336 flowObjectiveService.next(deviceId, nextObjBuilder.add());
337 } else {
338 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
339 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800340 return nextId;
341 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800342 /**
343 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800344 *
345 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800346 * @param treatment treatment to apply to packet, can be null
347 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800348 * @param add true to create an add objective, false to create a remove
349 * objective
350 * @return forwarding objective
351 */
352 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
353 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800354 int nextId,
Jonathan Hartea492382016-01-13 09:33:13 -0800355 boolean add) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800356 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
357 fobBuilder.withSelector(selector);
358 if (treatment != null) {
359 fobBuilder.withTreatment(treatment);
360 }
361 if (nextId != -1) {
362 fobBuilder.nextStep(nextId);
363 }
364 fobBuilder.fromApp(appId)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800365 .withPriority(ACL_PRIORITY)
Saurav Das49cb5a12016-01-16 22:54:07 -0800366 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800367
368 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800369 }
370
Jonathan Hartea492382016-01-13 09:33:13 -0800371 /**
372 * Listener for device events.
373 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800374 private class InternalDeviceListener implements DeviceListener {
kishore71a27532016-03-16 20:23:49 +0530375
Jonathan Hart6344f572015-12-15 08:26:25 -0800376 @Override
377 public void event(DeviceEvent event) {
378 if (controlPlaneConnectPoint != null &&
379 event.subject().id().equals(controlPlaneConnectPoint.deviceId())) {
380 switch (event.type()) {
381 case DEVICE_ADDED:
382 case DEVICE_AVAILABILITY_CHANGED:
383 if (deviceService.isAvailable(event.subject().id())) {
384 log.info("Device connected {}", event.subject().id());
Jonathan Hartea492382016-01-13 09:33:13 -0800385 updateDevice();
Jonathan Hart6344f572015-12-15 08:26:25 -0800386 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800387 break;
388 case DEVICE_UPDATED:
389 case DEVICE_REMOVED:
390 case DEVICE_SUSPENDED:
391 case PORT_ADDED:
392 case PORT_UPDATED:
393 case PORT_REMOVED:
394 default:
395 break;
396 }
397 }
398 }
399 }
400
Jonathan Hartea492382016-01-13 09:33:13 -0800401 /**
402 * Listener for network config events.
403 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800404 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530405
Jonathan Hart6344f572015-12-15 08:26:25 -0800406 @Override
407 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800408 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800409 switch (event.type()) {
410 case CONFIG_ADDED:
411 case CONFIG_UPDATED:
412 updateConfig();
413 break;
414 case CONFIG_REGISTERED:
415 case CONFIG_UNREGISTERED:
416 case CONFIG_REMOVED:
417 default:
418 break;
419 }
420 }
421 }
422 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800423
424 /**
425 * Listener for host events.
426 */
427 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530428
Charles Chand0fd5dc2016-02-16 23:14:49 -0800429 private void peerAdded(HostEvent event) {
430 Host peer = event.subject();
431 Optional<Interface> peerIntf =
432 interfaceService.getInterfacesByPort(peer.location()).stream()
433 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
434 .filter(intf -> peer.vlan().equals(intf.vlan()))
435 .findFirst();
436 if (!peerIntf.isPresent()) {
437 log.debug("Adding peer {}/{} on {} but the interface is not configured",
438 peer.mac(), peer.vlan(), peer.location());
439 return;
440 }
441
442 // Generate L3 Unicast groups and store it in the map
443 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
444 peer.vlan(), peer.location().deviceId(), controlPlaneConnectPoint.port());
445 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
446 peer.vlan(), peer.location().deviceId(), peer.location().port());
447 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
448
449 // From peer to router
450 peerIntf.get().ipAddresses().forEach(routerIp -> {
451 flowObjectiveService.forward(peer.location().deviceId(),
452 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
453 });
454
455 // From router to peer
456 peer.ipAddresses().forEach(peerIp -> {
457 flowObjectiveService.forward(peer.location().deviceId(),
458 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
459 });
460 }
461
462 private void peerRemoved(HostEvent event) {
463 Host peer = event.subject();
464 Optional<Interface> peerIntf =
465 interfaceService.getInterfacesByPort(peer.location()).stream()
466 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
467 .filter(intf -> peer.vlan().equals(intf.vlan()))
468 .findFirst();
469 if (!peerIntf.isPresent()) {
470 log.debug("Removing peer {}/{} on {} but the interface is not configured",
471 peer.mac(), peer.vlan(), peer.location());
472 return;
473 }
474
475 Set<Integer> nextIds = peerNextId.get(peer);
476 checkState(peerNextId.get(peer) != null,
477 "Peer nextId should not be null");
478 checkState(peerNextId.get(peer).size() == 2,
479 "Wrong nextId associated with the peer");
480 Iterator<Integer> iter = peerNextId.get(peer).iterator();
481 int toRouterL3Unicast = iter.next();
482 int toPeerL3Unicast = iter.next();
483
484 // From peer to router
485 peerIntf.get().ipAddresses().forEach(routerIp -> {
486 flowObjectiveService.forward(peer.location().deviceId(),
487 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
488 });
489
490 // From router to peer
491 peer.ipAddresses().forEach(peerIp -> {
492 flowObjectiveService.forward(peer.location().deviceId(),
493 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
494 });
495 }
496
497 private ForwardingObjective.Builder createPeerObjBuilder(
498 int nextId, IpPrefix ipAddresses) {
499 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
500 sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
501 sbuilder.matchIPDst(ipAddresses);
502 DefaultForwardingObjective.Builder builder =
503 DefaultForwardingObjective.builder()
504 .withSelector(sbuilder.build())
505 .fromApp(appId)
506 .withPriority(getPriorityFromPrefix(ipAddresses))
507 .withFlag(ForwardingObjective.Flag.SPECIFIC);
508 if (nextId != -1) {
509 builder.nextStep(nextId);
510 }
511 return builder;
512 }
513
514 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
515 VlanId vlanId, DeviceId deviceId, PortNumber port) {
516 int nextId = flowObjectiveService.allocateNextId();
517 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
518 .withId(nextId)
519 .withType(NextObjective.Type.SIMPLE)
520 .fromApp(appId);
521
522 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
523 ttBuilder.setEthSrc(srcMac);
524 ttBuilder.setEthDst(dstMac);
525 ttBuilder.setOutput(port);
526 nextObjBuilder.addTreatment(ttBuilder.build());
527
528 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
529 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
530 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN) :
531 vlanId;
532 metabuilder.matchVlanId(matchVlanId);
533 nextObjBuilder.withMeta(metabuilder.build());
534
535 flowObjectiveService.next(deviceId, nextObjBuilder.add());
536 return nextId;
537 }
538
539 @Override
540 public void event(HostEvent event) {
541 DeviceId deviceId = event.subject().location().deviceId();
542 if (!mastershipService.isLocalMaster(deviceId)) {
543 return;
544 }
545 switch (event.type()) {
546 case HOST_ADDED:
547 peerAdded(event);
548 break;
549 case HOST_MOVED:
550 //TODO We assume BGP peer does not move for now
551 break;
552 case HOST_REMOVED:
553 peerRemoved(event);
554 break;
555 case HOST_UPDATED:
556 //TODO We assume BGP peer does not change IP for now
557 break;
558 default:
559 break;
560 }
561 }
562 }
563
564 private int getPriorityFromPrefix(IpPrefix prefix) {
565 return (prefix.isIp4()) ?
566 2000 * prefix.prefixLength() + MIN_IP_PRIORITY :
567 500 * prefix.prefixLength() + MIN_IP_PRIORITY;
568 }
kishore71a27532016-03-16 20:23:49 +0530569 private class InternalInterfaceListener implements InterfaceListener {
570
571 @Override
572 public void event(InterfaceEvent event) {
573 Interface intf = event.subject();
574 switch (event.type()) {
575 case INTERFACE_ADDED:
576 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
577 provisionInterface(intf);
578 }
579 break;
580 case INTERFACE_UPDATED:
581 break;
582 case INTERFACE_REMOVED:
583 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
584 removeInterface(intf);
585 }
586 break;
587 default:
588 break;
589 }
590 }
591 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800592}