blob: 6fc63e1036acf6f9f2a53e87cc9162c395108b91 [file] [log] [blame]
CNlucius5b2fff12015-08-20 14:13:46 +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.impl;
17
18import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
19import static org.onlab.util.Tools.groupedThreads;
20import static org.slf4j.LoggerFactory.getLogger;
21
CNlucius40003022015-08-21 14:45:26 +080022import java.util.ArrayList;
23import java.util.Collection;
CNlucius5b2fff12015-08-20 14:13:46 +080024import java.util.HashSet;
CNlucius40003022015-08-21 14:45:26 +080025import java.util.Iterator;
CNlucius5b2fff12015-08-20 14:13:46 +080026import java.util.List;
27import java.util.Set;
28import java.util.concurrent.ScheduledExecutorService;
29
30import org.apache.felix.scr.annotations.Activate;
31import org.apache.felix.scr.annotations.Component;
32import org.apache.felix.scr.annotations.Deactivate;
33import org.apache.felix.scr.annotations.Reference;
34import org.apache.felix.scr.annotations.ReferenceCardinality;
35import org.apache.felix.scr.annotations.Service;
36import org.onlab.packet.IpAddress;
37import org.onlab.packet.MacAddress;
38import org.onlab.util.KryoNamespace;
39import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
41import org.onosproject.net.Device;
42import org.onosproject.net.DeviceId;
43import org.onosproject.net.Host;
44import org.onosproject.net.HostId;
45import org.onosproject.net.Port;
46import org.onosproject.net.PortNumber;
47import org.onosproject.net.behaviour.BridgeConfig;
CNlucius40003022015-08-21 14:45:26 +080048import org.onosproject.net.behaviour.BridgeDescription;
CNlucius5b2fff12015-08-20 14:13:46 +080049import org.onosproject.net.behaviour.BridgeName;
50import org.onosproject.net.behaviour.DefaultTunnelDescription;
51import org.onosproject.net.behaviour.IpTunnelEndPoint;
52import org.onosproject.net.behaviour.TunnelConfig;
53import org.onosproject.net.behaviour.TunnelDescription;
54import org.onosproject.net.behaviour.TunnelEndPoint;
55import org.onosproject.net.device.DeviceEvent;
56import org.onosproject.net.device.DeviceListener;
57import org.onosproject.net.device.DeviceService;
58import org.onosproject.net.driver.DriverHandler;
59import org.onosproject.net.driver.DriverService;
60import org.onosproject.net.flow.DefaultTrafficSelector;
61import org.onosproject.net.flow.DefaultTrafficTreatment;
62import org.onosproject.net.flow.FlowRuleService;
63import org.onosproject.net.flow.TrafficSelector;
64import org.onosproject.net.flow.TrafficTreatment;
65import org.onosproject.net.flow.criteria.Criteria;
66import org.onosproject.net.flow.instructions.Instructions;
67import org.onosproject.net.flowobjective.DefaultForwardingObjective;
68import org.onosproject.net.flowobjective.FlowObjectiveService;
69import org.onosproject.net.flowobjective.ForwardingObjective;
70import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
71import org.onosproject.net.flowobjective.Objective;
72import org.onosproject.net.host.HostEvent;
73import org.onosproject.net.host.HostListener;
74import org.onosproject.net.host.HostService;
75import org.onosproject.store.serializers.KryoNamespaces;
76import org.onosproject.store.service.EventuallyConsistentMap;
77import org.onosproject.store.service.StorageService;
78import org.onosproject.store.service.WallClockTimestamp;
79import org.onosproject.vtn.VTNService;
80import org.onosproject.vtnrsc.SegmentationId;
81import org.onosproject.vtnrsc.TenantNetwork;
82import org.onosproject.vtnrsc.VirtualPort;
83import org.onosproject.vtnrsc.VirtualPortId;
84import org.onosproject.vtnrsc.tenantnetwork.TenantNetworkService;
85import org.onosproject.vtnrsc.virtualport.VirtualPortService;
86import org.slf4j.Logger;
87
88import com.google.common.collect.Sets;
89
90/**
91 * Provides implementation of VTNService.
92 */
93@Component(immediate = true)
94@Service
95public class VTNManager implements VTNService {
96 private final Logger log = getLogger(getClass());
97
98 private static final String APP_ID = "org.onosproject.app.vtn";
99 private ScheduledExecutorService backgroundService;
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected DeviceService deviceService;
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected HostService hostService;
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected FlowRuleService flowRuleService;
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected CoreService coreService;
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected StorageService storageService;
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected TenantNetworkService tenantNetworkService;
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected VirtualPortService virtualPortService;
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected DriverService driverService;
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected FlowObjectiveService flowObjectiveService;
118 private EventuallyConsistentMap<HostId, SegmentationId> binding;
119 private ApplicationId appId;
120 private HostListener hostListener = new InnerHostListener();
121 private DeviceListener deviceListener = new InnerDeviceListener();
122 private static final String IFACEID = "ifaceid";
123 private static final String PORT_HEAD = "vxlan";
124 private static final String DEFAULT_BRIDGE_NAME = "br-int";
125 private static final String CONTROLLER_IP_KEY = "ipaddress";
CNlucius40003022015-08-21 14:45:26 +0800126 private static final int DEFAULT_MAC_PRIORITY = 0x0000;
127 private static final int MAC_PRIORITY = 0xffff;
128 private static final int DEFAULT_PORT_PRIORITY = 0x0000;
129 private static final int PORT_PRIORITY = 0xffff;
130 private static final String SWITCH_CHANNEL_ID = "channelId";
CNlucius5b2fff12015-08-20 14:13:46 +0800131
132 @Activate
133 public void activate() {
134 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
135 .register(KryoNamespaces.API);
136 appId = coreService.registerApplication(APP_ID);
137 deviceService.addListener(deviceListener);
138 hostService.addListener(hostListener);
139 backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos-apps/vtn",
140 "manager-background"));
141 binding = storageService
142 .<HostId, SegmentationId>eventuallyConsistentMapBuilder()
143 .withName("all_tunnel").withSerializer(serializer)
144 .withTimestampProvider((k, v) -> new WallClockTimestamp())
145 .build();
146 log.info("Started");
147 }
148
149 @Deactivate
150 public void deactivate() {
151 backgroundService.shutdown();
152 binding.destroy();
153 log.info("Stopped");
154 }
155
156 @Override
157 public void onServerDetected(Device device) {
158 Iterable<Device> devices = deviceService.getAvailableDevices();
159 DriverHandler handler = driverService.createHandler(device.id());
160 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
161 bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME));
162 String ipAddress = device.annotations().value(CONTROLLER_IP_KEY);
163 IpAddress ip = IpAddress.valueOf(ipAddress);
CNlucius40003022015-08-21 14:45:26 +0800164 Sets.newHashSet(devices).stream()
165 .filter(d -> Device.Type.CONTROLLER == d.type())
166 .filter(d -> !device.id().equals(d.id())).forEach(d -> {
167 if (!device.id().equals(d.id())
168 && Device.Type.CONTROLLER == d.type()) {
169 String ipAddress1 = d.annotations()
170 .value(CONTROLLER_IP_KEY);
171 IpAddress ip1 = IpAddress.valueOf(ipAddress1);
172 applyTunnelConfig(ip, ip1, handler);
173 DriverHandler handler1 = driverService
174 .createHandler(d.id());
175 applyTunnelConfig(ip1, ip, handler1);
176 }
177 });
CNlucius5b2fff12015-08-20 14:13:46 +0800178 }
179
180 @Override
181 public void onServerVanished(Device device) {
182 Iterable<Device> devices = deviceService.getAvailableDevices();
183 String ipAddress = device.annotations().value(CONTROLLER_IP_KEY);
184 IpAddress dst = IpAddress.valueOf(ipAddress);
CNlucius40003022015-08-21 14:45:26 +0800185 Sets.newHashSet(devices).stream()
CNlucius5b2fff12015-08-20 14:13:46 +0800186 .filter(d -> d.type() == Device.Type.CONTROLLER)
CNlucius40003022015-08-21 14:45:26 +0800187 .filter(d -> !device.id().equals(d.id())).forEach(d -> {
188 String ipAddress1 = d.annotations()
189 .value(CONTROLLER_IP_KEY);
190 DriverHandler handler = driverService.createHandler(d.id());
191 IpAddress src = IpAddress.valueOf(ipAddress1);
192 removeTunnelConfig(src, dst, handler);
193 });
CNlucius5b2fff12015-08-20 14:13:46 +0800194 }
195
196 private void applyTunnelConfig(IpAddress src, IpAddress dst,
197 DriverHandler handler) {
198 TunnelEndPoint tunnelAsSrc = IpTunnelEndPoint.ipTunnelPoint(src);
199 TunnelEndPoint tunnelAsDst = IpTunnelEndPoint.ipTunnelPoint(dst);
200 TunnelDescription tunnel = new DefaultTunnelDescription(
201 tunnelAsSrc,
202 tunnelAsDst,
203 TunnelDescription.Type.VXLAN,
204 null);
205 TunnelConfig config = handler.behaviour(TunnelConfig.class);
206 config.createTunnel(tunnel);
207 }
208
209 private void removeTunnelConfig(IpAddress src, IpAddress dst,
210 DriverHandler handler) {
211 TunnelEndPoint tunnelAsSrc = IpTunnelEndPoint.ipTunnelPoint(src);
212 TunnelEndPoint tunnelAsDst = IpTunnelEndPoint.ipTunnelPoint(dst);
213 TunnelDescription tunnel = new DefaultTunnelDescription(
214 tunnelAsSrc,
215 tunnelAsDst,
216 TunnelDescription.Type.VXLAN,
217 null);
218 TunnelConfig config = handler.behaviour(TunnelConfig.class);
219 config.removeTunnel(tunnel);
220 }
221
222 @Override
223 public void onOvsDetected(Device device) {
224 programMacDefaultRules(device.id(), appId, Objective.Operation.ADD);
225 programPortDefaultRules(device.id(), appId, Objective.Operation.ADD);
CNlucius40003022015-08-21 14:45:26 +0800226 Set<Host> hosts = hostService.getConnectedHosts(device.id());
227 hosts.forEach(h -> {
228 String ifaceId = h.annotations().value(IFACEID);
229 String currentControllerIp = getControllerIpOfSwitch(device.id());
230 VirtualPortId portId = VirtualPortId.portId(ifaceId);
231 VirtualPort port = virtualPortService.getPort(portId);
232 TenantNetwork network = tenantNetworkService
233 .getNetwork(port.networkId());
234 String vxlanName = "vxlan-" + currentControllerIp;
235
236 DriverHandler handler = driverService.createHandler(device.id());
237 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
238 Collection<BridgeDescription> bridgeDescriptions = bridgeConfig
239 .getBridges();
240 Iterator<BridgeDescription> it = bridgeDescriptions.iterator();
241 if (it.hasNext()) {
242 BridgeDescription sw = it.next();
243 Set<PortNumber> ports = bridgeConfig.getPortNumbers();
244 ports.stream().filter(p -> p.name().equalsIgnoreCase(vxlanName))
245 .forEach(p -> {
246 programTunnelOut(sw.deviceId(), network.segmentationId(), p,
247 h.mac(), appId, Objective.Operation.ADD);
248 });
249 }
250
251 });
CNlucius5b2fff12015-08-20 14:13:46 +0800252 }
253
254 @Override
255 public void onOvsVanished(Device device) {
256 programMacDefaultRules(device.id(), appId, Objective.Operation.REMOVE);
257 programPortDefaultRules(device.id(), appId, Objective.Operation.REMOVE);
258 }
259
260 @Override
261 public void onHostDetected(Host host) {
262 String ifaceId = host.annotations().value(IFACEID);
CNlucius40003022015-08-21 14:45:26 +0800263 DeviceId deviceId = host.location().deviceId();
264 String currentControllerIp = getControllerIpOfSwitch(deviceId);
265 Iterable<Device> devices = deviceService.getAvailableDevices();
CNlucius5b2fff12015-08-20 14:13:46 +0800266 VirtualPortId portId = VirtualPortId.portId(ifaceId);
267 VirtualPort port = virtualPortService.getPort(portId);
CNlucius40003022015-08-21 14:45:26 +0800268 TenantNetwork network = tenantNetworkService
269 .getNetwork(port.networkId());
270 String tunnelName = "vxlan-" + currentControllerIp;
CNlucius5b2fff12015-08-20 14:13:46 +0800271 binding.put(host.id(), network.segmentationId());
CNlucius5b2fff12015-08-20 14:13:46 +0800272 List<Port> allPorts = deviceService.getPorts(deviceId);
273 PortNumber inPort = host.location().port();
274 Set<Port> localPorts = new HashSet<>();
CNlucius40003022015-08-21 14:45:26 +0800275 Set<Port> tunnelPorts = new HashSet<>();
276 List<Port> outports = new ArrayList<>();
277 Sets.newHashSet(allPorts.iterator()).stream()
278 .filter(p -> !p.number().equals(PortNumber.LOCAL)).forEach(p -> {
279 if (!p.annotations().value("portName").startsWith(PORT_HEAD)) {
CNlucius5b2fff12015-08-20 14:13:46 +0800280 localPorts.add(p);
CNlucius40003022015-08-21 14:45:26 +0800281 } else {
282 tunnelPorts.add(p);
CNlucius5b2fff12015-08-20 14:13:46 +0800283 }
CNlucius40003022015-08-21 14:45:26 +0800284 outports.add(p);
CNlucius5b2fff12015-08-20 14:13:46 +0800285 });
CNlucius40003022015-08-21 14:45:26 +0800286
CNlucius5b2fff12015-08-20 14:13:46 +0800287 programLocalBcastRules(deviceId, network.segmentationId(), inPort,
CNlucius40003022015-08-21 14:45:26 +0800288 outports, appId, Objective.Operation.ADD);
CNlucius5b2fff12015-08-20 14:13:46 +0800289 programLocalOut(deviceId, network.segmentationId(), inPort, host.mac(),
290 appId, Objective.Operation.ADD);
CNlucius40003022015-08-21 14:45:26 +0800291 tunnelPorts
292 .forEach(tp -> programTunnelFloodOut(deviceId,
293 network.segmentationId(),
294 tp.number(), localPorts,
295 appId,
296 Objective.Operation.ADD));
297 Sets.newHashSet(devices).stream()
298 .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {
299 DriverHandler handler = driverService.createHandler(d.id());
300 BridgeConfig bridgeConfig = handler
301 .behaviour(BridgeConfig.class);
302 Collection<BridgeDescription> bridgeDescriptions = bridgeConfig
303 .getBridges();
304
305 Iterator<BridgeDescription> it = bridgeDescriptions
306 .iterator();
307 if (it.hasNext()) {
308 BridgeDescription sw = it.next();
309 Set<PortNumber> ports = bridgeConfig.getPortNumbers();
310 ports.stream()
311 .filter(p -> p.name()
312 .equalsIgnoreCase(tunnelName))
313 .forEach(p -> {
314 programTunnelOut(sw.deviceId(),
315 network.segmentationId(), p,
316 host.mac(), appId,
317 Objective.Operation.ADD);
318 });
319 }
320 });
CNlucius5b2fff12015-08-20 14:13:46 +0800321 programLocalIn(deviceId, network.segmentationId(), inPort, host.mac(),
322 appId, Objective.Operation.ADD);
CNlucius40003022015-08-21 14:45:26 +0800323 tunnelPorts
324 .forEach(tp -> programTunnelIn(deviceId,
325 network.segmentationId(),
326 tp.number(), inPort, host.mac(),
327 appId, Objective.Operation.ADD));
328
CNlucius5b2fff12015-08-20 14:13:46 +0800329 }
330
331 @Override
332 public void onHostVanished(Host host) {
333 SegmentationId segId = binding.remove(host.id());
334 DeviceId deviceId = host.location().deviceId();
CNlucius40003022015-08-21 14:45:26 +0800335 String currentControllerIp = getControllerIpOfSwitch(deviceId);
336 Iterable<Device> devices = deviceService.getAvailableDevices();
CNlucius5b2fff12015-08-20 14:13:46 +0800337 List<Port> allPorts = deviceService.getPorts(deviceId);
338 PortNumber inPort = host.location().port();
CNlucius40003022015-08-21 14:45:26 +0800339 String vxlanName = "vxlan-" + currentControllerIp;
CNlucius5b2fff12015-08-20 14:13:46 +0800340 Set<Port> localPorts = new HashSet<>();
CNlucius40003022015-08-21 14:45:26 +0800341 Set<Port> tunnelPorts = new HashSet<>();
342 List<Port> outports = new ArrayList<>();
343 Sets.newHashSet(allPorts.iterator()).stream()
344 .filter(p -> !p.number().equals(PortNumber.LOCAL)).forEach(p -> {
345 if (!p.annotations().value("portName").startsWith(PORT_HEAD)) {
CNlucius5b2fff12015-08-20 14:13:46 +0800346 localPorts.add(p);
CNlucius40003022015-08-21 14:45:26 +0800347 } else {
348 tunnelPorts.add(p);
CNlucius5b2fff12015-08-20 14:13:46 +0800349 }
CNlucius40003022015-08-21 14:45:26 +0800350 outports.add(p);
CNlucius5b2fff12015-08-20 14:13:46 +0800351 });
CNlucius40003022015-08-21 14:45:26 +0800352
353 programLocalBcastRules(deviceId, segId, inPort,
354 outports, appId, Objective.Operation.REMOVE);
355 programLocalOut(deviceId, segId, inPort, host.mac(),
356 appId, Objective.Operation.REMOVE);
357 tunnelPorts
358 .forEach(tp -> programTunnelFloodOut(deviceId,
359 segId,
360 tp.number(), localPorts,
361 appId,
362 Objective.Operation.REMOVE));
363 Sets.newHashSet(devices).stream()
364 .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {
365 DriverHandler handler = driverService.createHandler(d.id());
366 BridgeConfig bridgeConfig = handler
367 .behaviour(BridgeConfig.class);
368 Collection<BridgeDescription> bridgeDescriptions = bridgeConfig
369 .getBridges();
370
371 Iterator<BridgeDescription> it = bridgeDescriptions
372 .iterator();
373 if (it.hasNext()) {
374 BridgeDescription sw = it.next();
375 Set<PortNumber> ports = bridgeConfig.getPortNumbers();
376 ports.stream()
377 .filter(p -> p.name()
378 .equalsIgnoreCase(vxlanName))
379 .forEach(p -> {
380 programTunnelOut(sw.deviceId(),
381 segId, p,
382 host.mac(), appId,
383 Objective.Operation.REMOVE);
384 });
385 }
386 });
387 programLocalIn(deviceId, segId, inPort, host.mac(),
388 appId, Objective.Operation.REMOVE);
389 tunnelPorts
390 .forEach(tp -> programTunnelIn(deviceId,
391 segId,
392 tp.number(), inPort, host.mac(),
393 appId, Objective.Operation.REMOVE));
CNlucius5b2fff12015-08-20 14:13:46 +0800394 }
395
396 private class InnerDeviceListener implements DeviceListener {
397
398 @Override
399 public void event(DeviceEvent event) {
400 Device device = event.subject();
401 if (Device.Type.CONTROLLER == device.type()
402 && DeviceEvent.Type.DEVICE_ADDED == event.type()) {
403 backgroundService.execute(() -> {
404 onServerDetected(device);
405 });
406 } else if (Device.Type.CONTROLLER == device.type()
407 && DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED == event
408 .type()) {
409 backgroundService.execute(() -> {
410 onServerVanished(device);
411 });
412 } else if (Device.Type.SWITCH == device.type()
413 && DeviceEvent.Type.DEVICE_ADDED == event.type()) {
414 backgroundService.execute(() -> {
415 onOvsDetected(device);
416 });
417 } else if (Device.Type.SWITCH == device.type()
418 && DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED == event
419 .type()) {
420 backgroundService.execute(() -> {
421 onOvsVanished(device);
422 });
423 } else {
CNlucius40003022015-08-21 14:45:26 +0800424 log.info("Do nothing for this device type");
CNlucius5b2fff12015-08-20 14:13:46 +0800425 }
426 }
427
428 }
429
430 private class InnerHostListener implements HostListener {
431
432 @Override
433 public void event(HostEvent event) {
434 Host host = event.subject();
435 if (HostEvent.Type.HOST_ADDED == event.type()) {
436 backgroundService.execute(() -> {
437 onHostDetected(host);
438 });
439 } else if (HostEvent.Type.HOST_REMOVED == event.type()) {
440 backgroundService.execute(() -> {
441 onHostVanished(host);
442 });
CNlucius40003022015-08-21 14:45:26 +0800443 } else if (HostEvent.Type.HOST_UPDATED == event.type()) {
444 backgroundService.execute(() -> {
445 onHostVanished(host);
446 onHostDetected(host);
447 });
CNlucius5b2fff12015-08-20 14:13:46 +0800448 }
449 }
450
451 }
452
453 // Used to forward the flows to the local VM.
454 private void programLocalOut(DeviceId dpid, SegmentationId segmentationId,
455 PortNumber outPort, MacAddress sourceMac,
CNlucius40003022015-08-21 14:45:26 +0800456 ApplicationId appid,
457 Objective.Operation type) {
CNlucius5b2fff12015-08-20 14:13:46 +0800458 TrafficSelector selector = DefaultTrafficSelector.builder()
459 .matchEthDst(sourceMac).build();
CNlucius40003022015-08-21 14:45:26 +0800460 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
461 .add(Instructions
462 .modTunnelId(Long.parseLong(segmentationId.toString())))
463 .setOutput(outPort).build();
CNlucius5b2fff12015-08-20 14:13:46 +0800464 ForwardingObjective.Builder objective = DefaultForwardingObjective
465 .builder().withTreatment(treatment).withSelector(selector)
CNlucius40003022015-08-21 14:45:26 +0800466 .fromApp(appId).withFlag(Flag.SPECIFIC)
467 .withPriority(MAC_PRIORITY);
CNlucius5b2fff12015-08-20 14:13:46 +0800468 if (type.equals(Objective.Operation.ADD)) {
469 flowObjectiveService.forward(dpid, objective.add());
470 } else {
471 flowObjectiveService.forward(dpid, objective.remove());
472 }
473
474 }
475
CNlucius40003022015-08-21 14:45:26 +0800476 // Used to forward the flows into the VXLAN tunnel.
CNlucius5b2fff12015-08-20 14:13:46 +0800477 private void programTunnelOut(DeviceId dpid, SegmentationId segmentationId,
CNlucius40003022015-08-21 14:45:26 +0800478 PortNumber tunnelOutPort, MacAddress dstMac,
479 ApplicationId appid,
480 Objective.Operation type) {
CNlucius5b2fff12015-08-20 14:13:46 +0800481 TrafficSelector selector = DefaultTrafficSelector.builder()
CNlucius40003022015-08-21 14:45:26 +0800482 .matchEthDst(dstMac).add(Criteria.matchTunnelId(Long
483 .parseLong(segmentationId.toString())))
484 .build();
485 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
486
487 .setOutput(tunnelOutPort).build();
CNlucius5b2fff12015-08-20 14:13:46 +0800488 ForwardingObjective.Builder objective = DefaultForwardingObjective
489 .builder().withTreatment(treatment).withSelector(selector)
CNlucius40003022015-08-21 14:45:26 +0800490 .fromApp(appId).withFlag(Flag.SPECIFIC)
491 .withPriority(MAC_PRIORITY);
CNlucius5b2fff12015-08-20 14:13:46 +0800492 if (type.equals(Objective.Operation.ADD)) {
493 flowObjectiveService.forward(dpid, objective.add());
494 } else {
495 flowObjectiveService.forward(dpid, objective.remove());
496 }
CNlucius40003022015-08-21 14:45:26 +0800497
CNlucius5b2fff12015-08-20 14:13:46 +0800498 }
499
500 // Used to forward multicast flows to remote VMs of the same tenant via
501 // VXLAN tunnel.
502 private void programTunnelFloodOut(DeviceId dpid,
503 SegmentationId segmentationId,
504 PortNumber ofPortOut,
505 Iterable<Port> localports,
506 ApplicationId appid,
507 Objective.Operation type) {
CNlucius40003022015-08-21 14:45:26 +0800508 TrafficSelector selector = DefaultTrafficSelector.builder()
CNlucius5b2fff12015-08-20 14:13:46 +0800509 .matchInPort(ofPortOut)
510
511 .add(Criteria.matchTunnelId(Long.parseLong(segmentationId
512 .toString()))).matchEthDst(MacAddress.BROADCAST)
513 .build();
514 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
515 for (Port outport : localports) {
516 treatment.setOutput(outport.number());
517 }
518
519 ForwardingObjective.Builder objective = DefaultForwardingObjective
520 .builder().withTreatment(treatment.build())
521 .withSelector(selector).fromApp(appId).makePermanent()
CNlucius40003022015-08-21 14:45:26 +0800522 .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);
CNlucius5b2fff12015-08-20 14:13:46 +0800523 if (type.equals(Objective.Operation.ADD)) {
524 flowObjectiveService.forward(dpid, objective.add());
525 } else {
526 flowObjectiveService.forward(dpid, objective.remove());
527 }
528 }
529
530 // Applies default flows to mac table.
531 private void programMacDefaultRules(DeviceId dpid, ApplicationId appid,
532 Objective.Operation type) {
533 TrafficSelector selector = DefaultTrafficSelector.builder().build();
534 TrafficTreatment treatment = DefaultTrafficTreatment.builder().drop()
535 .build();
536 ForwardingObjective.Builder objective = DefaultForwardingObjective
537 .builder().withTreatment(treatment).withSelector(selector)
CNlucius40003022015-08-21 14:45:26 +0800538 .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
539 .withPriority(DEFAULT_MAC_PRIORITY);
CNlucius5b2fff12015-08-20 14:13:46 +0800540 if (type.equals(Objective.Operation.ADD)) {
541 flowObjectiveService.forward(dpid, objective.add());
542 } else {
543 flowObjectiveService.forward(dpid, objective.remove());
544 }
545 }
546
547 // Used to forward the flows to the local VMs with the same tenant.
548 private void programLocalBcastRules(DeviceId dpid,
549 SegmentationId segmentationId,
550 PortNumber inPort, List<Port> allports,
551 ApplicationId appid,
552 Objective.Operation type) {
CNlucius40003022015-08-21 14:45:26 +0800553 TrafficSelector selector = DefaultTrafficSelector.builder()
554 .matchInPort(inPort).matchEthDst(MacAddress.BROADCAST)
555 .add(Criteria.matchTunnelId(Long
556 .parseLong(segmentationId.toString())))
557 .build();
CNlucius5b2fff12015-08-20 14:13:46 +0800558 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
559
560 for (Port outport : allports) {
561 if (inPort != outport.number()) {
562 treatment.setOutput(outport.number());
563 }
564 }
565 ForwardingObjective.Builder objective = DefaultForwardingObjective
566 .builder().withTreatment(treatment.build())
567 .withSelector(selector).fromApp(appId).makePermanent()
CNlucius40003022015-08-21 14:45:26 +0800568 .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);
CNlucius5b2fff12015-08-20 14:13:46 +0800569 if (type.equals(Objective.Operation.ADD)) {
570 flowObjectiveService.forward(dpid, objective.add());
571 } else {
572 flowObjectiveService.forward(dpid, objective.remove());
573 }
574 }
575
576 // Used to apply local entry flow.
577 private void programLocalIn(DeviceId dpid, SegmentationId segmentationId,
578 PortNumber inPort, MacAddress srcMac,
579 ApplicationId appid, Objective.Operation type) {
580 TrafficSelector selector = DefaultTrafficSelector.builder()
581 .matchInPort(inPort).matchEthSrc(srcMac).build();
582 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
583 treatment.add(Instructions.modTunnelId(Long.parseLong(segmentationId
584 .toString())));
585 ForwardingObjective.Builder objective = DefaultForwardingObjective
586 .builder().withTreatment(treatment.build())
587 .withSelector(selector).fromApp(appId).makePermanent()
CNlucius40003022015-08-21 14:45:26 +0800588 .withFlag(Flag.SPECIFIC).withPriority(PORT_PRIORITY);
CNlucius5b2fff12015-08-20 14:13:46 +0800589 if (type.equals(Objective.Operation.ADD)) {
590 flowObjectiveService.forward(dpid, objective.add());
591 } else {
592 flowObjectiveService.forward(dpid, objective.remove());
593 }
594 }
595
596 // Used to forward the flows from the egress tunnel to the VM.
597 private void programTunnelIn(DeviceId dpid, SegmentationId segmentationId,
CNlucius40003022015-08-21 14:45:26 +0800598 PortNumber tunnelInPort, PortNumber outPort,
599 MacAddress sourceMac, ApplicationId appid,
600 Objective.Operation type) {
601 TrafficSelector selector = DefaultTrafficSelector.builder()
602 .matchInPort(tunnelInPort).add(Criteria.matchTunnelId(Long
603 .parseLong(segmentationId.toString())))
604 .build();
CNlucius5b2fff12015-08-20 14:13:46 +0800605 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
606
607 ForwardingObjective.Builder objective = DefaultForwardingObjective
608 .builder().withTreatment(treatment).withSelector(selector)
CNlucius40003022015-08-21 14:45:26 +0800609 .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
610 .withPriority(PORT_PRIORITY);
CNlucius5b2fff12015-08-20 14:13:46 +0800611 if (type.equals(Objective.Operation.ADD)) {
612 flowObjectiveService.forward(dpid, objective.add());
613 } else {
614 flowObjectiveService.forward(dpid, objective.remove());
615 }
616 }
617
618 // Applies the default flows to port table.
619 private void programPortDefaultRules(DeviceId dpid, ApplicationId appid,
620 Objective.Operation type) {
621 TrafficSelector selector = DefaultTrafficSelector.builder().build();
622 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
623 ForwardingObjective.Builder objective = DefaultForwardingObjective
624 .builder().withTreatment(treatment).withSelector(selector)
CNlucius40003022015-08-21 14:45:26 +0800625 .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
626 .withPriority(DEFAULT_PORT_PRIORITY);
CNlucius5b2fff12015-08-20 14:13:46 +0800627 if (type.equals(Objective.Operation.ADD)) {
628 flowObjectiveService.forward(dpid, objective.add());
629 } else {
630 flowObjectiveService.forward(dpid, objective.remove());
631 }
632 }
CNlucius40003022015-08-21 14:45:26 +0800633
634 // Used to get channelId from the device annotations.
635 private String getControllerIpOfSwitch(DeviceId deviceId) {
636 Device device = deviceService.getDevice(deviceId);
637 String url = device.annotations().value(SWITCH_CHANNEL_ID);
638 return url.substring(0, url.lastIndexOf(":"));
639 }
640
CNlucius5b2fff12015-08-20 14:13:46 +0800641}