blob: 49dc0ed6c77ccd64c6602c3feaa500caef3bf45b [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;
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;
kishore786b7e42016-05-19 16:25:57 +053030import org.onosproject.app.ApplicationService;
Jonathan Hart6344f572015-12-15 08:26:25 -080031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.incubator.net.intf.Interface;
kishore71a27532016-03-16 20:23:49 +053034import org.onosproject.incubator.net.intf.InterfaceEvent;
35import org.onosproject.incubator.net.intf.InterfaceListener;
Jonathan Hart6344f572015-12-15 08:26:25 -080036import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080037import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080038import org.onosproject.net.ConnectPoint;
39import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080040import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080041import org.onosproject.net.PortNumber;
42import org.onosproject.net.config.NetworkConfigEvent;
43import org.onosproject.net.config.NetworkConfigListener;
44import org.onosproject.net.config.NetworkConfigService;
45import org.onosproject.net.device.DeviceEvent;
46import org.onosproject.net.device.DeviceListener;
47import 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;
61import org.onosproject.routing.RoutingService;
62import org.onosproject.routing.config.RouterConfig;
63import org.slf4j.Logger;
64
Jonathan Hartf04b7d92016-03-29 09:39:11 -070065import java.util.Collections;
66import java.util.Iterator;
67import java.util.List;
68import java.util.Map;
69import java.util.Optional;
70import java.util.Set;
kishore7c42cbe2016-04-26 22:49:36 +053071import java.util.stream.Collectors;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070072
73import static com.google.common.base.Preconditions.checkState;
74import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080075
76/**
77 * Manages connectivity between peers redirecting control traffic to a routing
78 * control plane available on the dataplane.
79 */
80@Component(immediate = true, enabled = false)
81public class ControlPlaneRedirectManager {
82
83 private final Logger log = getLogger(getClass());
84
Charles Chand0fd5dc2016-02-16 23:14:49 -080085 private static final int MIN_IP_PRIORITY = 10;
86 private static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080087 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -080088
kishore786b7e42016-05-19 16:25:57 +053089 private static final String APP_NAME = "org.onosproject.vrouter";
Jonathan Hart6344f572015-12-15 08:26:25 -080090 private ApplicationId appId;
91
92 private ConnectPoint controlPlaneConnectPoint;
Jonathan Hartea492382016-01-13 09:33:13 -080093 private boolean ospfEnabled = false;
Jonathan Hart883fd372016-02-10 14:36:15 -080094 private List<String> interfaces = Collections.emptyList();
Charles Chand0fd5dc2016-02-16 23:14:49 -080095 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
Jonathan Hart6344f572015-12-15 08:26:25 -080096
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected CoreService coreService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected DeviceService deviceService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected InterfaceService interfaceService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected FlowObjectiveService flowObjectiveService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected NetworkConfigService networkConfigService;
111
Charles Chand0fd5dc2016-02-16 23:14:49 -0800112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected MastershipService mastershipService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected HostService hostService;
117
kishore786b7e42016-05-19 16:25:57 +0530118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected ApplicationService applicationService;
120
Jonathan Hart6344f572015-12-15 08:26:25 -0800121 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
122 private final InternalNetworkConfigListener networkConfigListener =
123 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800124 private final InternalHostListener hostListener = new InternalHostListener();
kishore71a27532016-03-16 20:23:49 +0530125 private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800126
127 @Activate
128 public void activate() {
129 this.appId = coreService.registerApplication(APP_NAME);
130
131 deviceService.addListener(deviceListener);
132 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800133 hostService.addListener(hostListener);
kishore71a27532016-03-16 20:23:49 +0530134 interfaceService.addListener(interfaceListener);
Jonathan Hart6344f572015-12-15 08:26:25 -0800135
kishore786b7e42016-05-19 16:25:57 +0530136 updateConfig(true);
137 applicationService.registerDeactivateHook(this.appId, () -> {
138 this.updateConfig(false);
139 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800140 }
141
142 @Deactivate
143 public void deactivate() {
144 deviceService.removeListener(deviceListener);
145 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800146 hostService.removeListener(hostListener);
kishore71a27532016-03-16 20:23:49 +0530147 interfaceService.removeListener(interfaceListener);
Jonathan Hart6344f572015-12-15 08:26:25 -0800148 }
149
kishore786b7e42016-05-19 16:25:57 +0530150 /**
151 * Installs or removes interface configuration
152 * based on the flag used on activate or deactivate.
153 *
154 * @param operation true on activate application, false on deactivate
155 * the application
156 **/
157 private void updateConfig(boolean operation) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800158 ApplicationId routingAppId =
159 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
160
161 RouterConfig config = networkConfigService.getConfig(
162 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
163
164 if (config == null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800165 log.warn("Router config not available");
Jonathan Hart6344f572015-12-15 08:26:25 -0800166 return;
167 }
168
Jonathan Hartea492382016-01-13 09:33:13 -0800169 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
170 ospfEnabled = config.getOspfEnabled();
Jonathan Hart883fd372016-02-10 14:36:15 -0800171 interfaces = config.getInterfaces();
Jonathan Hart6344f572015-12-15 08:26:25 -0800172
kishore786b7e42016-05-19 16:25:57 +0530173 updateDevice(operation);
Jonathan Hartea492382016-01-13 09:33:13 -0800174 }
175
kishore786b7e42016-05-19 16:25:57 +0530176 /**
177 * Installs or removes interface configuration for each interface
178 * based on the flag used on activate or deactivate.
179 *
180 * @param operation true on activate application, false on deactivate
181 * the application
182 **/
183 private void updateDevice(boolean operation) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800184 if (controlPlaneConnectPoint != null &&
185 deviceService.isAvailable(controlPlaneConnectPoint.deviceId())) {
Jonathan Hartea492382016-01-13 09:33:13 -0800186 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
187
188 interfaceService.getInterfaces().stream()
189 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
Jonathan Hart883fd372016-02-10 14:36:15 -0800190 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
kishore786b7e42016-05-19 16:25:57 +0530191 .forEach(operation ? this::provisionInterface : this::removeInterface);
Jonathan Hartea492382016-01-13 09:33:13 -0800192
193 log.info("Set up interfaces on {}", controlPlaneConnectPoint.deviceId());
Jonathan Hart6344f572015-12-15 08:26:25 -0800194 }
195 }
196
kishore71a27532016-03-16 20:23:49 +0530197 private void removeInterface(Interface intf) {
198 modifyBasicInterfaceForwarding(intf, false);
199 updateOspfForwarding(intf, false);
Jonathan Hart6344f572015-12-15 08:26:25 -0800200 }
201
kishore71a27532016-03-16 20:23:49 +0530202 private void provisionInterface(Interface intf) {
203 modifyBasicInterfaceForwarding(intf, true);
204 updateOspfForwarding(intf, true);
205 }
206 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700207 * Installs or removes the basic forwarding flows for each interface
kishore71a27532016-03-16 20:23:49 +0530208 * based on the flag used.
209 *
210 * @param intf the Interface on which event is received
211 * @param install true to create an add objective, false to create a remove
212 * objective
213 **/
214 private void modifyBasicInterfaceForwarding(Interface intf, boolean install) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800215 log.debug("Adding interface objectives for {}", intf);
216
217 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
218 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800219 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800220 // create nextObjectives for forwarding to this interface and the
221 // controlPlaneConnectPoint
222 int cpNextId, intfNextId;
223 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530224 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800225 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530226 true, install);
227 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Saurav Das49cb5a12016-01-16 22:54:07 -0800228 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530229 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800230 } else {
kishore71a27532016-03-16 20:23:49 +0530231 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
232 intf.vlan(), false, install);
233 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
234 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800235 }
236
Jonathan Hart6344f572015-12-15 08:26:25 -0800237 // IPv4 to router
238 TrafficSelector toSelector = DefaultTrafficSelector.builder()
239 .matchInPort(intf.connectPoint().port())
240 .matchEthDst(intf.mac())
241 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
242 .matchVlanId(intf.vlan())
243 .matchIPDst(ip.ipAddress().toIpPrefix())
244 .build();
245
Jonathan Hart6344f572015-12-15 08:26:25 -0800246 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530247 buildForwardingObjective(toSelector, null, cpNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800248
249 // IPv4 from router
250 TrafficSelector fromSelector = DefaultTrafficSelector.builder()
251 .matchInPort(controlPlanePort)
252 .matchEthSrc(intf.mac())
253 .matchVlanId(intf.vlan())
254 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
255 .matchIPSrc(ip.ipAddress().toIpPrefix())
256 .build();
257
Jonathan Hart6344f572015-12-15 08:26:25 -0800258 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530259 buildForwardingObjective(fromSelector, null, intfNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800260
261 // ARP to router
262 toSelector = DefaultTrafficSelector.builder()
263 .matchInPort(intf.connectPoint().port())
264 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
265 .matchVlanId(intf.vlan())
266 .build();
267
Saurav Das49cb5a12016-01-16 22:54:07 -0800268 TrafficTreatment puntTreatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800269 .punt()
270 .build();
271
272 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530273 buildForwardingObjective(toSelector, puntTreatment, cpNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800274
275 // ARP from router
276 fromSelector = DefaultTrafficSelector.builder()
277 .matchInPort(controlPlanePort)
278 .matchEthSrc(intf.mac())
279 .matchVlanId(intf.vlan())
280 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
Saurav Das49cb5a12016-01-16 22:54:07 -0800281 .matchArpSpa(ip.ipAddress().getIp4Address())
Jonathan Hart6344f572015-12-15 08:26:25 -0800282 .build();
283
284 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530285 buildForwardingObjective(fromSelector, puntTreatment, intfNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800286 }
287 }
288
kishore71a27532016-03-16 20:23:49 +0530289 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700290 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530291 *
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700292 * @param intf the interface on which event is received
kishore71a27532016-03-16 20:23:49 +0530293 * @param install true to create an add objective, false to create a remove
294 * objective
295 **/
296 private void updateOspfForwarding(Interface intf, boolean install) {
Jonathan Hartea492382016-01-13 09:33:13 -0800297 // OSPF to router
298 TrafficSelector toSelector = DefaultTrafficSelector.builder()
299 .matchInPort(intf.connectPoint().port())
300 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
301 .matchVlanId(intf.vlan())
302 .matchIPProtocol((byte) OSPF_IP_PROTO)
303 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800304
Saurav Das49cb5a12016-01-16 22:54:07 -0800305 // create nextObjectives for forwarding to the controlPlaneConnectPoint
306 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
307 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
308 int cpNextId;
309 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530310 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800311 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530312 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800313 } else {
kishore71a27532016-03-16 20:23:49 +0530314 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
315 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800316 }
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700317 log.debug("OSPF flows intf:{} nextid:{}", intf, cpNextId);
Jonathan Hartea492382016-01-13 09:33:13 -0800318 flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(),
kishore71a27532016-03-16 20:23:49 +0530319 buildForwardingObjective(toSelector, null, cpNextId, install ? ospfEnabled : install));
Jonathan Hartea492382016-01-13 09:33:13 -0800320 }
321
322 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800323 * Creates a next objective for forwarding to a port. Handles metadata for
324 * some pipelines that require vlan information for egress port.
325 *
326 * @param deviceId the device on which the next objective is being created
327 * @param portNumber the egress port
328 * @param vlanId vlan information for egress port
329 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530330 * @param install true to create an add next objective, false to create a remove
331 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800332 * @return nextId of the next objective created
333 */
kishore71a27532016-03-16 20:23:49 +0530334 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
335 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800336 int nextId = flowObjectiveService.allocateNextId();
337 NextObjective.Builder nextObjBuilder = DefaultNextObjective
338 .builder().withId(nextId)
339 .withType(NextObjective.Type.SIMPLE)
340 .fromApp(appId);
341
342 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
343 if (popVlan) {
344 ttBuilder.popVlan();
345 }
346 ttBuilder.setOutput(portNumber);
347
348 // setup metadata to pass to nextObjective - indicate the vlan on egress
349 // if needed by the switch pipeline.
350 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
351 metabuilder.matchVlanId(vlanId);
352
353 nextObjBuilder.withMeta(metabuilder.build());
354 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700355 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800356 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530357 if (install) {
358 flowObjectiveService.next(deviceId, nextObjBuilder.add());
359 } else {
360 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
361 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800362 return nextId;
363 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800364 /**
365 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800366 *
367 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800368 * @param treatment treatment to apply to packet, can be null
369 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800370 * @param add true to create an add objective, false to create a remove
371 * objective
372 * @return forwarding objective
373 */
374 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
375 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800376 int nextId,
Jonathan Hartea492382016-01-13 09:33:13 -0800377 boolean add) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800378 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
379 fobBuilder.withSelector(selector);
380 if (treatment != null) {
381 fobBuilder.withTreatment(treatment);
382 }
383 if (nextId != -1) {
384 fobBuilder.nextStep(nextId);
385 }
386 fobBuilder.fromApp(appId)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800387 .withPriority(ACL_PRIORITY)
Saurav Das49cb5a12016-01-16 22:54:07 -0800388 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800389
390 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800391 }
392
Jonathan Hartea492382016-01-13 09:33:13 -0800393 /**
394 * Listener for device events.
395 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800396 private class InternalDeviceListener implements DeviceListener {
kishore71a27532016-03-16 20:23:49 +0530397
Jonathan Hart6344f572015-12-15 08:26:25 -0800398 @Override
399 public void event(DeviceEvent event) {
400 if (controlPlaneConnectPoint != null &&
401 event.subject().id().equals(controlPlaneConnectPoint.deviceId())) {
402 switch (event.type()) {
403 case DEVICE_ADDED:
404 case DEVICE_AVAILABILITY_CHANGED:
405 if (deviceService.isAvailable(event.subject().id())) {
406 log.info("Device connected {}", event.subject().id());
kishore786b7e42016-05-19 16:25:57 +0530407 updateDevice(true);
Jonathan Hart6344f572015-12-15 08:26:25 -0800408 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800409 break;
410 case DEVICE_UPDATED:
411 case DEVICE_REMOVED:
412 case DEVICE_SUSPENDED:
413 case PORT_ADDED:
414 case PORT_UPDATED:
415 case PORT_REMOVED:
416 default:
417 break;
418 }
419 }
420 }
421 }
422
Jonathan Hartea492382016-01-13 09:33:13 -0800423 /**
424 * Listener for network config events.
425 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800426 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530427
Jonathan Hart6344f572015-12-15 08:26:25 -0800428 @Override
429 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800430 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800431 switch (event.type()) {
432 case CONFIG_ADDED:
433 case CONFIG_UPDATED:
kishore786b7e42016-05-19 16:25:57 +0530434 updateConfig(true);
Jonathan Hart6344f572015-12-15 08:26:25 -0800435 break;
436 case CONFIG_REGISTERED:
437 case CONFIG_UNREGISTERED:
438 case CONFIG_REMOVED:
439 default:
440 break;
441 }
442 }
443 }
444 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800445
446 /**
447 * Listener for host events.
448 */
449 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530450
Charles Chand0fd5dc2016-02-16 23:14:49 -0800451 private void peerAdded(HostEvent event) {
452 Host peer = event.subject();
453 Optional<Interface> peerIntf =
454 interfaceService.getInterfacesByPort(peer.location()).stream()
455 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
456 .filter(intf -> peer.vlan().equals(intf.vlan()))
457 .findFirst();
458 if (!peerIntf.isPresent()) {
459 log.debug("Adding peer {}/{} on {} but the interface is not configured",
460 peer.mac(), peer.vlan(), peer.location());
461 return;
462 }
463
464 // Generate L3 Unicast groups and store it in the map
465 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
466 peer.vlan(), peer.location().deviceId(), controlPlaneConnectPoint.port());
467 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
468 peer.vlan(), peer.location().deviceId(), peer.location().port());
469 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
470
471 // From peer to router
472 peerIntf.get().ipAddresses().forEach(routerIp -> {
473 flowObjectiveService.forward(peer.location().deviceId(),
474 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
475 });
476
477 // From router to peer
478 peer.ipAddresses().forEach(peerIp -> {
479 flowObjectiveService.forward(peer.location().deviceId(),
480 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
481 });
482 }
483
484 private void peerRemoved(HostEvent event) {
485 Host peer = event.subject();
486 Optional<Interface> peerIntf =
487 interfaceService.getInterfacesByPort(peer.location()).stream()
488 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
489 .filter(intf -> peer.vlan().equals(intf.vlan()))
490 .findFirst();
491 if (!peerIntf.isPresent()) {
492 log.debug("Removing peer {}/{} on {} but the interface is not configured",
493 peer.mac(), peer.vlan(), peer.location());
494 return;
495 }
496
497 Set<Integer> nextIds = peerNextId.get(peer);
498 checkState(peerNextId.get(peer) != null,
499 "Peer nextId should not be null");
500 checkState(peerNextId.get(peer).size() == 2,
501 "Wrong nextId associated with the peer");
502 Iterator<Integer> iter = peerNextId.get(peer).iterator();
503 int toRouterL3Unicast = iter.next();
504 int toPeerL3Unicast = iter.next();
505
506 // From peer to router
507 peerIntf.get().ipAddresses().forEach(routerIp -> {
508 flowObjectiveService.forward(peer.location().deviceId(),
509 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
510 });
511
512 // From router to peer
513 peer.ipAddresses().forEach(peerIp -> {
514 flowObjectiveService.forward(peer.location().deviceId(),
515 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
516 });
517 }
518
519 private ForwardingObjective.Builder createPeerObjBuilder(
520 int nextId, IpPrefix ipAddresses) {
521 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
522 sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
523 sbuilder.matchIPDst(ipAddresses);
524 DefaultForwardingObjective.Builder builder =
525 DefaultForwardingObjective.builder()
526 .withSelector(sbuilder.build())
527 .fromApp(appId)
528 .withPriority(getPriorityFromPrefix(ipAddresses))
529 .withFlag(ForwardingObjective.Flag.SPECIFIC);
530 if (nextId != -1) {
531 builder.nextStep(nextId);
532 }
533 return builder;
534 }
535
536 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
537 VlanId vlanId, DeviceId deviceId, PortNumber port) {
538 int nextId = flowObjectiveService.allocateNextId();
539 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
540 .withId(nextId)
541 .withType(NextObjective.Type.SIMPLE)
542 .fromApp(appId);
543
544 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
545 ttBuilder.setEthSrc(srcMac);
546 ttBuilder.setEthDst(dstMac);
547 ttBuilder.setOutput(port);
548 nextObjBuilder.addTreatment(ttBuilder.build());
549
550 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
551 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
552 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN) :
553 vlanId;
554 metabuilder.matchVlanId(matchVlanId);
555 nextObjBuilder.withMeta(metabuilder.build());
556
557 flowObjectiveService.next(deviceId, nextObjBuilder.add());
558 return nextId;
559 }
560
561 @Override
562 public void event(HostEvent event) {
563 DeviceId deviceId = event.subject().location().deviceId();
564 if (!mastershipService.isLocalMaster(deviceId)) {
565 return;
566 }
567 switch (event.type()) {
568 case HOST_ADDED:
569 peerAdded(event);
570 break;
571 case HOST_MOVED:
572 //TODO We assume BGP peer does not move for now
573 break;
574 case HOST_REMOVED:
575 peerRemoved(event);
576 break;
577 case HOST_UPDATED:
578 //TODO We assume BGP peer does not change IP for now
579 break;
580 default:
581 break;
582 }
583 }
584 }
585
586 private int getPriorityFromPrefix(IpPrefix prefix) {
587 return (prefix.isIp4()) ?
588 2000 * prefix.prefixLength() + MIN_IP_PRIORITY :
589 500 * prefix.prefixLength() + MIN_IP_PRIORITY;
590 }
kishore7c42cbe2016-04-26 22:49:36 +0530591
592 /**
593 * Update the flows comparing previous event and current event.
594 *
595 * @param prevIntf the previous interface event
596 * @param intf the current occured update envent
597 **/
598 private void updateInterface(Interface prevIntf, Interface intf) {
599 if (!prevIntf.vlan().equals(intf.vlan()) || !prevIntf.mac().equals(intf)) {
600 removeInterface(prevIntf);
601 provisionInterface(intf);
602 } else {
603 List<InterfaceIpAddress> removeIps =
604 prevIntf.ipAddressesList().stream()
605 .filter(pre -> !intf.ipAddressesList().contains(pre))
606 .collect(Collectors.toList());
607 List<InterfaceIpAddress> addIps =
608 intf.ipAddressesList().stream()
609 .filter(cur -> !prevIntf.ipAddressesList().contains(cur))
610 .collect(Collectors.toList());
611 // removing flows with match parameters present in previous subject
612 modifyBasicInterfaceForwarding(new Interface(prevIntf.name(), prevIntf.connectPoint(),
613 removeIps, prevIntf.mac(), prevIntf.vlan()), false);
614 // adding flows with match parameters present in event subject
615 modifyBasicInterfaceForwarding(new Interface(intf.name(), intf.connectPoint(),
616 addIps, intf.mac(), intf.vlan()), true);
617 }
618 }
619
kishore71a27532016-03-16 20:23:49 +0530620 private class InternalInterfaceListener implements InterfaceListener {
621
622 @Override
623 public void event(InterfaceEvent event) {
624 Interface intf = event.subject();
kishore7c42cbe2016-04-26 22:49:36 +0530625 Interface prevIntf = event.prevSubject();
kishore71a27532016-03-16 20:23:49 +0530626 switch (event.type()) {
627 case INTERFACE_ADDED:
628 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
629 provisionInterface(intf);
630 }
631 break;
632 case INTERFACE_UPDATED:
kishore7c42cbe2016-04-26 22:49:36 +0530633 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
634 updateInterface(prevIntf, intf);
635 }
kishore71a27532016-03-16 20:23:49 +0530636 break;
637 case INTERFACE_REMOVED:
638 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
639 removeInterface(intf);
640 }
641 break;
642 default:
643 break;
644 }
645 }
646 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800647}