diff options
Diffstat (limited to 'framework/src/onos/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java')
-rw-r--r-- | framework/src/onos/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/framework/src/onos/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java b/framework/src/onos/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java new file mode 100644 index 00000000..38c03638 --- /dev/null +++ b/framework/src/onos/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/OpenstackSwitchingRulePopulator.java @@ -0,0 +1,307 @@ +/* +* Copyright 2015 Open Networking Laboratory +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.onosproject.openstackswitching; + +import org.onlab.packet.Ethernet; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.behaviour.ExtensionTreatmentResolver; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.ExtensionTreatment; +import org.onosproject.net.flow.instructions.ExtensionPropertyException; +import org.onosproject.net.flow.instructions.ExtensionTreatmentType; +import org.onosproject.net.flowobjective.DefaultForwardingObjective; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; + +/** + * Populates switching flow rules. + */ +public class OpenstackSwitchingRulePopulator { + + private static Logger log = LoggerFactory + .getLogger(OpenstackSwitchingRulePopulator.class); + private static final int SWITCHING_RULE_PRIORITY = 50000; + + private FlowObjectiveService flowObjectiveService; + private DriverService driverService; + private DeviceService deviceService; + private OpenstackRestHandler restHandler; + private ApplicationId appId; + + private Collection<OpenstackNetwork> openstackNetworkList; + private Collection<OpenstackPort> openstackPortList; + + /** + * Creates OpenstackSwitchingRulPopulator. + * + * @param appId application id + * @param flowObjectiveService FlowObjectiveService reference + * @param deviceService DeviceService reference + * @param driverService DriverService reference + */ + public OpenstackSwitchingRulePopulator(ApplicationId appId, + FlowObjectiveService flowObjectiveService, + DeviceService deviceService, + OpenstackRestHandler restHandler, + DriverService driverService) { + this.flowObjectiveService = flowObjectiveService; + this.deviceService = deviceService; + this.driverService = driverService; + this.restHandler = restHandler; + this.appId = appId; + + openstackNetworkList = restHandler.getNetworks(); + openstackPortList = restHandler.getPorts(); + } + + /** + * Populates flow rules for the VM created. + * + * @param device device to populate rules to + * @param port port for the VM created + */ + public void populateSwitchingRules(Device device, Port port) { + populateFlowRulesForTrafficToSameCnode(device, port); + populateFlowRulesForTrafficToDifferentCnode(device, port); + } + + /** + * Populates the flow rules for traffic to VMs in the same Cnode as the sender. + * + * @param device device to put the rules + * @param port port info of the VM + */ + private void populateFlowRulesForTrafficToSameCnode(Device device, Port port) { + Ip4Address vmIp = getFixedIpAddressForPort(port.annotations().value("portName")); + if (vmIp != null) { + setFlowRuleForVMsInSameCnode(vmIp, device.id(), port); + } + } + + /** + * Populates the flow rules for traffic to VMs in different Cnode using + * Nicira extention. + * + * @param device device to put rules + * @param port port information of the VM + */ + private void populateFlowRulesForTrafficToDifferentCnode(Device device, Port port) { + String portName = port.annotations().value("portName"); + String channelId = device.annotations().value("channelId"); + Ip4Address hostIpAddress = Ip4Address.valueOf(channelId.split(":")[0]); + Ip4Address fixedIp = getFixedIpAddressForPort(portName); + MacAddress vmMac = getVmMacAddressForPort(portName); + String vni = getVniForPort(portName); + deviceService.getAvailableDevices().forEach(d -> { + if (!d.equals(device)) { + deviceService.getPorts(d.id()).forEach(p -> { + String pName = p.annotations().value("portName"); + if (!p.equals(port) && vni.equals(getVniForPort(pName))) { + String cidx = d.annotations().value("channelId"); + Ip4Address hostIpx = Ip4Address.valueOf(cidx.split(":")[0]); + MacAddress vmMacx = getVmMacAddressForPort(pName); + Ip4Address fixedIpx = getFixedIpAddressForPort(pName); + + setVxLanFlowRule(vni, device.id(), hostIpx, fixedIpx, vmMacx); + setVxLanFlowRule(vni, d.id(), hostIpAddress, fixedIp, vmMac); + } + }); + } + }); + } + + /** + * Returns the VNI of the VM of the port. + * + * @param portName VM port + * @return VNI + */ + private String getVniForPort(String portName) { + String uuid = portName.substring(3); + OpenstackPort port = openstackPortList.stream() + .filter(p -> p.id().startsWith(uuid)) + .findAny().orElse(null); + if (port == null) { + log.warn("No port information for port {}", portName); + return null; + } + + OpenstackNetwork network = openstackNetworkList.stream() + .filter(n -> n.id().equals(port.networkId())) + .findAny().orElse(null); + if (network == null) { + log.warn("No VNI information for network {}", port.networkId()); + return null; + } + + return network.segmentId(); + } + + /** + * Returns the Fixed IP address of the VM. + * + * @param portName VM port info + * @return IP address of the VM + */ + private Ip4Address getFixedIpAddressForPort(String portName) { + + String uuid = portName.substring(3); + OpenstackPort port = openstackPortList.stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().orElse(null); + + if (port == null) { + log.error("There is no port information for port name {}", portName); + return null; + } + + if (port.fixedIps().isEmpty()) { + log.error("There is no fixed IP info in the port information"); + return null; + } + + return (Ip4Address) port.fixedIps().values().toArray()[0]; + } + + /** + * Returns the MAC address of the VM of the port. + * + * @param portName VM port + * @return MAC address of the VM + */ + private MacAddress getVmMacAddressForPort(String portName) { + + String uuid = portName.substring(3); + OpenstackPort port = openstackPortList.stream() + .filter(p -> p.id().startsWith(uuid)) + .findFirst().orElse(null); + + if (port == null) { + log.error("There is port information for port name {}", portName); + return null; + } + + return port.macAddress(); + } + + /** + * Sets the flow rules for traffic between VMs in the same Cnode. + * + * @param ip4Address VM IP address + * @param id device ID to put rules + * @param port VM port + */ + private void setFlowRuleForVMsInSameCnode(Ip4Address ip4Address, DeviceId id, + Port port) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst(ip4Address.toIpPrefix()); + tBuilder.setOutput(port.number()); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(SWITCHING_RULE_PRIORITY) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } + + /** + * Sets the flow rules between traffic from VMs in different Cnode. + * + * @param vni VNI + * @param id device ID + * @param hostIp host IP of the VM + * @param vmIp fixed IP of the VM + * @param vmMac MAC address of the VM + */ + private void setVxLanFlowRule(String vni, DeviceId id, Ip4Address hostIp, + Ip4Address vmIp, MacAddress vmMac) { + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + sBuilder.matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst(vmIp.toIpPrefix()); + tBuilder.setTunnelId(Long.parseLong(vni)) + .extension(buildNiciraExtenstion(id, hostIp), id) + .setOutput(getTunnelPort(id)); + + ForwardingObjective fo = DefaultForwardingObjective.builder() + .withSelector(sBuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(SWITCHING_RULE_PRIORITY) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .fromApp(appId) + .add(); + + flowObjectiveService.forward(id, fo); + } + + private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) { + Driver driver = driverService.getDriver(id); + DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id)); + ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class); + + ExtensionTreatment extensionInstruction = + resolver.getExtensionInstruction( + ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type()); + + try { + extensionInstruction.setPropertyValue("tunnelDst", hostIp); + } catch (ExtensionPropertyException e) { + log.error("Error setting Nicira extension setting {}", e); + } + + return extensionInstruction; + } + + private PortNumber getTunnelPort(DeviceId id) { + Port port = deviceService.getPorts(id).stream() + .filter(p -> p.annotations().value("portName").equals("vxlan")) + .findAny().orElse(null); + + if (port == null) { + log.error("No TunnelPort was created."); + return null; + } + return port.number(); + } +} |