blob: 090ef0f1461f0242a02f987a2dbf4428a7097a96 [file] [log] [blame]
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -07001/*
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.impl;
17
18import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
19import static org.onlab.util.Tools.groupedThreads;
20import static org.slf4j.LoggerFactory.getLogger;
21
22import java.util.ArrayList;
23import java.util.Collection;
lishuaice883902015-09-14 15:46:23 +080024import java.util.Collections;
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -070025import java.util.Iterator;
26import java.util.List;
27import java.util.Set;
28import java.util.concurrent.ScheduledExecutorService;
lishuaice883902015-09-14 15:46:23 +080029import java.util.stream.Collectors;
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -070030
31import org.apache.felix.scr.annotations.Activate;
32import org.apache.felix.scr.annotations.Component;
33import org.apache.felix.scr.annotations.Deactivate;
34import org.apache.felix.scr.annotations.Reference;
35import org.apache.felix.scr.annotations.ReferenceCardinality;
36import org.apache.felix.scr.annotations.Service;
CNluciusa66c3972015-09-06 20:31:29 +080037import org.onlab.osgi.DefaultServiceDirectory;
38import org.onlab.osgi.ServiceDirectory;
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -070039import org.onlab.packet.IpAddress;
40import org.onlab.packet.MacAddress;
41import org.onlab.util.KryoNamespace;
42import org.onosproject.core.ApplicationId;
43import org.onosproject.core.CoreService;
44import org.onosproject.net.Device;
45import org.onosproject.net.DeviceId;
46import org.onosproject.net.Host;
47import org.onosproject.net.HostId;
48import org.onosproject.net.Port;
49import org.onosproject.net.PortNumber;
50import org.onosproject.net.behaviour.BridgeConfig;
51import org.onosproject.net.behaviour.BridgeDescription;
52import org.onosproject.net.behaviour.BridgeName;
53import org.onosproject.net.behaviour.DefaultTunnelDescription;
54import org.onosproject.net.behaviour.IpTunnelEndPoint;
CNluciusa66c3972015-09-06 20:31:29 +080055import org.onosproject.net.behaviour.Pipeliner;
56import org.onosproject.net.behaviour.PipelinerContext;
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -070057import org.onosproject.net.behaviour.TunnelConfig;
58import org.onosproject.net.behaviour.TunnelDescription;
59import org.onosproject.net.behaviour.TunnelEndPoint;
60import org.onosproject.net.device.DeviceEvent;
61import org.onosproject.net.device.DeviceListener;
62import org.onosproject.net.device.DeviceService;
CNluciusa66c3972015-09-06 20:31:29 +080063import org.onosproject.net.driver.DefaultDriverData;
64import org.onosproject.net.driver.Driver;
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -070065import org.onosproject.net.driver.DriverHandler;
66import org.onosproject.net.driver.DriverService;
67import org.onosproject.net.flow.DefaultTrafficSelector;
68import org.onosproject.net.flow.DefaultTrafficTreatment;
69import org.onosproject.net.flow.FlowRuleService;
70import org.onosproject.net.flow.TrafficSelector;
71import org.onosproject.net.flow.TrafficTreatment;
72import org.onosproject.net.flow.criteria.Criteria;
73import org.onosproject.net.flow.instructions.Instructions;
74import org.onosproject.net.flowobjective.DefaultForwardingObjective;
75import org.onosproject.net.flowobjective.FlowObjectiveService;
CNluciusa66c3972015-09-06 20:31:29 +080076import org.onosproject.net.flowobjective.FlowObjectiveStore;
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -070077import org.onosproject.net.flowobjective.ForwardingObjective;
78import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
79import org.onosproject.net.flowobjective.Objective;
80import org.onosproject.net.host.HostEvent;
81import org.onosproject.net.host.HostListener;
82import org.onosproject.net.host.HostService;
83import org.onosproject.store.serializers.KryoNamespaces;
84import org.onosproject.store.service.EventuallyConsistentMap;
85import org.onosproject.store.service.StorageService;
86import org.onosproject.store.service.WallClockTimestamp;
87import org.onosproject.vtn.VTNService;
88import org.onosproject.vtnrsc.SegmentationId;
89import org.onosproject.vtnrsc.TenantNetwork;
90import org.onosproject.vtnrsc.VirtualPort;
91import org.onosproject.vtnrsc.VirtualPortId;
92import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
93import org.onosproject.vtnrsc.virtualport.VirtualPortService;
94import org.slf4j.Logger;
95
96import com.google.common.collect.Sets;
97
98/**
99 * Provides implementation of VTNService.
100 */
101@Component(immediate = true)
102@Service
103public class VTNManager implements VTNService {
104 private final Logger log = getLogger(getClass());
105
106 private static final String APP_ID = "org.onosproject.app.vtn";
107 private ScheduledExecutorService backgroundService;
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected DeviceService deviceService;
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected HostService hostService;
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected FlowRuleService flowRuleService;
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected StorageService storageService;
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected TenantNetworkService tenantNetworkService;
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected VirtualPortService virtualPortService;
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected DriverService driverService;
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected FlowObjectiveService flowObjectiveService;
CNluciusa66c3972015-09-06 20:31:29 +0800126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected FlowObjectiveStore flowObjectiveStore;
128 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700129 private EventuallyConsistentMap<HostId, SegmentationId> binding;
130 private ApplicationId appId;
131 private HostListener hostListener = new InnerHostListener();
132 private DeviceListener deviceListener = new InnerDeviceListener();
133 private static final String IFACEID = "ifaceid";
134 private static final String PORT_HEAD = "vxlan";
135 private static final String DEFAULT_BRIDGE_NAME = "br-int";
136 private static final String CONTROLLER_IP_KEY = "ipaddress";
137 private static final int DEFAULT_MAC_PRIORITY = 0x0000;
138 private static final int MAC_PRIORITY = 0xffff;
139 private static final int DEFAULT_PORT_PRIORITY = 0x0000;
140 private static final int PORT_PRIORITY = 0xffff;
141 private static final String SWITCH_CHANNEL_ID = "channelId";
CNluciusa66c3972015-09-06 20:31:29 +0800142 private static final String DRIVER_NAME = "onosfw";
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700143
144 @Activate
145 public void activate() {
146 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
147 .register(KryoNamespaces.API);
148 appId = coreService.registerApplication(APP_ID);
149 deviceService.addListener(deviceListener);
150 hostService.addListener(hostListener);
151 backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos-apps/vtn",
152 "manager-background"));
153 binding = storageService
154 .<HostId, SegmentationId>eventuallyConsistentMapBuilder()
155 .withName("all_tunnel").withSerializer(serializer)
156 .withTimestampProvider((k, v) -> new WallClockTimestamp())
157 .build();
158 log.info("Started");
159 }
160
161 @Deactivate
162 public void deactivate() {
163 backgroundService.shutdown();
164 binding.destroy();
165 log.info("Stopped");
166 }
167
168 @Override
169 public void onServerDetected(Device device) {
170 Iterable<Device> devices = deviceService.getAvailableDevices();
171 DriverHandler handler = driverService.createHandler(device.id());
172 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
173 bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME));
174 String ipAddress = device.annotations().value(CONTROLLER_IP_KEY);
175 IpAddress ip = IpAddress.valueOf(ipAddress);
176 Sets.newHashSet(devices).stream()
177 .filter(d -> Device.Type.CONTROLLER == d.type())
CNluciusa66c3972015-09-06 20:31:29 +0800178 .filter(d -> !device.id().equals(d.id())).forEach(d -> {
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700179 String ipAddress1 = d.annotations()
180 .value(CONTROLLER_IP_KEY);
181 IpAddress ip1 = IpAddress.valueOf(ipAddress1);
182 applyTunnelConfig(ip, ip1, handler);
183 DriverHandler handler1 = driverService
184 .createHandler(d.id());
185 applyTunnelConfig(ip1, ip, handler1);
CNluciusa66c3972015-09-06 20:31:29 +0800186
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700187 });
188 }
189
190 @Override
191 public void onServerVanished(Device device) {
192 Iterable<Device> devices = deviceService.getAvailableDevices();
193 String ipAddress = device.annotations().value(CONTROLLER_IP_KEY);
194 IpAddress dst = IpAddress.valueOf(ipAddress);
195 Sets.newHashSet(devices).stream()
196 .filter(d -> d.type() == Device.Type.CONTROLLER)
197 .filter(d -> !device.id().equals(d.id())).forEach(d -> {
198 String ipAddress1 = d.annotations()
199 .value(CONTROLLER_IP_KEY);
200 DriverHandler handler = driverService.createHandler(d.id());
201 IpAddress src = IpAddress.valueOf(ipAddress1);
202 removeTunnelConfig(src, dst, handler);
203 });
204 }
205
206 private void applyTunnelConfig(IpAddress src, IpAddress dst,
207 DriverHandler handler) {
208 TunnelEndPoint tunnelAsSrc = IpTunnelEndPoint.ipTunnelPoint(src);
209 TunnelEndPoint tunnelAsDst = IpTunnelEndPoint.ipTunnelPoint(dst);
210 TunnelDescription tunnel = new DefaultTunnelDescription(
211 tunnelAsSrc,
212 tunnelAsDst,
213 TunnelDescription.Type.VXLAN,
214 null);
215 TunnelConfig config = handler.behaviour(TunnelConfig.class);
216 config.createTunnel(tunnel);
217 }
218
219 private void removeTunnelConfig(IpAddress src, IpAddress dst,
220 DriverHandler handler) {
221 TunnelEndPoint tunnelAsSrc = IpTunnelEndPoint.ipTunnelPoint(src);
222 TunnelEndPoint tunnelAsDst = IpTunnelEndPoint.ipTunnelPoint(dst);
223 TunnelDescription tunnel = new DefaultTunnelDescription(
224 tunnelAsSrc,
225 tunnelAsDst,
226 TunnelDescription.Type.VXLAN,
227 null);
228 TunnelConfig config = handler.behaviour(TunnelConfig.class);
229 config.removeTunnel(tunnel);
230 }
231
232 @Override
233 public void onOvsDetected(Device device) {
234 programMacDefaultRules(device.id(), appId, Objective.Operation.ADD);
235 programPortDefaultRules(device.id(), appId, Objective.Operation.ADD);
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700236 }
237
238 @Override
239 public void onOvsVanished(Device device) {
240 programMacDefaultRules(device.id(), appId, Objective.Operation.REMOVE);
241 programPortDefaultRules(device.id(), appId, Objective.Operation.REMOVE);
242 }
243
244 @Override
245 public void onHostDetected(Host host) {
246 String ifaceId = host.annotations().value(IFACEID);
247 DeviceId deviceId = host.location().deviceId();
248 String currentControllerIp = getControllerIpOfSwitch(deviceId);
249 Iterable<Device> devices = deviceService.getAvailableDevices();
250 VirtualPortId portId = VirtualPortId.portId(ifaceId);
251 VirtualPort port = virtualPortService.getPort(portId);
252 TenantNetwork network = tenantNetworkService
253 .getNetwork(port.networkId());
254 String tunnelName = "vxlan-" + currentControllerIp;
255 binding.put(host.id(), network.segmentationId());
256 List<Port> allPorts = deviceService.getPorts(deviceId);
257 PortNumber inPort = host.location().port();
CNluciusa66c3972015-09-06 20:31:29 +0800258 List<PortNumber> localVmPorts = getLocalPorts(deviceId, ifaceId);
259 List<PortNumber> localTunnelPorts = new ArrayList<>();
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700260 Sets.newHashSet(allPorts.iterator()).stream()
261 .filter(p -> !p.number().equals(PortNumber.LOCAL)).forEach(p -> {
CNluciusa66c3972015-09-06 20:31:29 +0800262 if (p.annotations().value("portName").startsWith(PORT_HEAD)) {
263 localTunnelPorts.add(p.number());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700264 }
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700265 });
266
CNluciusa66c3972015-09-06 20:31:29 +0800267 localVmPorts.forEach(lp -> programLocalBcastRules(deviceId, network.segmentationId(), lp, localVmPorts,
268 localTunnelPorts, appId, Objective.Operation.ADD));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700269 programLocalOut(deviceId, network.segmentationId(), inPort, host.mac(),
270 appId, Objective.Operation.ADD);
CNluciusa66c3972015-09-06 20:31:29 +0800271 localTunnelPorts
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700272 .forEach(tp -> programTunnelFloodOut(deviceId,
273 network.segmentationId(),
CNluciusa66c3972015-09-06 20:31:29 +0800274 tp, localVmPorts,
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700275 appId,
276 Objective.Operation.ADD));
277 Sets.newHashSet(devices).stream()
278 .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {
279 DriverHandler handler = driverService.createHandler(d.id());
280 BridgeConfig bridgeConfig = handler
281 .behaviour(BridgeConfig.class);
282 Collection<BridgeDescription> bridgeDescriptions = bridgeConfig
283 .getBridges();
284
285 Iterator<BridgeDescription> it = bridgeDescriptions
286 .iterator();
287 if (it.hasNext()) {
288 BridgeDescription sw = it.next();
289 Set<PortNumber> ports = bridgeConfig.getPortNumbers();
290 ports.stream()
291 .filter(p -> p.name()
292 .equalsIgnoreCase(tunnelName))
Sho SHIMIZUfeafdca2015-09-11 15:02:21 -0700293 .forEach(p -> programTunnelOut(sw.deviceId(),
294 network.segmentationId(), p,
295 host.mac(), appId,
296 Objective.Operation.ADD));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700297 }
298 });
299 programLocalIn(deviceId, network.segmentationId(), inPort, host.mac(),
300 appId, Objective.Operation.ADD);
CNluciusa66c3972015-09-06 20:31:29 +0800301 localTunnelPorts
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700302 .forEach(tp -> programTunnelIn(deviceId,
303 network.segmentationId(),
CNluciusa66c3972015-09-06 20:31:29 +0800304 tp, inPort, host.mac(),
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700305 appId, Objective.Operation.ADD));
306
307 }
308
309 @Override
310 public void onHostVanished(Host host) {
CNluciusa66c3972015-09-06 20:31:29 +0800311 String ifaceId = host.annotations().value(IFACEID);
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700312 SegmentationId segId = binding.remove(host.id());
313 DeviceId deviceId = host.location().deviceId();
314 String currentControllerIp = getControllerIpOfSwitch(deviceId);
315 Iterable<Device> devices = deviceService.getAvailableDevices();
CNluciusa66c3972015-09-06 20:31:29 +0800316
317 String tunnelName = "vxlan-" + currentControllerIp;
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700318 List<Port> allPorts = deviceService.getPorts(deviceId);
319 PortNumber inPort = host.location().port();
CNluciusa66c3972015-09-06 20:31:29 +0800320
321 List<PortNumber> localTunnelPorts = new ArrayList<>();
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700322 Sets.newHashSet(allPorts.iterator()).stream()
323 .filter(p -> !p.number().equals(PortNumber.LOCAL)).forEach(p -> {
CNluciusa66c3972015-09-06 20:31:29 +0800324 if (p.annotations().value("portName").startsWith(PORT_HEAD)) {
325 localTunnelPorts.add(p.number());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700326 }
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700327 });
328
CNluciusa66c3972015-09-06 20:31:29 +0800329 List<PortNumber> localVmPorts = getLocalPorts(deviceId, ifaceId);
330 localVmPorts.add(inPort);
331 localVmPorts.forEach(lp -> programLocalBcastRules(deviceId, segId, lp, localVmPorts,
332 localTunnelPorts, appId, Objective.Operation.REMOVE));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700333 programLocalOut(deviceId, segId, inPort, host.mac(),
334 appId, Objective.Operation.REMOVE);
CNluciusa66c3972015-09-06 20:31:29 +0800335 localTunnelPorts
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700336 .forEach(tp -> programTunnelFloodOut(deviceId,
337 segId,
CNluciusa66c3972015-09-06 20:31:29 +0800338 tp, localVmPorts,
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700339 appId,
340 Objective.Operation.REMOVE));
341 Sets.newHashSet(devices).stream()
342 .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {
343 DriverHandler handler = driverService.createHandler(d.id());
344 BridgeConfig bridgeConfig = handler
345 .behaviour(BridgeConfig.class);
346 Collection<BridgeDescription> bridgeDescriptions = bridgeConfig
347 .getBridges();
348
349 Iterator<BridgeDescription> it = bridgeDescriptions
350 .iterator();
351 if (it.hasNext()) {
352 BridgeDescription sw = it.next();
353 Set<PortNumber> ports = bridgeConfig.getPortNumbers();
354 ports.stream()
355 .filter(p -> p.name()
CNluciusa66c3972015-09-06 20:31:29 +0800356 .equalsIgnoreCase(tunnelName))
Sho SHIMIZUfeafdca2015-09-11 15:02:21 -0700357 .forEach(p -> programTunnelOut(sw.deviceId(),
358 segId, p,
359 host.mac(), appId,
360 Objective.Operation.REMOVE));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700361 }
362 });
363 programLocalIn(deviceId, segId, inPort, host.mac(),
364 appId, Objective.Operation.REMOVE);
CNluciusa66c3972015-09-06 20:31:29 +0800365 localTunnelPorts
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700366 .forEach(tp -> programTunnelIn(deviceId,
367 segId,
CNluciusa66c3972015-09-06 20:31:29 +0800368 tp, inPort, host.mac(),
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700369 appId, Objective.Operation.REMOVE));
370 }
371
372 private class InnerDeviceListener implements DeviceListener {
373
374 @Override
375 public void event(DeviceEvent event) {
376 Device device = event.subject();
377 if (Device.Type.CONTROLLER == device.type()
378 && DeviceEvent.Type.DEVICE_ADDED == event.type()) {
Sho SHIMIZUfeafdca2015-09-11 15:02:21 -0700379 backgroundService.execute(() -> onServerDetected(device));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700380 } else if (Device.Type.CONTROLLER == device.type()
381 && DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED == event
382 .type()) {
Sho SHIMIZUfeafdca2015-09-11 15:02:21 -0700383 backgroundService.execute(() -> onServerVanished(device));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700384 } else if (Device.Type.SWITCH == device.type()
385 && DeviceEvent.Type.DEVICE_ADDED == event.type()) {
Sho SHIMIZUfeafdca2015-09-11 15:02:21 -0700386 backgroundService.execute(() -> onOvsDetected(device));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700387 } else if (Device.Type.SWITCH == device.type()
388 && DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED == event
389 .type()) {
Sho SHIMIZUfeafdca2015-09-11 15:02:21 -0700390 backgroundService.execute(() -> onOvsVanished(device));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700391 } else {
392 log.info("Do nothing for this device type");
393 }
394 }
395
396 }
397
398 private class InnerHostListener implements HostListener {
399
400 @Override
401 public void event(HostEvent event) {
402 Host host = event.subject();
403 if (HostEvent.Type.HOST_ADDED == event.type()) {
Sho SHIMIZUfeafdca2015-09-11 15:02:21 -0700404 backgroundService.execute(() -> onHostDetected(host));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700405 } else if (HostEvent.Type.HOST_REMOVED == event.type()) {
Sho SHIMIZUfeafdca2015-09-11 15:02:21 -0700406 backgroundService.execute(() -> onHostVanished(host));
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700407 } else if (HostEvent.Type.HOST_UPDATED == event.type()) {
408 backgroundService.execute(() -> {
409 onHostVanished(host);
410 onHostDetected(host);
411 });
412 }
413 }
414
415 }
416
417 // Used to forward the flows to the local VM.
418 private void programLocalOut(DeviceId dpid, SegmentationId segmentationId,
419 PortNumber outPort, MacAddress sourceMac,
420 ApplicationId appid,
421 Objective.Operation type) {
422 TrafficSelector selector = DefaultTrafficSelector.builder()
CNluciusa66c3972015-09-06 20:31:29 +0800423 .matchTunnelId(Long.parseLong(segmentationId.toString()))
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700424 .matchEthDst(sourceMac).build();
425 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700426 .setOutput(outPort).build();
427 ForwardingObjective.Builder objective = DefaultForwardingObjective
428 .builder().withTreatment(treatment).withSelector(selector)
429 .fromApp(appId).withFlag(Flag.SPECIFIC)
430 .withPriority(MAC_PRIORITY);
431 if (type.equals(Objective.Operation.ADD)) {
CNluciusa66c3972015-09-06 20:31:29 +0800432 flowServiceForward(dpid, objective.add());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700433 } else {
CNluciusa66c3972015-09-06 20:31:29 +0800434 flowServiceForward(dpid, objective.remove());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700435 }
436
437 }
438
439 // Used to forward the flows into the VXLAN tunnel.
440 private void programTunnelOut(DeviceId dpid, SegmentationId segmentationId,
441 PortNumber tunnelOutPort, MacAddress dstMac,
442 ApplicationId appid,
443 Objective.Operation type) {
444 TrafficSelector selector = DefaultTrafficSelector.builder()
445 .matchEthDst(dstMac).add(Criteria.matchTunnelId(Long
446 .parseLong(segmentationId.toString())))
447 .build();
448 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
449
450 .setOutput(tunnelOutPort).build();
451 ForwardingObjective.Builder objective = DefaultForwardingObjective
452 .builder().withTreatment(treatment).withSelector(selector)
453 .fromApp(appId).withFlag(Flag.SPECIFIC)
454 .withPriority(MAC_PRIORITY);
455 if (type.equals(Objective.Operation.ADD)) {
CNluciusa66c3972015-09-06 20:31:29 +0800456 flowServiceForward(dpid, objective.add());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700457 } else {
CNluciusa66c3972015-09-06 20:31:29 +0800458 flowServiceForward(dpid, objective.remove());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700459 }
460
461 }
462
463 // Used to forward multicast flows to remote VMs of the same tenant via
464 // VXLAN tunnel.
CNluciusa66c3972015-09-06 20:31:29 +0800465 private void programTunnelFloodOut(DeviceId deviceId,
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700466 SegmentationId segmentationId,
467 PortNumber ofPortOut,
CNluciusa66c3972015-09-06 20:31:29 +0800468 List<PortNumber> localVmPorts,
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700469 ApplicationId appid,
470 Objective.Operation type) {
471 TrafficSelector selector = DefaultTrafficSelector.builder()
472 .matchInPort(ofPortOut)
473
474 .add(Criteria.matchTunnelId(Long.parseLong(segmentationId
475 .toString()))).matchEthDst(MacAddress.BROADCAST)
476 .build();
477 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
CNluciusa66c3972015-09-06 20:31:29 +0800478
479 for (PortNumber outPort : localVmPorts) {
480 treatment.setOutput(outPort);
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700481 }
482
483 ForwardingObjective.Builder objective = DefaultForwardingObjective
484 .builder().withTreatment(treatment.build())
485 .withSelector(selector).fromApp(appId).makePermanent()
486 .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);
487 if (type.equals(Objective.Operation.ADD)) {
CNluciusa66c3972015-09-06 20:31:29 +0800488 flowServiceForward(deviceId, objective.add());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700489 } else {
CNluciusa66c3972015-09-06 20:31:29 +0800490 flowServiceForward(deviceId, objective.remove());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700491 }
492 }
493
494 // Applies default flows to mac table.
495 private void programMacDefaultRules(DeviceId dpid, ApplicationId appid,
496 Objective.Operation type) {
497 TrafficSelector selector = DefaultTrafficSelector.builder().build();
498 TrafficTreatment treatment = DefaultTrafficTreatment.builder().drop()
499 .build();
500 ForwardingObjective.Builder objective = DefaultForwardingObjective
501 .builder().withTreatment(treatment).withSelector(selector)
502 .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
503 .withPriority(DEFAULT_MAC_PRIORITY);
504 if (type.equals(Objective.Operation.ADD)) {
CNluciusa66c3972015-09-06 20:31:29 +0800505 flowServiceForward(dpid, objective.add());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700506 } else {
CNluciusa66c3972015-09-06 20:31:29 +0800507 flowServiceForward(dpid, objective.remove());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700508 }
509 }
510
511 // Used to forward the flows to the local VMs with the same tenant.
CNluciusa66c3972015-09-06 20:31:29 +0800512 private void programLocalBcastRules(DeviceId deviceId,
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700513 SegmentationId segmentationId,
CNluciusa66c3972015-09-06 20:31:29 +0800514 PortNumber inPort,
515 List<PortNumber> localVmPorts,
516 List<PortNumber> localTunnelPorts,
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700517 ApplicationId appid,
518 Objective.Operation type) {
519 TrafficSelector selector = DefaultTrafficSelector.builder()
520 .matchInPort(inPort).matchEthDst(MacAddress.BROADCAST)
521 .add(Criteria.matchTunnelId(Long
522 .parseLong(segmentationId.toString())))
523 .build();
524 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
CNluciusa66c3972015-09-06 20:31:29 +0800525 for (PortNumber outPort : localVmPorts) {
526 if (inPort != outPort) {
527 treatment.setOutput(outPort);
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700528 }
529 }
CNluciusa66c3972015-09-06 20:31:29 +0800530 for (PortNumber outport : localTunnelPorts) {
531 treatment.setOutput(outport);
532 }
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700533 ForwardingObjective.Builder objective = DefaultForwardingObjective
534 .builder().withTreatment(treatment.build())
535 .withSelector(selector).fromApp(appId).makePermanent()
536 .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);
537 if (type.equals(Objective.Operation.ADD)) {
CNluciusa66c3972015-09-06 20:31:29 +0800538 flowServiceForward(deviceId, objective.add());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700539 } else {
CNluciusa66c3972015-09-06 20:31:29 +0800540 flowServiceForward(deviceId, objective.remove());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700541 }
542 }
543
544 // Used to apply local entry flow.
545 private void programLocalIn(DeviceId dpid, SegmentationId segmentationId,
546 PortNumber inPort, MacAddress srcMac,
547 ApplicationId appid, Objective.Operation type) {
548 TrafficSelector selector = DefaultTrafficSelector.builder()
549 .matchInPort(inPort).matchEthSrc(srcMac).build();
550 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
551 treatment.add(Instructions.modTunnelId(Long.parseLong(segmentationId
552 .toString())));
553 ForwardingObjective.Builder objective = DefaultForwardingObjective
554 .builder().withTreatment(treatment.build())
555 .withSelector(selector).fromApp(appId).makePermanent()
556 .withFlag(Flag.SPECIFIC).withPriority(PORT_PRIORITY);
557 if (type.equals(Objective.Operation.ADD)) {
CNluciusa66c3972015-09-06 20:31:29 +0800558 flowServiceForward(dpid, objective.add());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700559 } else {
CNluciusa66c3972015-09-06 20:31:29 +0800560 flowServiceForward(dpid, objective.remove());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700561 }
562 }
563
564 // Used to forward the flows from the egress tunnel to the VM.
565 private void programTunnelIn(DeviceId dpid, SegmentationId segmentationId,
566 PortNumber tunnelInPort, PortNumber outPort,
567 MacAddress sourceMac, ApplicationId appid,
568 Objective.Operation type) {
569 TrafficSelector selector = DefaultTrafficSelector.builder()
570 .matchInPort(tunnelInPort).add(Criteria.matchTunnelId(Long
571 .parseLong(segmentationId.toString())))
572 .build();
573 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
574
575 ForwardingObjective.Builder objective = DefaultForwardingObjective
576 .builder().withTreatment(treatment).withSelector(selector)
577 .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
578 .withPriority(PORT_PRIORITY);
579 if (type.equals(Objective.Operation.ADD)) {
CNluciusa66c3972015-09-06 20:31:29 +0800580 flowServiceForward(dpid, objective.add());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700581 } else {
CNluciusa66c3972015-09-06 20:31:29 +0800582 flowServiceForward(dpid, objective.remove());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700583 }
584 }
585
586 // Applies the default flows to port table.
587 private void programPortDefaultRules(DeviceId dpid, ApplicationId appid,
588 Objective.Operation type) {
589 TrafficSelector selector = DefaultTrafficSelector.builder().build();
590 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
591 ForwardingObjective.Builder objective = DefaultForwardingObjective
592 .builder().withTreatment(treatment).withSelector(selector)
593 .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
594 .withPriority(DEFAULT_PORT_PRIORITY);
595 if (type.equals(Objective.Operation.ADD)) {
CNluciusa66c3972015-09-06 20:31:29 +0800596 flowServiceForward(dpid, objective.add());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700597 } else {
CNluciusa66c3972015-09-06 20:31:29 +0800598 flowServiceForward(dpid, objective.remove());
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700599 }
600 }
601
602 // Used to get channelId from the device annotations.
603 private String getControllerIpOfSwitch(DeviceId deviceId) {
604 Device device = deviceService.getDevice(deviceId);
605 String url = device.annotations().value(SWITCH_CHANNEL_ID);
606 return url.substring(0, url.lastIndexOf(":"));
607 }
608
CNluciusa66c3972015-09-06 20:31:29 +0800609 private Iterable<String> getIfaceIds(String ifaceId) {
610 VirtualPortId portId = VirtualPortId.portId(ifaceId);
611 VirtualPort port = virtualPortService.getPort(portId);
lishuaice883902015-09-14 15:46:23 +0800612 if (port == null) {
613 return Collections.emptyList();
614 }
615
CNluciusa66c3972015-09-06 20:31:29 +0800616 TenantNetwork network = tenantNetworkService
617 .getNetwork(port.networkId());
lishuaice883902015-09-14 15:46:23 +0800618 if (network == null) {
619 return Collections.emptyList();
620 }
621
CNluciusa66c3972015-09-06 20:31:29 +0800622 Collection<VirtualPort> ports = virtualPortService
623 .getPorts(network.id());
lishuaice883902015-09-14 15:46:23 +0800624 return ports.stream().map(p -> p.portId().portId())
625 .collect(Collectors.toSet());
CNluciusa66c3972015-09-06 20:31:29 +0800626 }
627
628 private List<PortNumber> getLocalPorts(DeviceId deviceId, String ifaceId) {
629 DriverHandler handler = driverService
630 .createHandler(getController(deviceId));
631 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
632 Iterable<String> ifaceIds = getIfaceIds(ifaceId);
633 return bridgeConfig.getLocalPorts(ifaceIds);
634 }
635
636 private DeviceId getController(DeviceId deviceId) {
637 Iterable<Device> devices = deviceService.getAvailableDevices();
638 for (Device device : devices) {
639 if (device.type() == Device.Type.CONTROLLER && device.id()
640 .toString().contains(getControllerIpOfSwitch(deviceId))) {
641 return device.id();
642 }
643 }
644 log.info("Can not find controller for device : {}", deviceId);
645 return null;
646 }
647
648 //Used to apply flowRule
649 private void flowServiceForward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
650 Driver driver = driverService.getDriver(DRIVER_NAME);
651 Pipeliner pipeLiner = driver.createBehaviour(new DefaultDriverData(driver, deviceId), Pipeliner.class);
652 if (pipeLiner != null) {
653 final PipelinerContext context = new InnerPipelineContext();
654 pipeLiner.init(deviceId, context);
655 pipeLiner.forward(forwardingObjective);
656 }
657 }
658
659 // Processing context for initializing pipeline driver behaviours.
660 private class InnerPipelineContext implements PipelinerContext {
661 @Override
662 public ServiceDirectory directory() {
663 return serviceDirectory;
664 }
665
666 @Override
667 public FlowObjectiveStore store() {
668 return flowObjectiveStore;
669 }
670 }
671
Sho SHIMIZU7d2e48e2015-09-01 17:37:00 -0700672}