blob: a82d4ff29a0bd0d224673c532448c3bc3d05de0c [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
kishore71a27532016-03-16 20:23:49 +053019import static com.google.common.base.Preconditions.checkState;
20import static org.slf4j.LoggerFactory.getLogger;
21
22import java.util.Collections;
23import java.util.Iterator;
24import java.util.List;
25import java.util.Map;
26import java.util.Optional;
27import java.util.Set;
28
Jonathan Hart6344f572015-12-15 08:26:25 -080029import org.apache.felix.scr.annotations.Activate;
30import org.apache.felix.scr.annotations.Component;
31import org.apache.felix.scr.annotations.Deactivate;
32import org.apache.felix.scr.annotations.Reference;
33import org.apache.felix.scr.annotations.ReferenceCardinality;
34import org.onlab.packet.EthType;
Charles Chand0fd5dc2016-02-16 23:14:49 -080035import org.onlab.packet.IpPrefix;
36import org.onlab.packet.MacAddress;
Saurav Das49cb5a12016-01-16 22:54:07 -080037import org.onlab.packet.VlanId;
Jonathan Hart6344f572015-12-15 08:26:25 -080038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
40import org.onosproject.incubator.net.intf.Interface;
kishore71a27532016-03-16 20:23:49 +053041import org.onosproject.incubator.net.intf.InterfaceEvent;
42import org.onosproject.incubator.net.intf.InterfaceListener;
Jonathan Hart6344f572015-12-15 08:26:25 -080043import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080044import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080045import org.onosproject.net.ConnectPoint;
46import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080047import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080048import org.onosproject.net.PortNumber;
49import org.onosproject.net.config.NetworkConfigEvent;
50import org.onosproject.net.config.NetworkConfigListener;
51import org.onosproject.net.config.NetworkConfigService;
52import org.onosproject.net.device.DeviceEvent;
53import org.onosproject.net.device.DeviceListener;
54import org.onosproject.net.device.DeviceService;
55import org.onosproject.net.flow.DefaultTrafficSelector;
56import org.onosproject.net.flow.DefaultTrafficTreatment;
57import org.onosproject.net.flow.TrafficSelector;
58import org.onosproject.net.flow.TrafficTreatment;
59import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080060import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Hart6344f572015-12-15 08:26:25 -080061import org.onosproject.net.flowobjective.FlowObjectiveService;
62import org.onosproject.net.flowobjective.ForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080063import org.onosproject.net.flowobjective.NextObjective;
Charles Chand0fd5dc2016-02-16 23:14:49 -080064import org.onosproject.net.host.HostEvent;
65import org.onosproject.net.host.HostListener;
66import org.onosproject.net.host.HostService;
Jonathan Hart6344f572015-12-15 08:26:25 -080067import org.onosproject.net.host.InterfaceIpAddress;
68import org.onosproject.routing.RoutingService;
69import org.onosproject.routing.config.RouterConfig;
70import org.slf4j.Logger;
71
kishore71a27532016-03-16 20:23:49 +053072import com.google.common.collect.ImmutableSortedSet;
73import com.google.common.collect.Maps;
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 /**
186 * Install or removes the basic forwarding flows for each interface
187 * 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 /**
269 * Install or removes ospf forwarding rules.
270 *
271 * @param intf the Interface on which event is received
272 * @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 }
296 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());
334 log.debug("Submited next objective {} in device {} for port/vlan {}/{}",
335 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 }
388
389 break;
390 case DEVICE_UPDATED:
391 case DEVICE_REMOVED:
392 case DEVICE_SUSPENDED:
393 case PORT_ADDED:
394 case PORT_UPDATED:
395 case PORT_REMOVED:
396 default:
397 break;
398 }
399 }
400 }
401 }
402
Jonathan Hartea492382016-01-13 09:33:13 -0800403 /**
404 * Listener for network config events.
405 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800406 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530407
Jonathan Hart6344f572015-12-15 08:26:25 -0800408 @Override
409 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800410 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800411 switch (event.type()) {
412 case CONFIG_ADDED:
413 case CONFIG_UPDATED:
414 updateConfig();
415 break;
416 case CONFIG_REGISTERED:
417 case CONFIG_UNREGISTERED:
418 case CONFIG_REMOVED:
419 default:
420 break;
421 }
422 }
423 }
424 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800425
426 /**
427 * Listener for host events.
428 */
429 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530430
Charles Chand0fd5dc2016-02-16 23:14:49 -0800431 private void peerAdded(HostEvent event) {
432 Host peer = event.subject();
433 Optional<Interface> peerIntf =
434 interfaceService.getInterfacesByPort(peer.location()).stream()
435 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
436 .filter(intf -> peer.vlan().equals(intf.vlan()))
437 .findFirst();
438 if (!peerIntf.isPresent()) {
439 log.debug("Adding peer {}/{} on {} but the interface is not configured",
440 peer.mac(), peer.vlan(), peer.location());
441 return;
442 }
443
444 // Generate L3 Unicast groups and store it in the map
445 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
446 peer.vlan(), peer.location().deviceId(), controlPlaneConnectPoint.port());
447 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
448 peer.vlan(), peer.location().deviceId(), peer.location().port());
449 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
450
451 // From peer to router
452 peerIntf.get().ipAddresses().forEach(routerIp -> {
453 flowObjectiveService.forward(peer.location().deviceId(),
454 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
455 });
456
457 // From router to peer
458 peer.ipAddresses().forEach(peerIp -> {
459 flowObjectiveService.forward(peer.location().deviceId(),
460 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
461 });
462 }
463
464 private void peerRemoved(HostEvent event) {
465 Host peer = event.subject();
466 Optional<Interface> peerIntf =
467 interfaceService.getInterfacesByPort(peer.location()).stream()
468 .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
469 .filter(intf -> peer.vlan().equals(intf.vlan()))
470 .findFirst();
471 if (!peerIntf.isPresent()) {
472 log.debug("Removing peer {}/{} on {} but the interface is not configured",
473 peer.mac(), peer.vlan(), peer.location());
474 return;
475 }
476
477 Set<Integer> nextIds = peerNextId.get(peer);
478 checkState(peerNextId.get(peer) != null,
479 "Peer nextId should not be null");
480 checkState(peerNextId.get(peer).size() == 2,
481 "Wrong nextId associated with the peer");
482 Iterator<Integer> iter = peerNextId.get(peer).iterator();
483 int toRouterL3Unicast = iter.next();
484 int toPeerL3Unicast = iter.next();
485
486 // From peer to router
487 peerIntf.get().ipAddresses().forEach(routerIp -> {
488 flowObjectiveService.forward(peer.location().deviceId(),
489 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
490 });
491
492 // From router to peer
493 peer.ipAddresses().forEach(peerIp -> {
494 flowObjectiveService.forward(peer.location().deviceId(),
495 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
496 });
497 }
498
499 private ForwardingObjective.Builder createPeerObjBuilder(
500 int nextId, IpPrefix ipAddresses) {
501 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
502 sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
503 sbuilder.matchIPDst(ipAddresses);
504 DefaultForwardingObjective.Builder builder =
505 DefaultForwardingObjective.builder()
506 .withSelector(sbuilder.build())
507 .fromApp(appId)
508 .withPriority(getPriorityFromPrefix(ipAddresses))
509 .withFlag(ForwardingObjective.Flag.SPECIFIC);
510 if (nextId != -1) {
511 builder.nextStep(nextId);
512 }
513 return builder;
514 }
515
516 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
517 VlanId vlanId, DeviceId deviceId, PortNumber port) {
518 int nextId = flowObjectiveService.allocateNextId();
519 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
520 .withId(nextId)
521 .withType(NextObjective.Type.SIMPLE)
522 .fromApp(appId);
523
524 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
525 ttBuilder.setEthSrc(srcMac);
526 ttBuilder.setEthDst(dstMac);
527 ttBuilder.setOutput(port);
528 nextObjBuilder.addTreatment(ttBuilder.build());
529
530 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
531 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
532 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN) :
533 vlanId;
534 metabuilder.matchVlanId(matchVlanId);
535 nextObjBuilder.withMeta(metabuilder.build());
536
537 flowObjectiveService.next(deviceId, nextObjBuilder.add());
538 return nextId;
539 }
540
541 @Override
542 public void event(HostEvent event) {
543 DeviceId deviceId = event.subject().location().deviceId();
544 if (!mastershipService.isLocalMaster(deviceId)) {
545 return;
546 }
547 switch (event.type()) {
548 case HOST_ADDED:
549 peerAdded(event);
550 break;
551 case HOST_MOVED:
552 //TODO We assume BGP peer does not move for now
553 break;
554 case HOST_REMOVED:
555 peerRemoved(event);
556 break;
557 case HOST_UPDATED:
558 //TODO We assume BGP peer does not change IP for now
559 break;
560 default:
561 break;
562 }
563 }
564 }
565
566 private int getPriorityFromPrefix(IpPrefix prefix) {
567 return (prefix.isIp4()) ?
568 2000 * prefix.prefixLength() + MIN_IP_PRIORITY :
569 500 * prefix.prefixLength() + MIN_IP_PRIORITY;
570 }
kishore71a27532016-03-16 20:23:49 +0530571 private class InternalInterfaceListener implements InterfaceListener {
572
573 @Override
574 public void event(InterfaceEvent event) {
575 Interface intf = event.subject();
576 switch (event.type()) {
577 case INTERFACE_ADDED:
578 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
579 provisionInterface(intf);
580 }
581 break;
582 case INTERFACE_UPDATED:
583 break;
584 case INTERFACE_REMOVED:
585 if (intf != null && !intf.connectPoint().equals(controlPlaneConnectPoint)) {
586 removeInterface(intf);
587 }
588 break;
589 default:
590 break;
591 }
592 }
593 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800594}