blob: 9f889afdc867550a634ac81f12ad9514ce762b0c [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
Jonathan Hartf8035d32016-06-16 16:23:26 -0700136 readConfig();
137 applicationService.registerDeactivateHook(this.appId, () -> provisionDevice(false));
Jonathan Hart6344f572015-12-15 08:26:25 -0800138 }
139
140 @Deactivate
141 public void deactivate() {
142 deviceService.removeListener(deviceListener);
143 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800144 hostService.removeListener(hostListener);
kishore71a27532016-03-16 20:23:49 +0530145 interfaceService.removeListener(interfaceListener);
Jonathan Hart6344f572015-12-15 08:26:25 -0800146 }
147
kishore786b7e42016-05-19 16:25:57 +0530148 /**
149 * Installs or removes interface configuration
150 * based on the flag used on activate or deactivate.
151 *
kishore786b7e42016-05-19 16:25:57 +0530152 **/
Jonathan Hartf8035d32016-06-16 16:23:26 -0700153 private void readConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800154 ApplicationId routingAppId =
155 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
156
157 RouterConfig config = networkConfigService.getConfig(
158 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
159
160 if (config == null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800161 log.warn("Router config not available");
Jonathan Hart6344f572015-12-15 08:26:25 -0800162 return;
163 }
164
Jonathan Hartea492382016-01-13 09:33:13 -0800165 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
166 ospfEnabled = config.getOspfEnabled();
Jonathan Hart883fd372016-02-10 14:36:15 -0800167 interfaces = config.getInterfaces();
Jonathan Hart6344f572015-12-15 08:26:25 -0800168
Jonathan Hartf8035d32016-06-16 16:23:26 -0700169 provisionDevice(true);
Jonathan Hartea492382016-01-13 09:33:13 -0800170 }
171
kishore786b7e42016-05-19 16:25:57 +0530172 /**
173 * Installs or removes interface configuration for each interface
174 * based on the flag used on activate or deactivate.
175 *
Jonathan Hartf8035d32016-06-16 16:23:26 -0700176 * @param install true to install flows, false to remove them
kishore786b7e42016-05-19 16:25:57 +0530177 **/
Jonathan Hartf8035d32016-06-16 16:23:26 -0700178 private void provisionDevice(boolean install) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800179 if (controlPlaneConnectPoint != null &&
180 deviceService.isAvailable(controlPlaneConnectPoint.deviceId())) {
Jonathan Hartea492382016-01-13 09:33:13 -0800181 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
182
183 interfaceService.getInterfaces().stream()
184 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
Jonathan Hart883fd372016-02-10 14:36:15 -0800185 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
Jonathan Hartf8035d32016-06-16 16:23:26 -0700186 .forEach(intf -> provisionInterface(intf, install));
Jonathan Hartea492382016-01-13 09:33:13 -0800187
188 log.info("Set up interfaces on {}", controlPlaneConnectPoint.deviceId());
Jonathan Hart6344f572015-12-15 08:26:25 -0800189 }
190 }
191
Jonathan Hartf8035d32016-06-16 16:23:26 -0700192 private void provisionInterface(Interface intf, boolean install) {
193 updateInterfaceForwarding(intf, install);
194 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800195 }
196
kishore71a27532016-03-16 20:23:49 +0530197 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700198 * Installs or removes the basic forwarding flows for each interface
kishore71a27532016-03-16 20:23:49 +0530199 * based on the flag used.
200 *
201 * @param intf the Interface on which event is received
202 * @param install true to create an add objective, false to create a remove
203 * objective
204 **/
Jonathan Hartf8035d32016-06-16 16:23:26 -0700205 private void updateInterfaceForwarding(Interface intf, boolean install) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800206 log.debug("Adding interface objectives for {}", intf);
207
208 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
209 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800210 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800211 // create nextObjectives for forwarding to this interface and the
212 // controlPlaneConnectPoint
213 int cpNextId, intfNextId;
214 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530215 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800216 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530217 true, install);
218 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Saurav Das49cb5a12016-01-16 22:54:07 -0800219 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530220 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800221 } else {
kishore71a27532016-03-16 20:23:49 +0530222 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
223 intf.vlan(), false, install);
224 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
225 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800226 }
227
Jonathan Hart6344f572015-12-15 08:26:25 -0800228 // IPv4 to router
229 TrafficSelector toSelector = DefaultTrafficSelector.builder()
230 .matchInPort(intf.connectPoint().port())
231 .matchEthDst(intf.mac())
232 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
233 .matchVlanId(intf.vlan())
234 .matchIPDst(ip.ipAddress().toIpPrefix())
235 .build();
236
Jonathan Hart6344f572015-12-15 08:26:25 -0800237 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530238 buildForwardingObjective(toSelector, null, cpNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800239
240 // IPv4 from router
241 TrafficSelector fromSelector = DefaultTrafficSelector.builder()
242 .matchInPort(controlPlanePort)
243 .matchEthSrc(intf.mac())
244 .matchVlanId(intf.vlan())
245 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
246 .matchIPSrc(ip.ipAddress().toIpPrefix())
247 .build();
248
Jonathan Hart6344f572015-12-15 08:26:25 -0800249 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530250 buildForwardingObjective(fromSelector, null, intfNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800251
252 // ARP to router
253 toSelector = DefaultTrafficSelector.builder()
254 .matchInPort(intf.connectPoint().port())
255 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
256 .matchVlanId(intf.vlan())
257 .build();
258
Saurav Das49cb5a12016-01-16 22:54:07 -0800259 TrafficTreatment puntTreatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800260 .punt()
261 .build();
262
263 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530264 buildForwardingObjective(toSelector, puntTreatment, cpNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800265
266 // ARP from router
267 fromSelector = DefaultTrafficSelector.builder()
268 .matchInPort(controlPlanePort)
269 .matchEthSrc(intf.mac())
270 .matchVlanId(intf.vlan())
271 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
Saurav Das49cb5a12016-01-16 22:54:07 -0800272 .matchArpSpa(ip.ipAddress().getIp4Address())
Jonathan Hart6344f572015-12-15 08:26:25 -0800273 .build();
274
275 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530276 buildForwardingObjective(fromSelector, puntTreatment, intfNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800277 }
278 }
279
kishore71a27532016-03-16 20:23:49 +0530280 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700281 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530282 *
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700283 * @param intf the interface on which event is received
kishore71a27532016-03-16 20:23:49 +0530284 * @param install true to create an add objective, false to create a remove
285 * objective
286 **/
287 private void updateOspfForwarding(Interface intf, boolean install) {
Jonathan Hartea492382016-01-13 09:33:13 -0800288 // OSPF to router
289 TrafficSelector toSelector = DefaultTrafficSelector.builder()
290 .matchInPort(intf.connectPoint().port())
291 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
292 .matchVlanId(intf.vlan())
293 .matchIPProtocol((byte) OSPF_IP_PROTO)
294 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800295
Saurav Das49cb5a12016-01-16 22:54:07 -0800296 // create nextObjectives for forwarding to the controlPlaneConnectPoint
297 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
298 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
299 int cpNextId;
300 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530301 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800302 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530303 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800304 } else {
kishore71a27532016-03-16 20:23:49 +0530305 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
306 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800307 }
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700308 log.debug("OSPF flows intf:{} nextid:{}", intf, cpNextId);
Jonathan Hartea492382016-01-13 09:33:13 -0800309 flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(),
kishore71a27532016-03-16 20:23:49 +0530310 buildForwardingObjective(toSelector, null, cpNextId, install ? ospfEnabled : install));
Jonathan Hartea492382016-01-13 09:33:13 -0800311 }
312
313 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800314 * Creates a next objective for forwarding to a port. Handles metadata for
315 * some pipelines that require vlan information for egress port.
316 *
317 * @param deviceId the device on which the next objective is being created
318 * @param portNumber the egress port
319 * @param vlanId vlan information for egress port
320 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530321 * @param install true to create an add next objective, false to create a remove
322 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800323 * @return nextId of the next objective created
324 */
kishore71a27532016-03-16 20:23:49 +0530325 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
326 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800327 int nextId = flowObjectiveService.allocateNextId();
328 NextObjective.Builder nextObjBuilder = DefaultNextObjective
329 .builder().withId(nextId)
330 .withType(NextObjective.Type.SIMPLE)
331 .fromApp(appId);
332
333 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
334 if (popVlan) {
335 ttBuilder.popVlan();
336 }
337 ttBuilder.setOutput(portNumber);
338
339 // setup metadata to pass to nextObjective - indicate the vlan on egress
340 // if needed by the switch pipeline.
341 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
342 metabuilder.matchVlanId(vlanId);
343
344 nextObjBuilder.withMeta(metabuilder.build());
345 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700346 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800347 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530348 if (install) {
349 flowObjectiveService.next(deviceId, nextObjBuilder.add());
350 } else {
351 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
352 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800353 return nextId;
354 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700355
Saurav Das49cb5a12016-01-16 22:54:07 -0800356 /**
357 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800358 *
359 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800360 * @param treatment treatment to apply to packet, can be null
361 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800362 * @param add true to create an add objective, false to create a remove
363 * objective
364 * @return forwarding objective
365 */
366 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
367 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800368 int nextId,
Jonathan Hartea492382016-01-13 09:33:13 -0800369 boolean add) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800370 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
371 fobBuilder.withSelector(selector);
372 if (treatment != null) {
373 fobBuilder.withTreatment(treatment);
374 }
375 if (nextId != -1) {
376 fobBuilder.nextStep(nextId);
377 }
378 fobBuilder.fromApp(appId)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800379 .withPriority(ACL_PRIORITY)
Saurav Das49cb5a12016-01-16 22:54:07 -0800380 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800381
382 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800383 }
384
Jonathan Hartea492382016-01-13 09:33:13 -0800385 /**
386 * Listener for device events.
387 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800388 private class InternalDeviceListener implements DeviceListener {
kishore71a27532016-03-16 20:23:49 +0530389
Jonathan Hart6344f572015-12-15 08:26:25 -0800390 @Override
391 public void event(DeviceEvent event) {
392 if (controlPlaneConnectPoint != null &&
393 event.subject().id().equals(controlPlaneConnectPoint.deviceId())) {
394 switch (event.type()) {
395 case DEVICE_ADDED:
396 case DEVICE_AVAILABILITY_CHANGED:
397 if (deviceService.isAvailable(event.subject().id())) {
398 log.info("Device connected {}", event.subject().id());
Jonathan Hartf8035d32016-06-16 16:23:26 -0700399 provisionDevice(true);
Jonathan Hart6344f572015-12-15 08:26:25 -0800400 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800401 break;
402 case DEVICE_UPDATED:
403 case DEVICE_REMOVED:
404 case DEVICE_SUSPENDED:
405 case PORT_ADDED:
406 case PORT_UPDATED:
407 case PORT_REMOVED:
408 default:
409 break;
410 }
411 }
412 }
413 }
414
Jonathan Hartea492382016-01-13 09:33:13 -0800415 /**
416 * Listener for network config events.
417 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800418 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530419
Jonathan Hart6344f572015-12-15 08:26:25 -0800420 @Override
421 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800422 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800423 switch (event.type()) {
424 case CONFIG_ADDED:
425 case CONFIG_UPDATED:
Jonathan Hartf8035d32016-06-16 16:23:26 -0700426 readConfig();
Jonathan Hart6344f572015-12-15 08:26:25 -0800427 break;
428 case CONFIG_REGISTERED:
429 case CONFIG_UNREGISTERED:
430 case CONFIG_REMOVED:
431 default:
432 break;
433 }
434 }
435 }
436 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800437
438 /**
439 * Listener for host events.
440 */
441 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530442
Charles Chand0fd5dc2016-02-16 23:14:49 -0800443 private void peerAdded(HostEvent event) {
444 Host peer = event.subject();
445 Optional<Interface> peerIntf =
446 interfaceService.getInterfacesByPort(peer.location()).stream()
447 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
448 .filter(intf -> peer.vlan().equals(intf.vlan()))
449 .findFirst();
450 if (!peerIntf.isPresent()) {
451 log.debug("Adding peer {}/{} on {} but the interface is not configured",
452 peer.mac(), peer.vlan(), peer.location());
453 return;
454 }
455
456 // Generate L3 Unicast groups and store it in the map
457 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
458 peer.vlan(), peer.location().deviceId(), controlPlaneConnectPoint.port());
459 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
460 peer.vlan(), peer.location().deviceId(), peer.location().port());
461 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
462
463 // From peer to router
464 peerIntf.get().ipAddresses().forEach(routerIp -> {
465 flowObjectiveService.forward(peer.location().deviceId(),
466 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
467 });
468
469 // From router to peer
470 peer.ipAddresses().forEach(peerIp -> {
471 flowObjectiveService.forward(peer.location().deviceId(),
472 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
473 });
474 }
475
476 private void peerRemoved(HostEvent event) {
477 Host peer = event.subject();
478 Optional<Interface> peerIntf =
479 interfaceService.getInterfacesByPort(peer.location()).stream()
480 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
481 .filter(intf -> peer.vlan().equals(intf.vlan()))
482 .findFirst();
483 if (!peerIntf.isPresent()) {
484 log.debug("Removing peer {}/{} on {} but the interface is not configured",
485 peer.mac(), peer.vlan(), peer.location());
486 return;
487 }
488
Charles Chand0fd5dc2016-02-16 23:14:49 -0800489 checkState(peerNextId.get(peer) != null,
490 "Peer nextId should not be null");
491 checkState(peerNextId.get(peer).size() == 2,
492 "Wrong nextId associated with the peer");
493 Iterator<Integer> iter = peerNextId.get(peer).iterator();
494 int toRouterL3Unicast = iter.next();
495 int toPeerL3Unicast = iter.next();
496
497 // From peer to router
498 peerIntf.get().ipAddresses().forEach(routerIp -> {
499 flowObjectiveService.forward(peer.location().deviceId(),
500 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
501 });
502
503 // From router to peer
504 peer.ipAddresses().forEach(peerIp -> {
505 flowObjectiveService.forward(peer.location().deviceId(),
506 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
507 });
508 }
509
510 private ForwardingObjective.Builder createPeerObjBuilder(
511 int nextId, IpPrefix ipAddresses) {
512 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
513 sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
514 sbuilder.matchIPDst(ipAddresses);
515 DefaultForwardingObjective.Builder builder =
516 DefaultForwardingObjective.builder()
517 .withSelector(sbuilder.build())
518 .fromApp(appId)
519 .withPriority(getPriorityFromPrefix(ipAddresses))
520 .withFlag(ForwardingObjective.Flag.SPECIFIC);
521 if (nextId != -1) {
522 builder.nextStep(nextId);
523 }
524 return builder;
525 }
526
527 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
528 VlanId vlanId, DeviceId deviceId, PortNumber port) {
529 int nextId = flowObjectiveService.allocateNextId();
530 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
531 .withId(nextId)
532 .withType(NextObjective.Type.SIMPLE)
533 .fromApp(appId);
534
535 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
536 ttBuilder.setEthSrc(srcMac);
537 ttBuilder.setEthDst(dstMac);
538 ttBuilder.setOutput(port);
539 nextObjBuilder.addTreatment(ttBuilder.build());
540
541 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
542 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
543 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN) :
544 vlanId;
545 metabuilder.matchVlanId(matchVlanId);
546 nextObjBuilder.withMeta(metabuilder.build());
547
548 flowObjectiveService.next(deviceId, nextObjBuilder.add());
549 return nextId;
550 }
551
552 @Override
553 public void event(HostEvent event) {
554 DeviceId deviceId = event.subject().location().deviceId();
555 if (!mastershipService.isLocalMaster(deviceId)) {
556 return;
557 }
558 switch (event.type()) {
559 case HOST_ADDED:
560 peerAdded(event);
561 break;
562 case HOST_MOVED:
563 //TODO We assume BGP peer does not move for now
564 break;
565 case HOST_REMOVED:
566 peerRemoved(event);
567 break;
568 case HOST_UPDATED:
569 //TODO We assume BGP peer does not change IP for now
570 break;
571 default:
572 break;
573 }
574 }
575 }
576
577 private int getPriorityFromPrefix(IpPrefix prefix) {
578 return (prefix.isIp4()) ?
579 2000 * prefix.prefixLength() + MIN_IP_PRIORITY :
580 500 * prefix.prefixLength() + MIN_IP_PRIORITY;
581 }
kishore7c42cbe2016-04-26 22:49:36 +0530582
583 /**
584 * Update the flows comparing previous event and current event.
585 *
586 * @param prevIntf the previous interface event
Jonathan Hartf8035d32016-06-16 16:23:26 -0700587 * @param intf the current occurred update event
kishore7c42cbe2016-04-26 22:49:36 +0530588 **/
589 private void updateInterface(Interface prevIntf, Interface intf) {
590 if (!prevIntf.vlan().equals(intf.vlan()) || !prevIntf.mac().equals(intf)) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700591 provisionInterface(prevIntf, false);
592 provisionInterface(intf, true);
kishore7c42cbe2016-04-26 22:49:36 +0530593 } else {
594 List<InterfaceIpAddress> removeIps =
595 prevIntf.ipAddressesList().stream()
596 .filter(pre -> !intf.ipAddressesList().contains(pre))
597 .collect(Collectors.toList());
598 List<InterfaceIpAddress> addIps =
599 intf.ipAddressesList().stream()
600 .filter(cur -> !prevIntf.ipAddressesList().contains(cur))
601 .collect(Collectors.toList());
602 // removing flows with match parameters present in previous subject
Jonathan Hartf8035d32016-06-16 16:23:26 -0700603 updateInterfaceForwarding(new Interface(prevIntf.name(), prevIntf.connectPoint(),
kishore7c42cbe2016-04-26 22:49:36 +0530604 removeIps, prevIntf.mac(), prevIntf.vlan()), false);
605 // adding flows with match parameters present in event subject
Jonathan Hartf8035d32016-06-16 16:23:26 -0700606 updateInterfaceForwarding(new Interface(intf.name(), intf.connectPoint(),
kishore7c42cbe2016-04-26 22:49:36 +0530607 addIps, intf.mac(), intf.vlan()), true);
608 }
609 }
610
kishore71a27532016-03-16 20:23:49 +0530611 private class InternalInterfaceListener implements InterfaceListener {
kishore71a27532016-03-16 20:23:49 +0530612 @Override
613 public void event(InterfaceEvent event) {
Charles Chan4a6e91e2016-07-19 18:36:33 -0700614 if (controlPlaneConnectPoint == null) {
615 log.info("Control plane connect point is not configured. Abort InterfaceEvent.");
616 return;
617 }
618 Interface intf = event.subject();
619 Interface prevIntf = event.prevSubject();
620 switch (event.type()) {
kishore71a27532016-03-16 20:23:49 +0530621 case INTERFACE_ADDED:
622 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700623 provisionInterface(intf, true);
kishore71a27532016-03-16 20:23:49 +0530624 }
625 break;
626 case INTERFACE_UPDATED:
kishore7c42cbe2016-04-26 22:49:36 +0530627 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
628 updateInterface(prevIntf, intf);
629 }
kishore71a27532016-03-16 20:23:49 +0530630 break;
631 case INTERFACE_REMOVED:
632 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700633 provisionInterface(intf, false);
kishore71a27532016-03-16 20:23:49 +0530634 }
635 break;
636 default:
637 break;
Charles Chan4a6e91e2016-07-19 18:36:33 -0700638 }
kishore71a27532016-03-16 20:23:49 +0530639 }
640 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800641}