blob: 7192ad95f52878bcceec1bd956606044701ba796 [file] [log] [blame]
lishuai6c56f5e2015-11-17 16:38:19 +08001/*
2 * Copyright 2015 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 */
16package org.onosproject.vtn.manager.impl;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.Collection;
21import java.util.HashMap;
22import java.util.HashSet;
23import java.util.Iterator;
24import java.util.Map;
25import java.util.Set;
26
27import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
30import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
32import org.apache.felix.scr.annotations.Service;
33import org.onlab.packet.IpAddress;
34import org.onlab.packet.MacAddress;
35import org.onlab.util.KryoNamespace;
36import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
38import org.onosproject.mastership.MastershipService;
39import org.onosproject.net.Device;
40import org.onosproject.net.DeviceId;
41import org.onosproject.net.Host;
42import org.onosproject.net.Port;
43import org.onosproject.net.PortNumber;
44import org.onosproject.net.behaviour.BridgeConfig;
45import org.onosproject.net.behaviour.BridgeDescription;
46import org.onosproject.net.config.NetworkConfigService;
47import org.onosproject.net.config.basics.BasicDeviceConfig;
48import org.onosproject.net.device.DeviceEvent;
49import org.onosproject.net.device.DeviceListener;
50import org.onosproject.net.device.DeviceService;
51import org.onosproject.net.driver.DriverHandler;
52import org.onosproject.net.driver.DriverService;
53import org.onosproject.net.flowobjective.Objective;
54import org.onosproject.net.host.HostEvent;
55import org.onosproject.net.host.HostListener;
56import org.onosproject.net.host.HostService;
57import org.onosproject.store.serializers.KryoNamespaces;
58import org.onosproject.store.service.ConsistentMap;
59import org.onosproject.store.service.EventuallyConsistentMap;
60import org.onosproject.store.service.LogicalClockService;
61import org.onosproject.store.service.Serializer;
62import org.onosproject.store.service.StorageService;
63import org.onosproject.vtn.manager.VTNService;
64import org.onosproject.vtn.table.ClassifierService;
65import org.onosproject.vtn.table.L2ForwardService;
66import org.onosproject.vtn.table.impl.ClassifierServiceImpl;
67import org.onosproject.vtn.table.impl.L2ForwardServiceImpl;
68import org.onosproject.vtn.util.DataPathIdGenerator;
69import org.onosproject.vtn.util.VtnConfig;
70import org.onosproject.vtn.util.VtnData;
71import org.onosproject.vtnrsc.SegmentationId;
72import org.onosproject.vtnrsc.SubnetId;
73import org.onosproject.vtnrsc.TenantId;
74import org.onosproject.vtnrsc.TenantNetwork;
75import org.onosproject.vtnrsc.TenantNetworkId;
76import org.onosproject.vtnrsc.VirtualPort;
77import org.onosproject.vtnrsc.VirtualPortId;
78import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
79import org.onosproject.vtnrsc.virtualport.VirtualPortService;
80import org.slf4j.Logger;
81
82import com.google.common.collect.Sets;
83
84/**
85 * Provides implementation of VTNService.
86 */
87@Component(immediate = true)
88@Service
89public class VTNManager implements VTNService {
90 private final Logger log = getLogger(getClass());
91 private static final String APP_ID = "org.onosproject.app.vtn";
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected NetworkConfigService configService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected DeviceService deviceService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected HostService hostService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected CoreService coreService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected StorageService storageService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected TenantNetworkService tenantNetworkService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected VirtualPortService virtualPortService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected DriverService driverService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected LogicalClockService clockService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected MastershipService mastershipService;
122
123 private ApplicationId appId;
124 private ClassifierService classifierService;
125 private L2ForwardService l2ForwardService;
126
127 private final HostListener hostListener = new InnerHostListener();
128 private final DeviceListener deviceListener = new InnerDeviceListener();
129
130 private static final String IFACEID = "ifaceid";
131 private static final String CONTROLLER_IP_KEY = "ipaddress";
132 public static final String DRIVER_NAME = "onosfw";
133 private static final String EX_PORT_NAME = "eth0";
134 private static final String SWITCHES_OF_CONTROLLER = "switchesOfController";
135 private static final String SWITCH_OF_LOCAL_HOST_PORTS = "switchOfLocalHostPorts";
136
137 private EventuallyConsistentMap<IpAddress, Boolean> switchesOfController;
138 private ConsistentMap<DeviceId, NetworkOfLocalHostPorts> switchOfLocalHostPorts;
139
140 @Activate
141 public void activate() {
142 appId = coreService.registerApplication(APP_ID);
143 classifierService = new ClassifierServiceImpl(appId);
144 l2ForwardService = new L2ForwardServiceImpl(appId);
145
146 deviceService.addListener(deviceListener);
147 hostService.addListener(hostListener);
148
149 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
150 .register(KryoNamespaces.API)
151 .register(NetworkOfLocalHostPorts.class)
152 .register(TenantNetworkId.class)
153 .register(Host.class)
154 .register(TenantNetwork.class)
155 .register(TenantId.class)
156 .register(SubnetId.class);
157
158 switchesOfController = storageService
159 .<IpAddress, Boolean>eventuallyConsistentMapBuilder()
160 .withName(SWITCHES_OF_CONTROLLER).withSerializer(serializer)
161 .withTimestampProvider((k, v) -> clockService.getTimestamp())
162 .build();
163
164 switchOfLocalHostPorts = storageService
165 .<DeviceId, NetworkOfLocalHostPorts>consistentMapBuilder()
166 .withName(SWITCH_OF_LOCAL_HOST_PORTS)
167 .withSerializer(Serializer.using(serializer.build()))
168 .build();
169
170 log.info("Started");
171 }
172
173 @Deactivate
174 public void deactivate() {
175 deviceService.removeListener(deviceListener);
176 hostService.removeListener(hostListener);
177 log.info("Stopped");
178 }
179
180 @Override
181 public void onControllerDetected(Device controllerDevice) {
182 if (controllerDevice == null) {
183 log.error("The controller device is null");
184 return;
185 }
186 String localIpAddress = controllerDevice.annotations()
187 .value(CONTROLLER_IP_KEY);
188 IpAddress localIp = IpAddress.valueOf(localIpAddress);
189 DeviceId controllerDeviceId = controllerDevice.id();
190 DriverHandler handler = driverService.createHandler(controllerDeviceId);
191 if (mastershipService.isLocalMaster(controllerDeviceId)) {
192 // Get DataPathIdGenerator
193 String ipaddress = controllerDevice.annotations().value("ipaddress");
194 DataPathIdGenerator dpidGenerator = DataPathIdGenerator.builder()
195 .addIpAddress(ipaddress).build();
196 DeviceId deviceId = dpidGenerator.getDeviceId();
197 String dpid = dpidGenerator.getDpId();
198 // Inject pipeline driver name
199 BasicDeviceConfig config = configService.addConfig(deviceId,
200 BasicDeviceConfig.class);
201 config.driver(DRIVER_NAME);
202 configService.applyConfig(deviceId, BasicDeviceConfig.class, config.node());
203 // Add Bridge
204 VtnConfig.applyBridgeConfig(handler, dpid, EX_PORT_NAME);
205 log.info("A new ovs is created in node {}", localIp.toString());
206 switchesOfController.put(localIp, true);
207 }
208 // Create tunnel in br-int on all controllers
209 programTunnelConfig(controllerDeviceId, localIp, handler);
210 }
211
212 @Override
213 public void onControllerVanished(Device controllerDevice) {
214 if (controllerDevice == null) {
215 log.error("The device is null");
216 return;
217 }
218 String dstIp = controllerDevice.annotations().value(CONTROLLER_IP_KEY);
219 IpAddress dstIpAddress = IpAddress.valueOf(dstIp);
220 DeviceId controllerDeviceId = controllerDevice.id();
221 if (mastershipService.isLocalMaster(controllerDeviceId)) {
222 switchesOfController.remove(dstIpAddress);
223 }
224 // remove tunnel in br-int on other controllers
225 programTunnelConfig(controllerDeviceId, dstIpAddress, null);
226 }
227
228 @Override
229 public void onOvsDetected(Device device) {
230 // Create tunnel out flow rules
231 applyTunnelOut(device, Objective.Operation.ADD);
232 }
233
234 @Override
235 public void onOvsVanished(Device device) {
236 // Remove Tunnel out flow rules
237 applyTunnelOut(device, Objective.Operation.REMOVE);
238 }
239
240 @Override
241 public void onHostDetected(Host host) {
242 // apply L2 openflow rules
243 applyHostMonitoredL2Rules(host, Objective.Operation.ADD);
244 }
245
246 @Override
247 public void onHostVanished(Host host) {
248 // apply L2 openflow rules
249 applyHostMonitoredL2Rules(host, Objective.Operation.REMOVE);
250 }
251
252 private void programTunnelConfig(DeviceId localDeviceId, IpAddress localIp,
253 DriverHandler localHandler) {
254 Iterable<Device> devices = deviceService.getAvailableDevices();
255 Sets.newHashSet(devices).stream()
256 .filter(d -> Device.Type.CONTROLLER == d.type())
257 .filter(d -> !localDeviceId.equals(d.id())).forEach(d -> {
258 DriverHandler tunHandler = driverService
259 .createHandler(d.id());
260 String remoteIpAddress = d.annotations()
261 .value(CONTROLLER_IP_KEY);
262 IpAddress remoteIp = IpAddress.valueOf(remoteIpAddress);
263 if (remoteIp.toString()
264 .equalsIgnoreCase(localIp.toString())) {
265 log.error("The localIp and remoteIp are the same");
266 return;
267 }
268 if (localHandler != null) {
269 // Create tunnel in br-int on local controller
270 if (mastershipService.isLocalMaster(localDeviceId)) {
271 VtnConfig.applyTunnelConfig(localHandler, localIp, remoteIp);
272 log.info("Add tunnel between {} and {}", localIp,
273 remoteIp);
274 }
275 // Create tunnel in br-int on other controllers
276 if (mastershipService.isLocalMaster(d.id())) {
277 VtnConfig.applyTunnelConfig(tunHandler, remoteIp,
278 localIp);
279 log.info("Add tunnel between {} and {}", remoteIp,
280 localIp);
281 }
282 } else {
283 // remove tunnel in br-int on other controllers
284 if (mastershipService.isLocalMaster(d.id())) {
285 VtnConfig.removeTunnelConfig(tunHandler, remoteIp,
286 localIp);
287 log.info("Remove tunnel between {} and {}", remoteIp,
288 localIp);
289 }
290 }
291 });
292 }
293
294 private void applyTunnelOut(Device device, Objective.Operation type) {
295 if (device == null) {
296 log.error("The device is null");
297 return;
298 }
299 if (!mastershipService.isLocalMaster(device.id())) {
300 return;
301 }
302 String controllerIp = VtnData.getControllerIpOfSwitch(device);
303 if (controllerIp == null) {
304 log.error("Can't find controller of device: {}",
305 device.id().toString());
306 return;
307 }
308 IpAddress ipAddress = IpAddress.valueOf(controllerIp);
309 if (!switchesOfController.containsKey(ipAddress)) {
310 log.error("Can't find controller of device: {}",
311 device.id().toString());
312 return;
313 }
314 if (type == Objective.Operation.ADD) {
315 switchOfLocalHostPorts.put(device.id(), new NetworkOfLocalHostPorts());
316 } else if (type == Objective.Operation.REMOVE) {
317 switchOfLocalHostPorts.remove(device.id());
318 }
319 Iterable<Device> devices = deviceService.getAvailableDevices();
320 DeviceId localControllerId = VtnData.getControllerId(device, devices);
321 DriverHandler handler = driverService.createHandler(localControllerId);
322 Set<PortNumber> ports = VtnConfig.getPortNumbers(handler);
323 Iterable<Host> allHosts = hostService.getHosts();
324 if (allHosts != null) {
325 Sets.newHashSet(allHosts).stream().forEach(host -> {
326 MacAddress hostMac = host.mac();
327 String ifaceId = host.annotations().value(IFACEID);
328 if (ifaceId == null) {
329 log.error("The ifaceId of Host is null");
330 return;
331 }
332 VirtualPortId virtualPortId = VirtualPortId.portId(ifaceId);
333 VirtualPort virtualPort = virtualPortService
334 .getPort(virtualPortId);
335 TenantNetwork network = tenantNetworkService
336 .getNetwork(virtualPort.networkId());
337 SegmentationId segmentationId = network.segmentationId();
338 DeviceId remoteDeviceId = host.location().deviceId();
339 Device remoteDevice = deviceService.getDevice(remoteDeviceId);
340 String remoteControllerIp = VtnData
341 .getControllerIpOfSwitch(remoteDevice);
342 if (remoteControllerIp == null) {
343 log.error("Can't find remote controller of device: {}",
344 remoteDeviceId.toString());
345 return;
346 }
347 IpAddress remoteIpAddress = IpAddress
348 .valueOf(remoteControllerIp);
349 String tunnelName = "vxlan-" + remoteIpAddress.toString();
350 ports.stream()
351 .filter(p -> p.name().equalsIgnoreCase(tunnelName))
352 .forEach(p -> {
353 l2ForwardService
354 .programTunnelOut(device.id(), segmentationId, p,
355 hostMac, type);
356 });
357 });
358 }
359 }
360
361 private void applyHostMonitoredL2Rules(Host host, Objective.Operation type) {
362 DeviceId deviceId = host.location().deviceId();
363 if (!mastershipService.isLocalMaster(deviceId)) {
364 return;
365 }
366 String ifaceId = host.annotations().value(IFACEID);
367 if (ifaceId == null) {
368 log.error("The ifaceId of Host is null");
369 return;
370 }
371 VirtualPortId virtualPortId = VirtualPortId.portId(ifaceId);
372 VirtualPort virtualPort = virtualPortService.getPort(virtualPortId);
373 if (virtualPort == null) {
374 log.error("The virtualPort of host is null");
375 return;
376 }
377
378 Iterable<Device> devices = deviceService.getAvailableDevices();
379 PortNumber inPort = host.location().port();
380 MacAddress mac = host.mac();
381 Device device = deviceService.getDevice(deviceId);
382 String controllerIp = VtnData.getControllerIpOfSwitch(device);
383 IpAddress ipAddress = IpAddress.valueOf(controllerIp);
384 TenantNetwork network = tenantNetworkService.getNetwork(virtualPort.networkId());
385 if (network == null) {
386 log.error("Can't find network of the host");
387 return;
388 }
389 SegmentationId segmentationId = network.segmentationId();
390 // Get all the tunnel PortNumber in the current node
391 Iterable<Port> ports = deviceService.getPorts(deviceId);
392 Collection<PortNumber> localTunnelPorts = VtnData.getLocalTunnelPorts(ports);
393 // Get all the local vm's PortNumber in the current node
394 Map<TenantNetworkId, Set<PortNumber>> localHostPorts = switchOfLocalHostPorts
395 .get(deviceId).value().getNetworkOfLocalHostPorts();
396 Set<PortNumber> networkOflocalHostPorts = localHostPorts.get(network.id());
397
398 l2ForwardService.programLocalBcastRules(deviceId, segmentationId,
399 inPort, networkOflocalHostPorts,
400 localTunnelPorts,
401 type);
402
403 l2ForwardService.programLocalOut(deviceId, segmentationId, inPort, mac,
404 type);
405
406 if (type == Objective.Operation.ADD) {
407 if (networkOflocalHostPorts == null) {
408 networkOflocalHostPorts = new HashSet<PortNumber>();
409 localHostPorts.putIfAbsent(network.id(), networkOflocalHostPorts);
410 }
411 networkOflocalHostPorts.add(inPort);
412 classifierService.programTunnelIn(deviceId, segmentationId,
413 localTunnelPorts,
414 type);
415 } else if (type == Objective.Operation.REMOVE) {
416 networkOflocalHostPorts.remove(inPort);
417 if (networkOflocalHostPorts.isEmpty()) {
418 classifierService.programTunnelIn(deviceId, segmentationId,
419 localTunnelPorts,
420 Objective.Operation.REMOVE);
421 switchOfLocalHostPorts.get(deviceId).value().getNetworkOfLocalHostPorts()
422 .remove(virtualPort.networkId());
423 }
424 }
425
426 l2ForwardService.programTunnelBcastRules(deviceId, segmentationId,
427 networkOflocalHostPorts,
428 localTunnelPorts,
429 type);
430
431 programTunnelOuts(devices, ipAddress, segmentationId, mac,
432 type);
433
434 classifierService.programLocalIn(deviceId, segmentationId, inPort, mac,
435 appId, type);
436 }
437
438 private void programTunnelOuts(Iterable<Device> devices,
439 IpAddress ipAddress,
440 SegmentationId segmentationId,
441 MacAddress dstMac,
442 Objective.Operation type) {
443 String tunnelName = "vxlan-" + ipAddress.toString();
444 Sets.newHashSet(devices).stream()
445 .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {
446 DriverHandler handler = driverService.createHandler(d.id());
447 BridgeConfig bridgeConfig = handler
448 .behaviour(BridgeConfig.class);
449 Collection<BridgeDescription> bridgeDescriptions = bridgeConfig
450 .getBridges();
451 Set<PortNumber> ports = bridgeConfig.getPortNumbers();
452 Iterator<BridgeDescription> it = bridgeDescriptions
453 .iterator();
454 if (it.hasNext()) {
455 BridgeDescription sw = it.next();
456 ports.stream()
457 .filter(p -> p.name()
458 .equalsIgnoreCase(tunnelName))
459 .forEach(p -> {
460 l2ForwardService.programTunnelOut(sw.deviceId(),
461 segmentationId, p,
462 dstMac, type);
463 });
464 }
465 });
466 }
467
468 private class InnerDeviceListener implements DeviceListener {
469
470 @Override
471 public void event(DeviceEvent event) {
472 Device device = event.subject();
473 if (Device.Type.CONTROLLER == device.type()) {
474 if (DeviceEvent.Type.DEVICE_ADDED == event.type()) {
475 onControllerDetected(device);
476 }
477 if (DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED == event.type()) {
478 if (deviceService.isAvailable(device.id())) {
479 onControllerDetected(device);
480 } else {
481 onControllerVanished(device);
482 }
483 }
484 } else if (Device.Type.SWITCH == device.type()) {
485 if (DeviceEvent.Type.DEVICE_ADDED == event.type()) {
486 onOvsDetected(device);
487 }
488 if (DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED == event.type()) {
489 if (deviceService.isAvailable(device.id())) {
490 onOvsDetected(device);
491 } else {
492 onOvsVanished(device);
493 }
494 }
495 } else {
496 log.info("Do nothing for this device type");
497 }
498 }
499 }
500
501 private class InnerHostListener implements HostListener {
502
503 @Override
504 public void event(HostEvent event) {
505 Host host = event.subject();
506 if (HostEvent.Type.HOST_ADDED == event.type()) {
507 onHostDetected(host);
508 } else if (HostEvent.Type.HOST_REMOVED == event.type()) {
509 onHostVanished(host);
510 } else if (HostEvent.Type.HOST_UPDATED == event.type()) {
511 onHostVanished(host);
512 onHostDetected(host);
513 }
514 }
515
516 }
517
518 // Local Host Ports of Network.
519 private class NetworkOfLocalHostPorts {
520 private final Map<TenantNetworkId, Set<PortNumber>> networkOfLocalHostPorts =
521 new HashMap<TenantNetworkId, Set<PortNumber>>();
522
523 public Map<TenantNetworkId, Set<PortNumber>> getNetworkOfLocalHostPorts() {
524 return networkOfLocalHostPorts;
525 }
526 }
527
528}