blob: 90d09059c1561616b075e0e8a6df96d5d02d8383 [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;
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;
kishore7c42cbe2016-04-26 22:49:36 +053070import java.util.stream.Collectors;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070071
72import static com.google.common.base.Preconditions.checkState;
73import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080074
75/**
76 * Manages connectivity between peers redirecting control traffic to a routing
77 * control plane available on the dataplane.
78 */
79@Component(immediate = true, enabled = false)
80public class ControlPlaneRedirectManager {
81
82 private final Logger log = getLogger(getClass());
83
Charles Chand0fd5dc2016-02-16 23:14:49 -080084 private static final int MIN_IP_PRIORITY = 10;
85 private static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080086 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -080087
88 private static final String APP_NAME = "org.onosproject.cpredirect";
89 private ApplicationId appId;
90
91 private ConnectPoint controlPlaneConnectPoint;
Jonathan Hartea492382016-01-13 09:33:13 -080092 private boolean ospfEnabled = false;
Jonathan Hart883fd372016-02-10 14:36:15 -080093 private List<String> interfaces = Collections.emptyList();
Charles Chand0fd5dc2016-02-16 23:14:49 -080094 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
Jonathan Hart6344f572015-12-15 08:26:25 -080095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected CoreService coreService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected DeviceService deviceService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected InterfaceService interfaceService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected FlowObjectiveService flowObjectiveService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected NetworkConfigService networkConfigService;
110
Charles Chand0fd5dc2016-02-16 23:14:49 -0800111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected MastershipService mastershipService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected HostService hostService;
116
Jonathan Hart6344f572015-12-15 08:26:25 -0800117 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
118 private final InternalNetworkConfigListener networkConfigListener =
119 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800120 private final InternalHostListener hostListener = new InternalHostListener();
kishore71a27532016-03-16 20:23:49 +0530121 private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800122
123 @Activate
124 public void activate() {
125 this.appId = coreService.registerApplication(APP_NAME);
126
127 deviceService.addListener(deviceListener);
128 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800129 hostService.addListener(hostListener);
kishore71a27532016-03-16 20:23:49 +0530130 interfaceService.addListener(interfaceListener);
Jonathan Hart6344f572015-12-15 08:26:25 -0800131
132 updateConfig();
133 }
134
135 @Deactivate
136 public void deactivate() {
137 deviceService.removeListener(deviceListener);
138 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800139 hostService.removeListener(hostListener);
kishore71a27532016-03-16 20:23:49 +0530140 interfaceService.removeListener(interfaceListener);
Jonathan Hart6344f572015-12-15 08:26:25 -0800141 }
142
143 private void updateConfig() {
144 ApplicationId routingAppId =
145 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
146
147 RouterConfig config = networkConfigService.getConfig(
148 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
149
150 if (config == null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800151 log.warn("Router config not available");
Jonathan Hart6344f572015-12-15 08:26:25 -0800152 return;
153 }
154
Jonathan Hartea492382016-01-13 09:33:13 -0800155 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
156 ospfEnabled = config.getOspfEnabled();
Jonathan Hart883fd372016-02-10 14:36:15 -0800157 interfaces = config.getInterfaces();
Jonathan Hart6344f572015-12-15 08:26:25 -0800158
Jonathan Hartea492382016-01-13 09:33:13 -0800159 updateDevice();
160 }
161
162 private void updateDevice() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800163 if (controlPlaneConnectPoint != null &&
164 deviceService.isAvailable(controlPlaneConnectPoint.deviceId())) {
Jonathan Hartea492382016-01-13 09:33:13 -0800165 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
166
167 interfaceService.getInterfaces().stream()
168 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
Jonathan Hart883fd372016-02-10 14:36:15 -0800169 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
Jonathan Hartea492382016-01-13 09:33:13 -0800170 .forEach(this::provisionInterface);
171
172 log.info("Set up interfaces on {}", controlPlaneConnectPoint.deviceId());
Jonathan Hart6344f572015-12-15 08:26:25 -0800173 }
174 }
175
kishore71a27532016-03-16 20:23:49 +0530176 private void removeInterface(Interface intf) {
177 modifyBasicInterfaceForwarding(intf, false);
178 updateOspfForwarding(intf, false);
Jonathan Hart6344f572015-12-15 08:26:25 -0800179 }
180
kishore71a27532016-03-16 20:23:49 +0530181 private void provisionInterface(Interface intf) {
182 modifyBasicInterfaceForwarding(intf, true);
183 updateOspfForwarding(intf, true);
184 }
185 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700186 * Installs or removes the basic forwarding flows for each interface
kishore71a27532016-03-16 20:23:49 +0530187 * based on the flag used.
188 *
189 * @param intf the Interface on which event is received
190 * @param install true to create an add objective, false to create a remove
191 * objective
192 **/
193 private void modifyBasicInterfaceForwarding(Interface intf, boolean install) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800194 log.debug("Adding interface objectives for {}", intf);
195
196 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
197 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800198 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800199 // create nextObjectives for forwarding to this interface and the
200 // controlPlaneConnectPoint
201 int cpNextId, intfNextId;
202 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530203 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800204 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530205 true, install);
206 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Saurav Das49cb5a12016-01-16 22:54:07 -0800207 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530208 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800209 } else {
kishore71a27532016-03-16 20:23:49 +0530210 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
211 intf.vlan(), false, install);
212 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
213 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800214 }
215
Jonathan Hart6344f572015-12-15 08:26:25 -0800216 // IPv4 to router
217 TrafficSelector toSelector = DefaultTrafficSelector.builder()
218 .matchInPort(intf.connectPoint().port())
219 .matchEthDst(intf.mac())
220 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
221 .matchVlanId(intf.vlan())
222 .matchIPDst(ip.ipAddress().toIpPrefix())
223 .build();
224
Jonathan Hart6344f572015-12-15 08:26:25 -0800225 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530226 buildForwardingObjective(toSelector, null, cpNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800227
228 // IPv4 from router
229 TrafficSelector fromSelector = DefaultTrafficSelector.builder()
230 .matchInPort(controlPlanePort)
231 .matchEthSrc(intf.mac())
232 .matchVlanId(intf.vlan())
233 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
234 .matchIPSrc(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(fromSelector, null, intfNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800239
240 // ARP to router
241 toSelector = DefaultTrafficSelector.builder()
242 .matchInPort(intf.connectPoint().port())
243 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
244 .matchVlanId(intf.vlan())
245 .build();
246
Saurav Das49cb5a12016-01-16 22:54:07 -0800247 TrafficTreatment puntTreatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800248 .punt()
249 .build();
250
251 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530252 buildForwardingObjective(toSelector, puntTreatment, cpNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800253
254 // ARP from router
255 fromSelector = DefaultTrafficSelector.builder()
256 .matchInPort(controlPlanePort)
257 .matchEthSrc(intf.mac())
258 .matchVlanId(intf.vlan())
259 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
Saurav Das49cb5a12016-01-16 22:54:07 -0800260 .matchArpSpa(ip.ipAddress().getIp4Address())
Jonathan Hart6344f572015-12-15 08:26:25 -0800261 .build();
262
263 flowObjectiveService.forward(deviceId,
kishore71a27532016-03-16 20:23:49 +0530264 buildForwardingObjective(fromSelector, puntTreatment, intfNextId, install));
Jonathan Hart6344f572015-12-15 08:26:25 -0800265 }
266 }
267
kishore71a27532016-03-16 20:23:49 +0530268 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700269 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530270 *
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700271 * @param intf the interface on which event is received
kishore71a27532016-03-16 20:23:49 +0530272 * @param install true to create an add objective, false to create a remove
273 * objective
274 **/
275 private void updateOspfForwarding(Interface intf, boolean install) {
Jonathan Hartea492382016-01-13 09:33:13 -0800276 // OSPF to router
277 TrafficSelector toSelector = DefaultTrafficSelector.builder()
278 .matchInPort(intf.connectPoint().port())
279 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
280 .matchVlanId(intf.vlan())
281 .matchIPProtocol((byte) OSPF_IP_PROTO)
282 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800283
Saurav Das49cb5a12016-01-16 22:54:07 -0800284 // create nextObjectives for forwarding to the controlPlaneConnectPoint
285 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
286 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
287 int cpNextId;
288 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530289 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800290 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530291 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800292 } else {
kishore71a27532016-03-16 20:23:49 +0530293 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
294 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800295 }
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700296 log.debug("OSPF flows intf:{} nextid:{}", intf, cpNextId);
Jonathan Hartea492382016-01-13 09:33:13 -0800297 flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(),
kishore71a27532016-03-16 20:23:49 +0530298 buildForwardingObjective(toSelector, null, cpNextId, install ? ospfEnabled : install));
Jonathan Hartea492382016-01-13 09:33:13 -0800299 }
300
301 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800302 * Creates a next objective for forwarding to a port. Handles metadata for
303 * some pipelines that require vlan information for egress port.
304 *
305 * @param deviceId the device on which the next objective is being created
306 * @param portNumber the egress port
307 * @param vlanId vlan information for egress port
308 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530309 * @param install true to create an add next objective, false to create a remove
310 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800311 * @return nextId of the next objective created
312 */
kishore71a27532016-03-16 20:23:49 +0530313 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
314 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800315 int nextId = flowObjectiveService.allocateNextId();
316 NextObjective.Builder nextObjBuilder = DefaultNextObjective
317 .builder().withId(nextId)
318 .withType(NextObjective.Type.SIMPLE)
319 .fromApp(appId);
320
321 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
322 if (popVlan) {
323 ttBuilder.popVlan();
324 }
325 ttBuilder.setOutput(portNumber);
326
327 // setup metadata to pass to nextObjective - indicate the vlan on egress
328 // if needed by the switch pipeline.
329 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
330 metabuilder.matchVlanId(vlanId);
331
332 nextObjBuilder.withMeta(metabuilder.build());
333 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700334 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800335 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530336 if (install) {
337 flowObjectiveService.next(deviceId, nextObjBuilder.add());
338 } else {
339 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
340 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800341 return nextId;
342 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800343 /**
344 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800345 *
346 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800347 * @param treatment treatment to apply to packet, can be null
348 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800349 * @param add true to create an add objective, false to create a remove
350 * objective
351 * @return forwarding objective
352 */
353 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
354 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800355 int nextId,
Jonathan Hartea492382016-01-13 09:33:13 -0800356 boolean add) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800357 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
358 fobBuilder.withSelector(selector);
359 if (treatment != null) {
360 fobBuilder.withTreatment(treatment);
361 }
362 if (nextId != -1) {
363 fobBuilder.nextStep(nextId);
364 }
365 fobBuilder.fromApp(appId)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800366 .withPriority(ACL_PRIORITY)
Saurav Das49cb5a12016-01-16 22:54:07 -0800367 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800368
369 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800370 }
371
Jonathan Hartea492382016-01-13 09:33:13 -0800372 /**
373 * Listener for device events.
374 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800375 private class InternalDeviceListener implements DeviceListener {
kishore71a27532016-03-16 20:23:49 +0530376
Jonathan Hart6344f572015-12-15 08:26:25 -0800377 @Override
378 public void event(DeviceEvent event) {
379 if (controlPlaneConnectPoint != null &&
380 event.subject().id().equals(controlPlaneConnectPoint.deviceId())) {
381 switch (event.type()) {
382 case DEVICE_ADDED:
383 case DEVICE_AVAILABILITY_CHANGED:
384 if (deviceService.isAvailable(event.subject().id())) {
385 log.info("Device connected {}", event.subject().id());
Jonathan Hartea492382016-01-13 09:33:13 -0800386 updateDevice();
Jonathan Hart6344f572015-12-15 08:26:25 -0800387 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800388 break;
389 case DEVICE_UPDATED:
390 case DEVICE_REMOVED:
391 case DEVICE_SUSPENDED:
392 case PORT_ADDED:
393 case PORT_UPDATED:
394 case PORT_REMOVED:
395 default:
396 break;
397 }
398 }
399 }
400 }
401
Jonathan Hartea492382016-01-13 09:33:13 -0800402 /**
403 * Listener for network config events.
404 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800405 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530406
Jonathan Hart6344f572015-12-15 08:26:25 -0800407 @Override
408 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800409 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800410 switch (event.type()) {
411 case CONFIG_ADDED:
412 case CONFIG_UPDATED:
413 updateConfig();
414 break;
415 case CONFIG_REGISTERED:
416 case CONFIG_UNREGISTERED:
417 case CONFIG_REMOVED:
418 default:
419 break;
420 }
421 }
422 }
423 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800424
425 /**
426 * Listener for host events.
427 */
428 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530429
Charles Chand0fd5dc2016-02-16 23:14:49 -0800430 private void peerAdded(HostEvent event) {
431 Host peer = event.subject();
432 Optional<Interface> peerIntf =
433 interfaceService.getInterfacesByPort(peer.location()).stream()
434 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
435 .filter(intf -> peer.vlan().equals(intf.vlan()))
436 .findFirst();
437 if (!peerIntf.isPresent()) {
438 log.debug("Adding peer {}/{} on {} but the interface is not configured",
439 peer.mac(), peer.vlan(), peer.location());
440 return;
441 }
442
443 // Generate L3 Unicast groups and store it in the map
444 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
445 peer.vlan(), peer.location().deviceId(), controlPlaneConnectPoint.port());
446 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
447 peer.vlan(), peer.location().deviceId(), peer.location().port());
448 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
449
450 // From peer to router
451 peerIntf.get().ipAddresses().forEach(routerIp -> {
452 flowObjectiveService.forward(peer.location().deviceId(),
453 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
454 });
455
456 // From router to peer
457 peer.ipAddresses().forEach(peerIp -> {
458 flowObjectiveService.forward(peer.location().deviceId(),
459 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
460 });
461 }
462
463 private void peerRemoved(HostEvent event) {
464 Host peer = event.subject();
465 Optional<Interface> peerIntf =
466 interfaceService.getInterfacesByPort(peer.location()).stream()
467 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
468 .filter(intf -> peer.vlan().equals(intf.vlan()))
469 .findFirst();
470 if (!peerIntf.isPresent()) {
471 log.debug("Removing peer {}/{} on {} but the interface is not configured",
472 peer.mac(), peer.vlan(), peer.location());
473 return;
474 }
475
476 Set<Integer> nextIds = peerNextId.get(peer);
477 checkState(peerNextId.get(peer) != null,
478 "Peer nextId should not be null");
479 checkState(peerNextId.get(peer).size() == 2,
480 "Wrong nextId associated with the peer");
481 Iterator<Integer> iter = peerNextId.get(peer).iterator();
482 int toRouterL3Unicast = iter.next();
483 int toPeerL3Unicast = iter.next();
484
485 // From peer to router
486 peerIntf.get().ipAddresses().forEach(routerIp -> {
487 flowObjectiveService.forward(peer.location().deviceId(),
488 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
489 });
490
491 // From router to peer
492 peer.ipAddresses().forEach(peerIp -> {
493 flowObjectiveService.forward(peer.location().deviceId(),
494 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
495 });
496 }
497
498 private ForwardingObjective.Builder createPeerObjBuilder(
499 int nextId, IpPrefix ipAddresses) {
500 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
501 sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
502 sbuilder.matchIPDst(ipAddresses);
503 DefaultForwardingObjective.Builder builder =
504 DefaultForwardingObjective.builder()
505 .withSelector(sbuilder.build())
506 .fromApp(appId)
507 .withPriority(getPriorityFromPrefix(ipAddresses))
508 .withFlag(ForwardingObjective.Flag.SPECIFIC);
509 if (nextId != -1) {
510 builder.nextStep(nextId);
511 }
512 return builder;
513 }
514
515 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
516 VlanId vlanId, DeviceId deviceId, PortNumber port) {
517 int nextId = flowObjectiveService.allocateNextId();
518 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
519 .withId(nextId)
520 .withType(NextObjective.Type.SIMPLE)
521 .fromApp(appId);
522
523 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
524 ttBuilder.setEthSrc(srcMac);
525 ttBuilder.setEthDst(dstMac);
526 ttBuilder.setOutput(port);
527 nextObjBuilder.addTreatment(ttBuilder.build());
528
529 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
530 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
531 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN) :
532 vlanId;
533 metabuilder.matchVlanId(matchVlanId);
534 nextObjBuilder.withMeta(metabuilder.build());
535
536 flowObjectiveService.next(deviceId, nextObjBuilder.add());
537 return nextId;
538 }
539
540 @Override
541 public void event(HostEvent event) {
542 DeviceId deviceId = event.subject().location().deviceId();
543 if (!mastershipService.isLocalMaster(deviceId)) {
544 return;
545 }
546 switch (event.type()) {
547 case HOST_ADDED:
548 peerAdded(event);
549 break;
550 case HOST_MOVED:
551 //TODO We assume BGP peer does not move for now
552 break;
553 case HOST_REMOVED:
554 peerRemoved(event);
555 break;
556 case HOST_UPDATED:
557 //TODO We assume BGP peer does not change IP for now
558 break;
559 default:
560 break;
561 }
562 }
563 }
564
565 private int getPriorityFromPrefix(IpPrefix prefix) {
566 return (prefix.isIp4()) ?
567 2000 * prefix.prefixLength() + MIN_IP_PRIORITY :
568 500 * prefix.prefixLength() + MIN_IP_PRIORITY;
569 }
kishore7c42cbe2016-04-26 22:49:36 +0530570
571 /**
572 * Update the flows comparing previous event and current event.
573 *
574 * @param prevIntf the previous interface event
575 * @param intf the current occured update envent
576 **/
577 private void updateInterface(Interface prevIntf, Interface intf) {
578 if (!prevIntf.vlan().equals(intf.vlan()) || !prevIntf.mac().equals(intf)) {
579 removeInterface(prevIntf);
580 provisionInterface(intf);
581 } else {
582 List<InterfaceIpAddress> removeIps =
583 prevIntf.ipAddressesList().stream()
584 .filter(pre -> !intf.ipAddressesList().contains(pre))
585 .collect(Collectors.toList());
586 List<InterfaceIpAddress> addIps =
587 intf.ipAddressesList().stream()
588 .filter(cur -> !prevIntf.ipAddressesList().contains(cur))
589 .collect(Collectors.toList());
590 // removing flows with match parameters present in previous subject
591 modifyBasicInterfaceForwarding(new Interface(prevIntf.name(), prevIntf.connectPoint(),
592 removeIps, prevIntf.mac(), prevIntf.vlan()), false);
593 // adding flows with match parameters present in event subject
594 modifyBasicInterfaceForwarding(new Interface(intf.name(), intf.connectPoint(),
595 addIps, intf.mac(), intf.vlan()), true);
596 }
597 }
598
kishore71a27532016-03-16 20:23:49 +0530599 private class InternalInterfaceListener implements InterfaceListener {
600
601 @Override
602 public void event(InterfaceEvent event) {
603 Interface intf = event.subject();
kishore7c42cbe2016-04-26 22:49:36 +0530604 Interface prevIntf = event.prevSubject();
kishore71a27532016-03-16 20:23:49 +0530605 switch (event.type()) {
606 case INTERFACE_ADDED:
607 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
608 provisionInterface(intf);
609 }
610 break;
611 case INTERFACE_UPDATED:
kishore7c42cbe2016-04-26 22:49:36 +0530612 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
613 updateInterface(prevIntf, intf);
614 }
kishore71a27532016-03-16 20:23:49 +0530615 break;
616 case INTERFACE_REMOVED:
617 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
618 removeInterface(intf);
619 }
620 break;
621 default:
622 break;
623 }
624 }
625 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800626}