Daniel Park
Committed by Gerrit Code Review

[ONOS-3696] Remove flow rules when a VM is terminated

- ProcessPortAdded method name is changed to ProcessPortUpdated
- PortNumber is removed in OpenstackPortInfo class
- Checks doNotPushFlows in OpenstackSwitchingRulePopulator
- etc
- rebased

Change-Id: I215892102669799af0fd8c8ac8ea377ab7be2aad
1 +/*
2 + * Copyright 2014-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 + */
16 +package org.onosproject.openstackswitching;
17 +
18 +import org.onlab.packet.Ip4Address;
19 +import org.onosproject.net.DeviceId;
20 +
21 +import static com.google.common.base.Preconditions.checkNotNull;
22 +
23 +/**
24 + * Contains OpenstackPort Information.
25 + */
26 +public final class OpenstackPortInfo {
27 +
28 + private final Ip4Address hostIp;
29 + private final DeviceId deviceId;
30 + private final long vni;
31 +
32 + public OpenstackPortInfo(Ip4Address hostIp, DeviceId deviceId,
33 + long vni) {
34 + this.hostIp = hostIp;
35 + this.deviceId = deviceId;
36 + this.vni = vni;
37 + }
38 +
39 + public Ip4Address ip() {
40 + return hostIp;
41 + }
42 +
43 + public DeviceId deviceId() {
44 + return deviceId;
45 + }
46 +
47 + public long vni() {
48 + return vni;
49 + }
50 +
51 + public static OpenstackPortInfo.Builder builder() {
52 + return new Builder();
53 + }
54 +
55 + public static final class Builder {
56 + private Ip4Address hostIp;
57 + private DeviceId deviceId;
58 + private long vni;
59 +
60 + public Builder setHostIp(Ip4Address hostIp) {
61 + this.hostIp = checkNotNull(hostIp, "hostIp cannot be null");
62 + return this;
63 + }
64 +
65 + public Builder setDeviceId(DeviceId deviceId) {
66 + this.deviceId = checkNotNull(deviceId, "deviceId cannot be null");
67 + return this;
68 + }
69 +
70 + public Builder setVNI(long vni) {
71 + this.vni = checkNotNull(vni, "vni cannot be null");
72 + return this;
73 + }
74 + public OpenstackPortInfo build() {
75 + return new OpenstackPortInfo(this);
76 + }
77 + }
78 +
79 + private OpenstackPortInfo(Builder builder) {
80 + hostIp = builder.hostIp;
81 + deviceId = builder.deviceId;
82 + vni = builder.vni;
83 + }
84 +}
...@@ -17,6 +17,7 @@ package org.onosproject.openstackswitching; ...@@ -17,6 +17,7 @@ package org.onosproject.openstackswitching;
17 17
18 import com.google.common.collect.ImmutableSet; 18 import com.google.common.collect.ImmutableSet;
19 import com.google.common.collect.Lists; 19 import com.google.common.collect.Lists;
20 +import com.google.common.collect.Maps;
20 import org.apache.felix.scr.annotations.Activate; 21 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 22 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 23 import org.apache.felix.scr.annotations.Deactivate;
...@@ -25,13 +26,11 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; ...@@ -25,13 +26,11 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.apache.felix.scr.annotations.Service; 26 import org.apache.felix.scr.annotations.Service;
26 import org.onlab.packet.Ethernet; 27 import org.onlab.packet.Ethernet;
27 import org.onlab.packet.Ip4Address; 28 import org.onlab.packet.Ip4Address;
28 -import org.onlab.packet.IpAddress;
29 import org.onosproject.core.ApplicationId; 29 import org.onosproject.core.ApplicationId;
30 import org.onosproject.core.CoreService; 30 import org.onosproject.core.CoreService;
31 import org.onosproject.dhcp.DhcpService; 31 import org.onosproject.dhcp.DhcpService;
32 import org.onosproject.event.AbstractEvent; 32 import org.onosproject.event.AbstractEvent;
33 import org.onosproject.net.Device; 33 import org.onosproject.net.Device;
34 -import org.onosproject.net.DeviceId;
35 import org.onosproject.net.Host; 34 import org.onosproject.net.Host;
36 import org.onosproject.net.Port; 35 import org.onosproject.net.Port;
37 import org.onosproject.net.config.ConfigFactory; 36 import org.onosproject.net.config.ConfigFactory;
...@@ -42,12 +41,6 @@ import org.onosproject.net.device.DeviceEvent; ...@@ -42,12 +41,6 @@ import org.onosproject.net.device.DeviceEvent;
42 import org.onosproject.net.device.DeviceListener; 41 import org.onosproject.net.device.DeviceListener;
43 import org.onosproject.net.device.DeviceService; 42 import org.onosproject.net.device.DeviceService;
44 import org.onosproject.net.driver.DriverService; 43 import org.onosproject.net.driver.DriverService;
45 -import org.onosproject.net.flow.FlowEntry;
46 -import org.onosproject.net.flow.FlowRuleService;
47 -import org.onosproject.net.flow.criteria.Criterion;
48 -import org.onosproject.net.flow.criteria.IPCriterion;
49 -import org.onosproject.net.flow.instructions.Instruction;
50 -import org.onosproject.net.flow.instructions.L2ModificationInstruction;
51 import org.onosproject.net.flowobjective.FlowObjectiveService; 44 import org.onosproject.net.flowobjective.FlowObjectiveService;
52 import org.onosproject.net.host.HostEvent; 45 import org.onosproject.net.host.HostEvent;
53 import org.onosproject.net.host.HostListener; 46 import org.onosproject.net.host.HostListener;
...@@ -60,6 +53,7 @@ import org.slf4j.Logger; ...@@ -60,6 +53,7 @@ import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory; 53 import org.slf4j.LoggerFactory;
61 import java.util.List; 54 import java.util.List;
62 import java.util.Collection; 55 import java.util.Collection;
56 +import java.util.Map;
63 import java.util.NoSuchElementException; 57 import java.util.NoSuchElementException;
64 import java.util.Set; 58 import java.util.Set;
65 import java.util.concurrent.ExecutorService; 59 import java.util.concurrent.ExecutorService;
...@@ -104,9 +98,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -104,9 +98,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected DriverService driverService; 99 protected DriverService driverService;
106 100
107 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 - protected FlowRuleService flowRuleService;
109 -
110 private ApplicationId appId; 101 private ApplicationId appId;
111 private boolean doNotPushFlows; 102 private boolean doNotPushFlows;
112 private Ip4Address neutronServer; 103 private Ip4Address neutronServer;
...@@ -136,6 +127,9 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -136,6 +127,9 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
136 } 127 }
137 ); 128 );
138 129
130 +
131 + private Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
132 +
139 @Activate 133 @Activate
140 protected void activate() { 134 protected void activate() {
141 appId = coreService 135 appId = coreService
...@@ -258,13 +252,39 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -258,13 +252,39 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
258 log.debug("device {} is added", device.id()); 252 log.debug("device {} is added", device.id());
259 } 253 }
260 254
261 - private void processPortAdded(Device device, Port port) { 255 + private void processPortUpdated(Device device, Port port) {
262 - if (!port.annotations().value("portName").equals("vxlan") 256 + if (!port.annotations().value("portName").equals("vxlan") && !doNotPushFlows) {
263 - && port.isEnabled() && !doNotPushFlows) { 257 + if (port.isEnabled()) {
264 OpenstackSwitchingRulePopulator rulePopulator = 258 OpenstackSwitchingRulePopulator rulePopulator =
265 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService, 259 new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
266 deviceService, restHandler, driverService); 260 deviceService, restHandler, driverService);
267 rulePopulator.populateSwitchingRules(device, port); 261 rulePopulator.populateSwitchingRules(device, port);
262 +
263 + OpenstackPort openstackPort = port(port);
264 +
265 + long vni = Long.parseLong(restHandler.getNetworks().stream()
266 + .filter(n -> n.id().equals(openstackPort.networkId()))
267 + .findAny().orElse(null).segmentId());
268 +
269 + OpenstackPortInfo.Builder portBuilder = OpenstackPortInfo.builder()
270 + .setDeviceId(device.id())
271 + .setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
272 + .setVNI(vni);
273 +
274 + openstackPortInfoMap.putIfAbsent(port.annotations().value("portName"),
275 + portBuilder.build());
276 + }
277 +
278 + //In case portupdate event is driven by vm shutoff from openstack
279 + if (!port.isEnabled() && openstackPortInfoMap.containsKey(port.annotations().value("portName"))) {
280 + log.debug("Flowrules according to the port {} were removed", port.number().toString());
281 + OpenstackSwitchingRulePopulator rulePopulator =
282 + new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
283 + deviceService, restHandler, driverService);
284 + openstackPortInfoMap.get(port.annotations().value("portName"));
285 + rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
286 + openstackPortInfoMap.remove(port.annotations().value("portName"));
287 + }
268 } 288 }
269 } 289 }
270 290
...@@ -300,46 +320,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -300,46 +320,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
300 320
301 private void processHostRemoved(Host host) { 321 private void processHostRemoved(Host host) {
302 log.debug("host {} was removed", host.toString()); 322 log.debug("host {} was removed", host.toString());
303 -
304 - try {
305 - if (!doNotPushFlows) {
306 - IpAddress hostIp = host.ipAddresses().stream().
307 - filter(ip -> ip.isIp4()).findAny().orElse(null);
308 - OpenstackSwitchingRulePopulator rulePopulator =
309 - new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
310 - deviceService, restHandler, driverService);
311 - rulePopulator.removeSwitchingRules(host.location().deviceId(),
312 - hostIp.getIp4Address());
313 - }
314 -
315 - dhcpService.removeStaticMapping(host.mac());
316 - } catch (NoSuchElementException e) {
317 - log.error("No IP address is assigned.");
318 - }
319 - }
320 -
321 - private long getVniFromFlowRules(DeviceId deviceId, Ip4Address hostIp) {
322 -
323 - for (FlowEntry flowEntry: flowRuleService.getFlowEntries(deviceId)) {
324 - Criterion c = flowEntry.selector().getCriterion(Criterion.Type.IPV4_DST);
325 - if (c != null) {
326 - IPCriterion destIpCriterion = (IPCriterion) c;
327 - if (destIpCriterion.ip().getIp4Prefix().address().equals(hostIp)) {
328 - for (Instruction i : flowEntry.treatment().immediate()) {
329 - if (i.type().equals(Instruction.Type.L2MODIFICATION)) {
330 - L2ModificationInstruction l2m = (L2ModificationInstruction) i;
331 - if (l2m.subtype().equals(L2ModificationInstruction.L2SubType.TUNNEL_ID)) {
332 - L2ModificationInstruction.ModTunnelIdInstruction setTunnelInstr =
333 - (L2ModificationInstruction.ModTunnelIdInstruction) l2m;
334 - return setTunnelInstr.tunnelId();
335 - }
336 - }
337 - }
338 - }
339 - }
340 - }
341 -
342 - return 0;
343 } 323 }
344 324
345 private void registerDhcpInfo(OpenstackPort openstackPort) { 325 private void registerDhcpInfo(OpenstackPort openstackPort) {
...@@ -350,7 +330,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -350,7 +330,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
350 Ip4Address domainServer; 330 Ip4Address domainServer;
351 OpenstackSubnet openstackSubnet; 331 OpenstackSubnet openstackSubnet;
352 332
353 - ip4Address = (Ip4Address) openstackPort.fixedIps().values().toArray()[0]; 333 + ip4Address = (Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null);
354 334
355 openstackSubnet = restHandler.getSubnets().stream() 335 openstackSubnet = restHandler.getSubnets().stream()
356 .filter(n -> n.networkId().equals(openstackPort.networkId())) 336 .filter(n -> n.networkId().equals(openstackPort.networkId()))
...@@ -442,7 +422,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -442,7 +422,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
442 case DEVICE_UPDATED: 422 case DEVICE_UPDATED:
443 Port port = (Port) deviceEvent.subject(); 423 Port port = (Port) deviceEvent.subject();
444 if (port.isEnabled()) { 424 if (port.isEnabled()) {
445 - processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); 425 + processPortUpdated((Device) deviceEvent.subject(), deviceEvent.port());
446 } 426 }
447 break; 427 break;
448 case DEVICE_AVAILABILITY_CHANGED: 428 case DEVICE_AVAILABILITY_CHANGED:
...@@ -452,10 +432,10 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -452,10 +432,10 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
452 } 432 }
453 break; 433 break;
454 case PORT_ADDED: 434 case PORT_ADDED:
455 - processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); 435 + processPortUpdated((Device) deviceEvent.subject(), deviceEvent.port());
456 break; 436 break;
457 case PORT_UPDATED: 437 case PORT_UPDATED:
458 - processPortAdded((Device) deviceEvent.subject(), deviceEvent.port()); 438 + processPortUpdated((Device) deviceEvent.subject(), deviceEvent.port());
459 break; 439 break;
460 case PORT_REMOVED: 440 case PORT_REMOVED:
461 processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port()); 441 processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port());
...@@ -502,19 +482,4 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -502,19 +482,4 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
502 } 482 }
503 483
504 } 484 }
505 -
506 - private final class PortInfo {
507 - DeviceId deviceId;
508 - String portName;
509 - Ip4Address fixedIp;
510 - Ip4Address hostIp;
511 -
512 - private PortInfo(DeviceId deviceId, String portName, Ip4Address fixedIp,
513 - Ip4Address hostIp) {
514 - this.deviceId = deviceId;
515 - this.portName = portName;
516 - this.fixedIp = fixedIp;
517 - this.hostIp = hostIp;
518 - }
519 - }
520 } 485 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -18,7 +18,6 @@ package org.onosproject.openstackswitching; ...@@ -18,7 +18,6 @@ package org.onosproject.openstackswitching;
18 18
19 import org.onlab.packet.Ethernet; 19 import org.onlab.packet.Ethernet;
20 import org.onlab.packet.Ip4Address; 20 import org.onlab.packet.Ip4Address;
21 -import org.onlab.packet.MacAddress;
22 import org.onosproject.core.ApplicationId; 21 import org.onosproject.core.ApplicationId;
23 import org.onosproject.net.Device; 22 import org.onosproject.net.Device;
24 import org.onosproject.net.DeviceId; 23 import org.onosproject.net.DeviceId;
...@@ -45,6 +44,7 @@ import org.slf4j.Logger; ...@@ -45,6 +44,7 @@ import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory; 44 import org.slf4j.LoggerFactory;
46 45
47 import java.util.Collection; 46 import java.util.Collection;
47 +import java.util.Map;
48 48
49 /** 49 /**
50 * Populates switching flow rules. 50 * Populates switching flow rules.
...@@ -118,31 +118,25 @@ public class OpenstackSwitchingRulePopulator { ...@@ -118,31 +118,25 @@ public class OpenstackSwitchingRulePopulator {
118 } 118 }
119 } 119 }
120 120
121 - /** 121 + private void setFlowRuleForTunnelTag(DeviceId deviceId, Port port, String vni) {
122 - * Returns OpenstackPort object for the Port reference given.
123 - *
124 - * @param port Port object
125 - * @return OpenstackPort reference, or null when not found
126 - */
127 - public OpenstackPort openstackPort(Port port) {
128 - String uuid = port.annotations().value("portName").substring(3);
129 - return openstackPortList.stream().filter(p -> p.id().startsWith(uuid))
130 - .findAny().orElse(null);
131 - }
132 122
133 - /** 123 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
134 - * Remove flows rules for the VM removed. 124 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
135 - * 125 +
136 - * @param deviceId device to remove rules 126 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
137 - * @param vmIp IP address of the VM removed 127 + .matchInPort(port.number());
138 - */ 128 +
139 - public void removeSwitchingRules(DeviceId deviceId, Ip4Address vmIp) { 129 + tBuilder.setTunnelId(Long.parseLong(vni));
140 - removeFlowRuleForVMsInSameCnode(deviceId, vmIp); 130 +
141 - deviceService.getAvailableDevices().forEach(device -> { 131 + ForwardingObjective fo = DefaultForwardingObjective.builder()
142 - if (!device.id().equals(deviceId)) { 132 + .withSelector(sBuilder.build())
143 - removeVxLanFlowRule(device.id(), vmIp); 133 + .withTreatment(tBuilder.build())
144 - } 134 + .withPriority(TUNNELTAG_RULE_PRIORITY)
145 - }); 135 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
136 + .fromApp(appId)
137 + .add();
138 +
139 + flowObjectiveService.forward(deviceId, fo);
146 } 140 }
147 141
148 /** 142 /**
...@@ -155,14 +149,45 @@ public class OpenstackSwitchingRulePopulator { ...@@ -155,14 +149,45 @@ public class OpenstackSwitchingRulePopulator {
155 Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName")); 149 Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName"));
156 String portName = port.annotations().value("portName"); 150 String portName = port.annotations().value("portName");
157 String vni = getVniForPort(portName); 151 String vni = getVniForPort(portName);
158 - MacAddress vmMacAddress = getVmMacAddressForPort(portName);
159 152
160 if (vmIp != null) { 153 if (vmIp != null) {
161 - setFlowRuleForVMsInSameCnode(vmIp, device.id(), port, vni, vmMacAddress); 154 + setFlowRuleForVMsInSameCnode(vmIp, device.id(), port, vni);
162 } 155 }
163 } 156 }
164 157
165 /** 158 /**
159 + * Sets the flow rules for traffic between VMs in the same Cnode.
160 + *
161 + * @param ip4Address VM IP address
162 + * @param id device ID to put rules
163 + * @param port VM port
164 + * @param vni VM VNI
165 + */
166 + private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id,
167 + Port port, String vni) {
168 +
169 + //For L2 Switching Case
170 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
171 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
172 +
173 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
174 + .matchIPDst(ip4Address.toIpPrefix())
175 + .matchTunnelId(Long.parseLong(vni));
176 +
177 + tBuilder.setOutput(port.number());
178 +
179 + ForwardingObjective fo = DefaultForwardingObjective.builder()
180 + .withSelector(sBuilder.build())
181 + .withTreatment(tBuilder.build())
182 + .withPriority(SWITCHING_RULE_PRIORITY)
183 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
184 + .fromApp(appId)
185 + .add();
186 +
187 + flowObjectiveService.forward(id, fo);
188 + }
189 +
190 + /**
166 * Populates the flow rules for traffic to VMs in different Cnode using 191 * Populates the flow rules for traffic to VMs in different Cnode using
167 * Nicira extention. 192 * Nicira extention.
168 * 193 *
...@@ -174,7 +199,6 @@ public class OpenstackSwitchingRulePopulator { ...@@ -174,7 +199,6 @@ public class OpenstackSwitchingRulePopulator {
174 String channelId = device.annotations().value("channelId"); 199 String channelId = device.annotations().value("channelId");
175 Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]); 200 Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]);
176 Ip4Address fixedIp = getFixedIpAddressForPort(portName); 201 Ip4Address fixedIp = getFixedIpAddressForPort(portName);
177 - MacAddress vmMac = getVmMacAddressForPort(portName);
178 String vni = getVniForPort(portName); 202 String vni = getVniForPort(portName);
179 deviceService.getAvailableDevices().forEach(d -> { 203 deviceService.getAvailableDevices().forEach(d -> {
180 if (!d.equals(device)) { 204 if (!d.equals(device)) {
...@@ -183,11 +207,10 @@ public class OpenstackSwitchingRulePopulator { ...@@ -183,11 +207,10 @@ public class OpenstackSwitchingRulePopulator {
183 if (!p.equals(port) && vni.equals(getVniForPort(pName))) { 207 if (!p.equals(port) && vni.equals(getVniForPort(pName))) {
184 String cidx = d.annotations().value("channelId"); 208 String cidx = d.annotations().value("channelId");
185 Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]); 209 Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]);
186 - MacAddress vmMacx = getVmMacAddressForPort(pName);
187 Ip4Address fixedIpx = getFixedIpAddressForPort(pName); 210 Ip4Address fixedIpx = getFixedIpAddressForPort(pName);
188 if (port.isEnabled()) { 211 if (port.isEnabled()) {
189 - setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx, vmMacx); 212 + setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx);
190 - setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp, vmMac); 213 + setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp);
191 } 214 }
192 } 215 }
193 }); 216 });
...@@ -196,88 +219,80 @@ public class OpenstackSwitchingRulePopulator { ...@@ -196,88 +219,80 @@ public class OpenstackSwitchingRulePopulator {
196 } 219 }
197 220
198 /** 221 /**
199 - * Returns the VNI of the VM of the port. 222 + * Sets the flow rules between traffic from VMs in different Cnode.
200 * 223 *
201 - * @param portName VM port 224 + * @param vni VNI
202 - * @return VNI 225 + * @param deviceId device ID
226 + * @param hostIp host IP of the VM
227 + * @param vmIp fixed IP of the VM
203 */ 228 */
204 - private String getVniForPort(String portName) { 229 + private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address hostIp,
205 - String uuid = portName.substring(3); 230 + Ip4Address vmIp) {
206 - OpenstackPort port = openstackPortList.stream() 231 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
207 - .filter(p -> p.id().startsWith(uuid)) 232 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
208 - .findAny().orElse(null);
209 - if (port == null) {
210 - log.debug("No port information for port {}", portName);
211 - return null;
212 - }
213 233
214 - OpenstackNetwork network = openstackNetworkList.stream() 234 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
215 - .filter(n -> n.id().equals(port.networkId())) 235 + .matchTunnelId(Long.parseLong(vni))
216 - .findAny().orElse(null); 236 + .matchIPDst(vmIp.toIpPrefix());
217 - if (network == null) { 237 + tBuilder.extension(buildNiciraExtenstion(deviceId, hostIp), deviceId)
218 - log.warn("No VNI information for network {}", port.networkId()); 238 + .setOutput(getTunnelPort(deviceId));
219 - return null;
220 - }
221 239
222 - return network.segmentId(); 240 + ForwardingObjective fo = DefaultForwardingObjective.builder()
241 + .withSelector(sBuilder.build())
242 + .withTreatment(tBuilder.build())
243 + .withPriority(SWITCHING_RULE_PRIORITY)
244 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
245 + .fromApp(appId)
246 + .add();
247 +
248 + flowObjectiveService.forward(deviceId, fo);
223 } 249 }
224 250
225 /** 251 /**
226 - * Returns the Fixed IP address of the VM. 252 + * Returns OpenstackPort object for the Port reference given.
227 * 253 *
228 - * @param portName VM port info 254 + * @param port Port object
229 - * @return IP address of the VM 255 + * @return OpenstackPort reference, or null when not found
230 */ 256 */
231 - private Ip4Address getFixedIpAddressForPort(String portName) { 257 + public OpenstackPort openstackPort(Port port) {
232 - 258 + String uuid = port.annotations().value("portName").substring(3);
233 - String uuid = portName.substring(3); 259 + return openstackPortList.stream().filter(p -> p.id().startsWith(uuid))
234 - OpenstackPort port = openstackPortList.stream() 260 + .findAny().orElse(null);
235 - .filter(p -> p.id().startsWith(uuid))
236 - .findFirst().orElse(null);
237 -
238 - if (port == null) {
239 - log.error("There is no port information for port name {}", portName);
240 - return null;
241 - }
242 -
243 - if (port.fixedIps().isEmpty()) {
244 - log.error("There is no fixed IP info in the port information");
245 - return null;
246 - }
247 -
248 - return (Ip4Address) port.fixedIps().values().toArray()[0];
249 } 261 }
250 262
251 /** 263 /**
252 - * Returns the MAC address of the VM of the port. 264 + * Remove flows rules for the removed VM.
253 * 265 *
254 - * @param portName VM port 266 + * @param removedPort removedport info
255 - * @return MAC address of the VM 267 + * @param openstackPortInfoMap openstackPortInfoMap
256 */ 268 */
257 - private MacAddress getVmMacAddressForPort(String portName) { 269 + public void removeSwitchingRules(Port removedPort, Map<String, OpenstackPortInfo> openstackPortInfoMap) {
258 270
259 - String uuid = portName.substring(3); 271 + OpenstackPortInfo openstackPortInfo = openstackPortInfoMap
260 - OpenstackPort port = openstackPortList.stream() 272 + .get(removedPort.annotations().value("portName"));
261 - .filter(p -> p.id().startsWith(uuid))
262 - .findFirst().orElse(null);
263 273
264 - if (port == null) { 274 + DeviceId deviceId = openstackPortInfo.deviceId();
265 - log.error("There is no port information for port name {}", portName); 275 + Ip4Address vmIp = openstackPortInfo.ip();
266 - return null; 276 + PortNumber portNumber = removedPort.number();
267 - } 277 + long vni = openstackPortInfo.vni();
268 278
269 - return port.macAddress(); 279 + removeFlowRuleForTunnelTag(deviceId, portNumber);
280 + removeFlowRuleForVMsInSameCnode(deviceId, vmIp, vni);
281 + removeFlowRuleForVMsInDiffrentCnode(removedPort, deviceId, vmIp, vni, openstackPortInfoMap);
270 } 282 }
271 283
272 - private void setFlowRuleForTunnelTag(DeviceId deviceId, Port port, String vni) { 284 + /**
273 - 285 + * Removes flow rules for tagging tunnelId.
286 + *
287 + * @param deviceId device id
288 + * @param portNumber port number
289 + */
290 + private void removeFlowRuleForTunnelTag(DeviceId deviceId, PortNumber portNumber) {
274 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); 291 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
275 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); 292 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
276 293
277 sBuilder.matchEthType(Ethernet.TYPE_IPV4) 294 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
278 - .matchInPort(port.number()); 295 + .matchInPort(portNumber);
279 -
280 - tBuilder.setTunnelId(Long.parseLong(vni));
281 296
282 ForwardingObjective fo = DefaultForwardingObjective.builder() 297 ForwardingObjective fo = DefaultForwardingObjective.builder()
283 .withSelector(sBuilder.build()) 298 .withSelector(sBuilder.build())
...@@ -285,110 +300,159 @@ public class OpenstackSwitchingRulePopulator { ...@@ -285,110 +300,159 @@ public class OpenstackSwitchingRulePopulator {
285 .withPriority(TUNNELTAG_RULE_PRIORITY) 300 .withPriority(TUNNELTAG_RULE_PRIORITY)
286 .withFlag(ForwardingObjective.Flag.SPECIFIC) 301 .withFlag(ForwardingObjective.Flag.SPECIFIC)
287 .fromApp(appId) 302 .fromApp(appId)
288 - .add(); 303 + .remove();
289 304
290 flowObjectiveService.forward(deviceId, fo); 305 flowObjectiveService.forward(deviceId, fo);
291 } 306 }
292 307
293 -
294 /** 308 /**
295 - * Sets the flow rules for traffic between VMs in the same Cnode. 309 + * Removes the flow rules for traffic between VMs in the same Cnode.
296 * 310 *
297 - * @param ip4Address VM IP address 311 + * @param deviceId device id on which removed VM was run
298 - * @param id device ID to put rules 312 + * @param vmIp ip of the removed VM
299 - * @param port VM port 313 + * @param vni vni which removed VM was belonged
300 - * @param vni VM VNI
301 - * @param vmMacAddress VM MAC address
302 */ 314 */
303 - private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id, 315 + private void removeFlowRuleForVMsInSameCnode(DeviceId deviceId, Ip4Address vmIp, long vni) {
304 - Port port, String vni, MacAddress vmMacAddress) {
305 -
306 - //For L2 Switching Case
307 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); 316 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
308 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
309 317
310 sBuilder.matchEthType(Ethernet.TYPE_IPV4) 318 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
311 - .matchIPDst(ip4Address.toIpPrefix()) 319 + .matchIPDst(vmIp.toIpPrefix())
312 - .matchTunnelId(Long.parseLong(vni)); 320 + .matchTunnelId(vni);
313 -
314 - tBuilder.setOutput(port.number());
315 321
316 ForwardingObjective fo = DefaultForwardingObjective.builder() 322 ForwardingObjective fo = DefaultForwardingObjective.builder()
317 .withSelector(sBuilder.build()) 323 .withSelector(sBuilder.build())
318 - .withTreatment(tBuilder.build()) 324 + .withTreatment(DefaultTrafficTreatment.builder().build())
319 - .withPriority(SWITCHING_RULE_PRIORITY)
320 .withFlag(ForwardingObjective.Flag.SPECIFIC) 325 .withFlag(ForwardingObjective.Flag.SPECIFIC)
326 + .withPriority(SWITCHING_RULE_PRIORITY)
321 .fromApp(appId) 327 .fromApp(appId)
322 - .add(); 328 + .remove();
323 329
324 - flowObjectiveService.forward(id, fo); 330 + flowObjectiveService.forward(deviceId, fo);
325 } 331 }
326 332
327 -
328 /** 333 /**
329 - * Sets the flow rules between traffic from VMs in different Cnode. 334 + * Removes the flow rules for traffic between VMs in the different Cnode.
330 * 335 *
331 - * @param vni VNI 336 + * @param removedPort removedport info
332 - * @param id device ID 337 + * @param deviceId device id on which removed VM was run
333 - * @param hostIp host IP of the VM 338 + * @param vmIp ip of the removed VM
334 - * @param vmIp fixed IP of the VM 339 + * @param vni vni which removed VM was belonged
335 - * @param vmMac MAC address of the VM 340 + * @param openstackPortInfoMap openstackPortInfoMap
336 */ 341 */
337 - private void setVxLanFlowRule(String vni, DeviceId id, Ip4Address hostIp, 342 + private void removeFlowRuleForVMsInDiffrentCnode(Port removedPort, DeviceId deviceId, Ip4Address vmIp,
338 - Ip4Address vmIp, MacAddress vmMac) { 343 + long vni, Map<String, OpenstackPortInfo> openstackPortInfoMap) {
339 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
340 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
341 -
342 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
343 - .matchTunnelId(Long.parseLong(vni))
344 - .matchIPDst(vmIp.toIpPrefix());
345 344
346 - tBuilder.extension(buildNiciraExtenstion(id, hostIp), id) 345 + final boolean anyPortRemainedInSameCnode
347 - .setOutput(getTunnelPort(id)); 346 + = checkIfAnyPortRemainedInSameCnode(removedPort, deviceId, vni, openstackPortInfoMap);
348 347
349 - ForwardingObjective fo = DefaultForwardingObjective.builder() 348 + openstackPortInfoMap.forEach((port, portInfo) -> {
350 - .withSelector(sBuilder.build()) 349 + if (portInfo.vni() == vni && !portInfo.deviceId().equals(deviceId)) {
351 - .withTreatment(tBuilder.build()) 350 + removeVxLanFlowRule(portInfo.deviceId(), vmIp, vni);
352 - .withPriority(SWITCHING_RULE_PRIORITY) 351 + if (!anyPortRemainedInSameCnode) {
353 - .withFlag(ForwardingObjective.Flag.SPECIFIC) 352 + removeVxLanFlowRule(deviceId, portInfo.ip(), vni);
354 - .fromApp(appId) 353 + }
355 - .add(); 354 + }
356 - 355 + });
357 - flowObjectiveService.forward(id, fo);
358 } 356 }
359 357
360 - private void removeFlowRuleForVMsInSameCnode(DeviceId id, Ip4Address vmIp) { 358 + /**
359 + * Removes the flow rules between traffic from VMs in different Cnode.
360 + *
361 + * @param deviceId device id
362 + * @param vmIp ip
363 + * @param vni vni which removed VM was belonged
364 + */
365 + private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, long vni) {
361 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); 366 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
362 367
363 sBuilder.matchEthType(Ethernet.TYPE_IPV4) 368 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
369 + .matchTunnelId(vni)
364 .matchIPDst(vmIp.toIpPrefix()); 370 .matchIPDst(vmIp.toIpPrefix());
365 371
366 ForwardingObjective fo = DefaultForwardingObjective.builder() 372 ForwardingObjective fo = DefaultForwardingObjective.builder()
367 .withSelector(sBuilder.build()) 373 .withSelector(sBuilder.build())
368 .withTreatment(DefaultTrafficTreatment.builder().build()) 374 .withTreatment(DefaultTrafficTreatment.builder().build())
369 - .withFlag(ForwardingObjective.Flag.VERSATILE) 375 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
370 .withPriority(SWITCHING_RULE_PRIORITY) 376 .withPriority(SWITCHING_RULE_PRIORITY)
371 .fromApp(appId) 377 .fromApp(appId)
372 .remove(); 378 .remove();
373 379
374 - flowObjectiveService.forward(id, fo); 380 + flowObjectiveService.forward(deviceId, fo);
375 } 381 }
376 382
377 - private void removeVxLanFlowRule(DeviceId id, Ip4Address vmIp) { 383 + /**
378 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); 384 + * Checks if there is any port remained with same vni at the device, on which the removed VM was run.
379 - // XXX: Later, more matches will be added when multiple table is implemented. 385 + *
380 - sBuilder.matchEthType(Ethernet.TYPE_IPV4) 386 + * @param removedPort removedport info
381 - .matchIPDst(vmIp.toIpPrefix()); 387 + * @param deviceId device id on which removed VM was run
388 + * @param vni vni which removed VM was belonged
389 + * @param openstackPortInfoMap openstackPortInfoMap
390 + * @return true if there is, false otherwise
391 + */
392 + private boolean checkIfAnyPortRemainedInSameCnode(Port removedPort, DeviceId deviceId, long vni,
393 + Map<String, OpenstackPortInfo> openstackPortInfoMap) {
382 394
383 - ForwardingObjective fo = DefaultForwardingObjective.builder() 395 + for (Map.Entry<String, OpenstackPortInfo> entry : openstackPortInfoMap.entrySet()) {
384 - .withSelector(sBuilder.build()) 396 + if (!removedPort.annotations().value("portName").equals(entry.getKey())) {
385 - .withTreatment(DefaultTrafficTreatment.builder().build()) 397 + if (entry.getValue().vni() == vni && entry.getValue().deviceId().equals(deviceId)) {
386 - .withFlag(ForwardingObjective.Flag.VERSATILE) 398 + return true;
387 - .withPriority(SWITCHING_RULE_PRIORITY) 399 + }
388 - .fromApp(appId) 400 + }
389 - .remove(); 401 + }
402 + return false;
403 + }
390 404
391 - flowObjectiveService.forward(id, fo); 405 + /**
406 + * Returns the VNI of the VM of the port.
407 + *
408 + * @param portName VM port
409 + * @return VNI
410 + */
411 + private String getVniForPort(String portName) {
412 + String uuid = portName.substring(3);
413 + OpenstackPort port = openstackPortList.stream()
414 + .filter(p -> p.id().startsWith(uuid))
415 + .findAny().orElse(null);
416 + if (port == null) {
417 + log.debug("No port information for port {}", portName);
418 + return null;
419 + }
420 +
421 + OpenstackNetwork network = openstackNetworkList.stream()
422 + .filter(n -> n.id().equals(port.networkId()))
423 + .findAny().orElse(null);
424 + if (network == null) {
425 + log.warn("No VNI information for network {}", port.networkId());
426 + return null;
427 + }
428 +
429 + return network.segmentId();
430 + }
431 +
432 + /**
433 + * Returns the Fixed IP address of the VM.
434 + *
435 + * @param portName VM port info
436 + * @return IP address of the VM
437 + */
438 + private Ip4Address getFixedIpAddressForPort(String portName) {
439 +
440 + String uuid = portName.substring(3);
441 + OpenstackPort port = openstackPortList.stream()
442 + .filter(p -> p.id().startsWith(uuid))
443 + .findFirst().orElse(null);
444 +
445 + if (port == null) {
446 + log.error("There is no port information for port name {}", portName);
447 + return null;
448 + }
449 +
450 + if (port.fixedIps().isEmpty()) {
451 + log.error("There is no fixed IP info in the port information");
452 + return null;
453 + }
454 +
455 + return (Ip4Address) port.fixedIps().values().toArray()[0];
392 } 456 }
393 457
394 private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) { 458 private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
...@@ -409,8 +473,8 @@ public class OpenstackSwitchingRulePopulator { ...@@ -409,8 +473,8 @@ public class OpenstackSwitchingRulePopulator {
409 return extensionInstruction; 473 return extensionInstruction;
410 } 474 }
411 475
412 - private PortNumber getTunnelPort(DeviceId id) { 476 + private PortNumber getTunnelPort(DeviceId deviceId) {
413 - Port port = deviceService.getPorts(id).stream() 477 + Port port = deviceService.getPorts(deviceId).stream()
414 .filter(p -> p.annotations().value("portName").equals("vxlan")) 478 .filter(p -> p.annotations().value("portName").equals("vxlan"))
415 .findAny().orElse(null); 479 .findAny().orElse(null);
416 480
......