blob: 38c036389b0e444928c351d449fda39085585948 [file] [log] [blame]
sanghoshin94872a12015-10-16 18:04:34 +09001/*
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*/
16
17package org.onosproject.openstackswitching;
18
19import org.onlab.packet.Ethernet;
sanghoshin94872a12015-10-16 18:04:34 +090020import org.onlab.packet.Ip4Address;
sanghoshin94872a12015-10-16 18:04:34 +090021import org.onlab.packet.MacAddress;
sanghoshin94872a12015-10-16 18:04:34 +090022import org.onosproject.core.ApplicationId;
sanghoshinf25d2e02015-11-11 23:07:17 +090023import org.onosproject.net.Device;
sanghoshin94872a12015-10-16 18:04:34 +090024import org.onosproject.net.DeviceId;
25import org.onosproject.net.Port;
26import org.onosproject.net.PortNumber;
sanghoshinf25d2e02015-11-11 23:07:17 +090027import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
28import org.onosproject.net.device.DeviceService;
29import org.onosproject.net.driver.DefaultDriverData;
30import org.onosproject.net.driver.DefaultDriverHandler;
31import org.onosproject.net.driver.Driver;
32import org.onosproject.net.driver.DriverHandler;
33import org.onosproject.net.driver.DriverService;
sanghoshin94872a12015-10-16 18:04:34 +090034import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.flow.TrafficTreatment;
sanghoshinf25d2e02015-11-11 23:07:17 +090038import org.onosproject.net.flow.instructions.ExtensionTreatment;
39import org.onosproject.net.flow.instructions.ExtensionPropertyException;
40import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
sanghoshin94872a12015-10-16 18:04:34 +090041import org.onosproject.net.flowobjective.DefaultForwardingObjective;
42import org.onosproject.net.flowobjective.FlowObjectiveService;
43import org.onosproject.net.flowobjective.ForwardingObjective;
44import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
sanghoshinf25d2e02015-11-11 23:07:17 +090047import java.util.Collection;
48
sanghoshin94872a12015-10-16 18:04:34 +090049/**
sanghoshin46297d22015-11-03 17:51:24 +090050 * Populates switching flow rules.
sanghoshin94872a12015-10-16 18:04:34 +090051 */
52public class OpenstackSwitchingRulePopulator {
53
54 private static Logger log = LoggerFactory
55 .getLogger(OpenstackSwitchingRulePopulator.class);
sanghoshinf25d2e02015-11-11 23:07:17 +090056 private static final int SWITCHING_RULE_PRIORITY = 50000;
sanghoshin94872a12015-10-16 18:04:34 +090057
58 private FlowObjectiveService flowObjectiveService;
sanghoshinf25d2e02015-11-11 23:07:17 +090059 private DriverService driverService;
60 private DeviceService deviceService;
61 private OpenstackRestHandler restHandler;
sanghoshin94872a12015-10-16 18:04:34 +090062 private ApplicationId appId;
63
sanghoshinf25d2e02015-11-11 23:07:17 +090064 private Collection<OpenstackNetwork> openstackNetworkList;
65 private Collection<OpenstackPort> openstackPortList;
66
sanghoshin94872a12015-10-16 18:04:34 +090067 /**
Ray Milkey87b16b02015-10-30 11:50:00 -070068 * Creates OpenstackSwitchingRulPopulator.
69 *
70 * @param appId application id
sanghoshin94872a12015-10-16 18:04:34 +090071 * @param flowObjectiveService FlowObjectiveService reference
sanghoshinf25d2e02015-11-11 23:07:17 +090072 * @param deviceService DeviceService reference
73 * @param driverService DriverService reference
sanghoshin94872a12015-10-16 18:04:34 +090074 */
75 public OpenstackSwitchingRulePopulator(ApplicationId appId,
sanghoshinf25d2e02015-11-11 23:07:17 +090076 FlowObjectiveService flowObjectiveService,
77 DeviceService deviceService,
78 OpenstackRestHandler restHandler,
79 DriverService driverService) {
sanghoshin94872a12015-10-16 18:04:34 +090080 this.flowObjectiveService = flowObjectiveService;
sanghoshinf25d2e02015-11-11 23:07:17 +090081 this.deviceService = deviceService;
82 this.driverService = driverService;
83 this.restHandler = restHandler;
sanghoshin94872a12015-10-16 18:04:34 +090084 this.appId = appId;
sanghoshinf25d2e02015-11-11 23:07:17 +090085
86 openstackNetworkList = restHandler.getNetworks();
87 openstackPortList = restHandler.getPorts();
sanghoshin94872a12015-10-16 18:04:34 +090088 }
89
90 /**
sanghoshinf25d2e02015-11-11 23:07:17 +090091 * Populates flow rules for the VM created.
sanghoshin94872a12015-10-16 18:04:34 +090092 *
sanghoshinf25d2e02015-11-11 23:07:17 +090093 * @param device device to populate rules to
94 * @param port port for the VM created
sanghoshin94872a12015-10-16 18:04:34 +090095 */
sanghoshinf25d2e02015-11-11 23:07:17 +090096 public void populateSwitchingRules(Device device, Port port) {
97 populateFlowRulesForTrafficToSameCnode(device, port);
98 populateFlowRulesForTrafficToDifferentCnode(device, port);
sanghoshin94872a12015-10-16 18:04:34 +090099 }
100
101 /**
sanghoshinf25d2e02015-11-11 23:07:17 +0900102 * Populates the flow rules for traffic to VMs in the same Cnode as the sender.
sanghoshin94872a12015-10-16 18:04:34 +0900103 *
sanghoshinf25d2e02015-11-11 23:07:17 +0900104 * @param device device to put the rules
105 * @param port port info of the VM
sanghoshin94872a12015-10-16 18:04:34 +0900106 */
sanghoshinf25d2e02015-11-11 23:07:17 +0900107 private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) {
108 Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName"));
109 if (vmIp != null) {
110 setFlowRuleForVMsInSameCnode(vmIp, device.id(), port);
111 }
sanghoshin94872a12015-10-16 18:04:34 +0900112 }
113
114 /**
sanghoshinf25d2e02015-11-11 23:07:17 +0900115 * Populates the flow rules for traffic to VMs in different Cnode using
116 * Nicira extention.
sanghoshin94872a12015-10-16 18:04:34 +0900117 *
sanghoshinf25d2e02015-11-11 23:07:17 +0900118 * @param device device to put rules
119 * @param port port information of the VM
sanghoshin94872a12015-10-16 18:04:34 +0900120 */
sanghoshinf25d2e02015-11-11 23:07:17 +0900121 private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) {
122 String portName = port.annotations().value("portName");
123 String channelId = device.annotations().value("channelId");
124 Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]);
125 Ip4Address fixedIp = getFixedIpAddressForPort(portName);
126 MacAddress vmMac = getVmMacAddressForPort(portName);
127 String vni = getVniForPort(portName);
128 deviceService.getAvailableDevices().forEach(d -> {
129 if (!d.equals(device)) {
130 deviceService.getPorts(d.id()).forEach(p -> {
131 String pName = p.annotations().value("portName");
132 if (!p.equals(port) && vni.equals(getVniForPort(pName))) {
133 String cidx = d.annotations().value("channelId");
134 Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]);
135 MacAddress vmMacx = getVmMacAddressForPort(pName);
136 Ip4Address fixedIpx = getFixedIpAddressForPort(pName);
137
138 setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx, vmMacx);
139 setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp, vmMac);
140 }
141 });
142 }
143 });
sanghoshin94872a12015-10-16 18:04:34 +0900144 }
145
146 /**
sanghoshinf25d2e02015-11-11 23:07:17 +0900147 * Returns the VNI of the VM of the port.
sanghoshin94872a12015-10-16 18:04:34 +0900148 *
sanghoshinf25d2e02015-11-11 23:07:17 +0900149 * @param portName VM port
150 * @return VNI
sanghoshin94872a12015-10-16 18:04:34 +0900151 */
sanghoshinf25d2e02015-11-11 23:07:17 +0900152 private String getVniForPort(String portName) {
153 String uuid = portName.substring(3);
154 OpenstackPort port = openstackPortList.stream()
155 .filter(p -> p.id().startsWith(uuid))
156 .findAny().orElse(null);
157 if (port == null) {
158 log.warn("No port information for port {}", portName);
159 return null;
160 }
sanghoshin94872a12015-10-16 18:04:34 +0900161
sanghoshinf25d2e02015-11-11 23:07:17 +0900162 OpenstackNetwork network = openstackNetworkList.stream()
163 .filter(n -> n.id().equals(port.networkId()))
164 .findAny().orElse(null);
165 if (network == null) {
Satish K2e2d6352015-11-27 12:02:15 +0530166 log.warn("No VNI information for network {}", port.networkId());
sanghoshinf25d2e02015-11-11 23:07:17 +0900167 return null;
168 }
sanghoshin94872a12015-10-16 18:04:34 +0900169
sanghoshinf25d2e02015-11-11 23:07:17 +0900170 return network.segmentId();
sanghoshin94872a12015-10-16 18:04:34 +0900171 }
172
173 /**
sanghoshinf25d2e02015-11-11 23:07:17 +0900174 * Returns the Fixed IP address of the VM.
sanghoshin94872a12015-10-16 18:04:34 +0900175 *
sanghoshinf25d2e02015-11-11 23:07:17 +0900176 * @param portName VM port info
177 * @return IP address of the VM
sanghoshin94872a12015-10-16 18:04:34 +0900178 */
sanghoshinf25d2e02015-11-11 23:07:17 +0900179 private Ip4Address getFixedIpAddressForPort(String portName) {
sanghoshin94872a12015-10-16 18:04:34 +0900180
sanghoshinf25d2e02015-11-11 23:07:17 +0900181 String uuid = portName.substring(3);
182 OpenstackPort port = openstackPortList.stream()
183 .filter(p -> p.id().startsWith(uuid))
184 .findFirst().orElse(null);
sanghoshin94872a12015-10-16 18:04:34 +0900185
sanghoshinf25d2e02015-11-11 23:07:17 +0900186 if (port == null) {
187 log.error("There is no port information for port name {}", portName);
188 return null;
189 }
sanghoshin94872a12015-10-16 18:04:34 +0900190
sanghoshinf25d2e02015-11-11 23:07:17 +0900191 if (port.fixedIps().isEmpty()) {
192 log.error("There is no fixed IP info in the port information");
193 return null;
194 }
195
196 return (Ip4Address) port.fixedIps().values().toArray()[0];
197 }
198
199 /**
200 * Returns the MAC address of the VM of the port.
201 *
202 * @param portName VM port
203 * @return MAC address of the VM
204 */
205 private MacAddress getVmMacAddressForPort(String portName) {
206
207 String uuid = portName.substring(3);
208 OpenstackPort port = openstackPortList.stream()
209 .filter(p -> p.id().startsWith(uuid))
210 .findFirst().orElse(null);
211
212 if (port == null) {
213 log.error("There is port information for port name {}", portName);
214 return null;
215 }
216
217 return port.macAddress();
sanghoshin94872a12015-10-16 18:04:34 +0900218 }
219
220 /**
221 * Sets the flow rules for traffic between VMs in the same Cnode.
222 *
223 * @param ip4Address VM IP address
224 * @param id device ID to put rules
225 * @param port VM port
sanghoshin94872a12015-10-16 18:04:34 +0900226 */
227 private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id,
sanghoshinf25d2e02015-11-11 23:07:17 +0900228 Port port) {
sanghoshin94872a12015-10-16 18:04:34 +0900229 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
230 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
231
232 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
sanghoshinf25d2e02015-11-11 23:07:17 +0900233 .matchIPDst(ip4Address.toIpPrefix());
sanghoshin94872a12015-10-16 18:04:34 +0900234 tBuilder.setOutput(port.number());
235
236 ForwardingObjective fo = DefaultForwardingObjective.builder()
237 .withSelector(sBuilder.build())
238 .withTreatment(tBuilder.build())
sanghoshinf25d2e02015-11-11 23:07:17 +0900239 .withPriority(SWITCHING_RULE_PRIORITY)
sanghoshin94872a12015-10-16 18:04:34 +0900240 .withFlag(ForwardingObjective.Flag.VERSATILE)
241 .fromApp(appId)
242 .add();
243
244 flowObjectiveService.forward(id, fo);
245 }
246
247 /**
248 * Sets the flow rules between traffic from VMs in different Cnode.
249 *
250 * @param vni VNI
251 * @param id device ID
252 * @param hostIp host IP of the VM
253 * @param vmIp fixed IP of the VM
254 * @param vmMac MAC address of the VM
sanghoshin94872a12015-10-16 18:04:34 +0900255 */
256 private void setVxLanFlowRule(String vni, DeviceId id, Ip4Address hostIp,
sanghoshinf25d2e02015-11-11 23:07:17 +0900257 Ip4Address vmIp, MacAddress vmMac) {
sanghoshin94872a12015-10-16 18:04:34 +0900258 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
259 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
260
261 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
262 .matchIPDst(vmIp.toIpPrefix());
263 tBuilder.setTunnelId(Long.parseLong(vni))
sanghoshinf25d2e02015-11-11 23:07:17 +0900264 .extension(buildNiciraExtenstion(id, hostIp), id)
265 .setOutput(getTunnelPort(id));
sanghoshin94872a12015-10-16 18:04:34 +0900266
267 ForwardingObjective fo = DefaultForwardingObjective.builder()
268 .withSelector(sBuilder.build())
269 .withTreatment(tBuilder.build())
sanghoshinf25d2e02015-11-11 23:07:17 +0900270 .withPriority(SWITCHING_RULE_PRIORITY)
sanghoshin94872a12015-10-16 18:04:34 +0900271 .withFlag(ForwardingObjective.Flag.VERSATILE)
272 .fromApp(appId)
273 .add();
274
275 flowObjectiveService.forward(id, fo);
276 }
sanghoshinf25d2e02015-11-11 23:07:17 +0900277
278 private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
279 Driver driver = driverService.getDriver(id);
280 DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id));
281 ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
282
283 ExtensionTreatment extensionInstruction =
284 resolver.getExtensionInstruction(
285 ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
286
287 try {
288 extensionInstruction.setPropertyValue("tunnelDst", hostIp);
289 } catch (ExtensionPropertyException e) {
290 log.error("Error setting Nicira extension setting {}", e);
291 }
292
293 return extensionInstruction;
294 }
295
296 private PortNumber getTunnelPort(DeviceId id) {
297 Port port = deviceService.getPorts(id).stream()
298 .filter(p -> p.annotations().value("portName").equals("vxlan"))
299 .findAny().orElse(null);
300
301 if (port == null) {
302 log.error("No TunnelPort was created.");
303 return null;
304 }
305 return port.number();
306 }
sanghoshin94872a12015-10-16 18:04:34 +0900307}