[Falcon] CORD-366 Implemented CORD service dependency API and pipeline
Done - Implement service dependency APIs - Populate or remove basic tenant connectivity rules when VM created or removed - Populate direct/indirect service access rules when service dependency created - Remove service dependency rules Todo - Add/remove bucket to proper group when a VM is created or terminated - Populate service dependency rules for existing VMs when service is activated - Cleanup flow rules remove Change-Id: I1daaf7ac9b41d7f2694605cb9b75f12d42144dbd
Showing
6 changed files
with
1011 additions
and
469 deletions
| ... | @@ -18,8 +18,18 @@ package org.onosproject.cordvtn; | ... | @@ -18,8 +18,18 @@ package org.onosproject.cordvtn; |
| 18 | import com.google.common.base.MoreObjects; | 18 | import com.google.common.base.MoreObjects; |
| 19 | import org.onlab.packet.IpAddress; | 19 | import org.onlab.packet.IpAddress; |
| 20 | import org.onlab.packet.IpPrefix; | 20 | import org.onlab.packet.IpPrefix; |
| 21 | +import org.onosproject.net.Host; | ||
| 22 | +import org.onosproject.openstackswitching.OpenstackNetwork; | ||
| 23 | +import org.onosproject.openstackswitching.OpenstackSubnet; | ||
| 21 | 24 | ||
| 25 | +import java.util.Map; | ||
| 22 | import java.util.Objects; | 26 | import java.util.Objects; |
| 27 | +import java.util.Set; | ||
| 28 | + | ||
| 29 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 30 | +import static org.onosproject.cordvtn.CordService.ServiceType.*; | ||
| 31 | +import static org.onosproject.cordvtn.CordService.ServiceType.PRIVATE; | ||
| 32 | +import static org.onosproject.cordvtn.CordService.ServiceType.PUBLIC_INDIRECT; | ||
| 23 | 33 | ||
| 24 | public final class CordService { | 34 | public final class CordService { |
| 25 | 35 | ||
| ... | @@ -36,23 +46,25 @@ public final class CordService { | ... | @@ -36,23 +46,25 @@ public final class CordService { |
| 36 | private final ServiceType serviceType; | 46 | private final ServiceType serviceType; |
| 37 | private final IpPrefix serviceIpRange; | 47 | private final IpPrefix serviceIpRange; |
| 38 | private final IpAddress serviceIp; | 48 | private final IpAddress serviceIp; |
| 49 | + private final Map<Host, IpAddress> hosts; | ||
| 50 | + private final Set<CordServiceId> tenantServices; | ||
| 39 | 51 | ||
| 40 | /** | 52 | /** |
| 41 | * Default constructor. | 53 | * Default constructor. |
| 42 | * | 54 | * |
| 43 | - * @param id service id, which is identical to OpenStack network id | 55 | + * @param vNet OpenStack network |
| 44 | - * @param segmentationId segmentation id, which is identical to VNI | 56 | + * @param hosts host and tunnel ip map |
| 45 | - * @param serviceType service type | 57 | + * @param tenantServices list of tenant service ids |
| 46 | - * @param serviceIpRange service ip range | ||
| 47 | - * @param serviceIp service ip | ||
| 48 | */ | 58 | */ |
| 49 | - public CordService(CordServiceId id, long segmentationId, ServiceType serviceType, | 59 | + public CordService(OpenstackNetwork vNet, OpenstackSubnet subnet, |
| 50 | - IpPrefix serviceIpRange, IpAddress serviceIp) { | 60 | + Map<Host, IpAddress> hosts, Set<CordServiceId> tenantServices) { |
| 51 | - this.id = id; | 61 | + this.id = CordServiceId.of(vNet.id()); |
| 52 | - this.segmentationId = segmentationId; | 62 | + this.segmentationId = Long.parseLong(vNet.segmentId()); |
| 53 | - this.serviceType = serviceType; | 63 | + this.serviceType = getServiceType(vNet.name()); |
| 54 | - this.serviceIpRange = serviceIpRange; | 64 | + this.serviceIpRange = IpPrefix.valueOf(subnet.cidr()); |
| 55 | - this.serviceIp = serviceIp; | 65 | + this.serviceIp = IpAddress.valueOf(subnet.gatewayIp()); |
| 66 | + this.hosts = hosts; | ||
| 67 | + this.tenantServices = tenantServices; | ||
| 56 | } | 68 | } |
| 57 | 69 | ||
| 58 | /** | 70 | /** |
| ... | @@ -100,6 +112,24 @@ public final class CordService { | ... | @@ -100,6 +112,24 @@ public final class CordService { |
| 100 | return serviceIp; | 112 | return serviceIp; |
| 101 | } | 113 | } |
| 102 | 114 | ||
| 115 | + /** | ||
| 116 | + * Returns hosts associated with this service. | ||
| 117 | + * | ||
| 118 | + * @return list of hosts | ||
| 119 | + */ | ||
| 120 | + public Map<Host, IpAddress> hosts() { | ||
| 121 | + return hosts; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + /** | ||
| 125 | + * Returns tenant service IDs. | ||
| 126 | + * | ||
| 127 | + * @return list of tenant service id | ||
| 128 | + */ | ||
| 129 | + public Set<CordServiceId> tenantServices() { | ||
| 130 | + return tenantServices; | ||
| 131 | + } | ||
| 132 | + | ||
| 103 | @Override | 133 | @Override |
| 104 | public int hashCode() { | 134 | public int hashCode() { |
| 105 | return Objects.hash(id); | 135 | return Objects.hash(id); |
| ... | @@ -125,6 +155,33 @@ public final class CordService { | ... | @@ -125,6 +155,33 @@ public final class CordService { |
| 125 | .add("serviceType", serviceType) | 155 | .add("serviceType", serviceType) |
| 126 | .add("serviceIpRange", serviceIpRange) | 156 | .add("serviceIpRange", serviceIpRange) |
| 127 | .add("serviceIp", serviceIp) | 157 | .add("serviceIp", serviceIp) |
| 158 | + .add("tenantServices", tenantServices) | ||
| 128 | .toString(); | 159 | .toString(); |
| 129 | } | 160 | } |
| 161 | + | ||
| 162 | + /** | ||
| 163 | + * Returns network type from network name. | ||
| 164 | + * It assumes that network name contains network type. | ||
| 165 | + * | ||
| 166 | + * @param netName network name | ||
| 167 | + * @return network type, or null if it doesn't match any type | ||
| 168 | + */ | ||
| 169 | + private ServiceType getServiceType(String netName) { | ||
| 170 | + checkNotNull(netName); | ||
| 171 | + | ||
| 172 | + String name = netName.toUpperCase(); | ||
| 173 | + if (name.contains(PRIVATE_DIRECT.toString())) { | ||
| 174 | + return PRIVATE_DIRECT; | ||
| 175 | + } else if (name.contains(PRIVATE_INDIRECT.toString())) { | ||
| 176 | + return PRIVATE_INDIRECT; | ||
| 177 | + } else if (name.contains(PUBLIC_DIRECT.toString())) { | ||
| 178 | + return PUBLIC_DIRECT; | ||
| 179 | + } else if (name.contains(PUBLIC_INDIRECT.toString())) { | ||
| 180 | + return PUBLIC_INDIRECT; | ||
| 181 | + } else if (name.contains(PRIVATE.toString())) { | ||
| 182 | + return PRIVATE; | ||
| 183 | + } else { | ||
| 184 | + return null; | ||
| 185 | + } | ||
| 186 | + } | ||
| 130 | } | 187 | } | ... | ... |
| ... | @@ -15,7 +15,6 @@ | ... | @@ -15,7 +15,6 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.cordvtn; | 16 | package org.onosproject.cordvtn; |
| 17 | 17 | ||
| 18 | -import com.google.common.collect.Lists; | ||
| 19 | import com.google.common.collect.Maps; | 18 | import com.google.common.collect.Maps; |
| 20 | import com.google.common.collect.Sets; | 19 | import com.google.common.collect.Sets; |
| 21 | import org.apache.felix.scr.annotations.Activate; | 20 | import org.apache.felix.scr.annotations.Activate; |
| ... | @@ -24,21 +23,23 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -24,21 +23,23 @@ import org.apache.felix.scr.annotations.Deactivate; |
| 24 | import org.apache.felix.scr.annotations.Reference; | 23 | import org.apache.felix.scr.annotations.Reference; |
| 25 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 24 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 26 | import org.apache.felix.scr.annotations.Service; | 25 | import org.apache.felix.scr.annotations.Service; |
| 26 | +import org.onlab.packet.Ip4Address; | ||
| 27 | import org.onlab.util.ItemNotFoundException; | 27 | import org.onlab.util.ItemNotFoundException; |
| 28 | import org.onlab.packet.IpAddress; | 28 | import org.onlab.packet.IpAddress; |
| 29 | import org.onlab.util.KryoNamespace; | 29 | import org.onlab.util.KryoNamespace; |
| 30 | import org.onosproject.cluster.ClusterService; | 30 | import org.onosproject.cluster.ClusterService; |
| 31 | import org.onosproject.core.ApplicationId; | 31 | import org.onosproject.core.ApplicationId; |
| 32 | import org.onosproject.core.CoreService; | 32 | import org.onosproject.core.CoreService; |
| 33 | +import org.onosproject.mastership.MastershipService; | ||
| 33 | import org.onosproject.net.DefaultAnnotations; | 34 | import org.onosproject.net.DefaultAnnotations; |
| 34 | import org.onosproject.net.Device; | 35 | import org.onosproject.net.Device; |
| 35 | import org.onosproject.net.DeviceId; | 36 | import org.onosproject.net.DeviceId; |
| 36 | import org.onosproject.net.Host; | 37 | import org.onosproject.net.Host; |
| 37 | import org.onosproject.net.HostId; | 38 | import org.onosproject.net.HostId; |
| 38 | import org.onosproject.net.Port; | 39 | import org.onosproject.net.Port; |
| 40 | +import org.onosproject.net.PortNumber; | ||
| 39 | import org.onosproject.net.behaviour.BridgeConfig; | 41 | import org.onosproject.net.behaviour.BridgeConfig; |
| 40 | import org.onosproject.net.behaviour.BridgeName; | 42 | import org.onosproject.net.behaviour.BridgeName; |
| 41 | -import org.onosproject.net.ConnectPoint; | ||
| 42 | import org.onosproject.net.behaviour.ControllerInfo; | 43 | import org.onosproject.net.behaviour.ControllerInfo; |
| 43 | import org.onosproject.net.behaviour.DefaultTunnelDescription; | 44 | import org.onosproject.net.behaviour.DefaultTunnelDescription; |
| 44 | import org.onosproject.net.behaviour.TunnelConfig; | 45 | import org.onosproject.net.behaviour.TunnelConfig; |
| ... | @@ -50,12 +51,14 @@ import org.onosproject.net.device.DeviceListener; | ... | @@ -50,12 +51,14 @@ import org.onosproject.net.device.DeviceListener; |
| 50 | import org.onosproject.net.device.DeviceService; | 51 | import org.onosproject.net.device.DeviceService; |
| 51 | import org.onosproject.net.driver.DriverHandler; | 52 | import org.onosproject.net.driver.DriverHandler; |
| 52 | import org.onosproject.net.driver.DriverService; | 53 | import org.onosproject.net.driver.DriverService; |
| 53 | -import org.onosproject.net.flowobjective.FlowObjectiveService; | 54 | +import org.onosproject.net.flow.FlowRuleService; |
| 55 | +import org.onosproject.net.group.GroupService; | ||
| 54 | import org.onosproject.net.host.HostEvent; | 56 | import org.onosproject.net.host.HostEvent; |
| 55 | import org.onosproject.net.host.HostListener; | 57 | import org.onosproject.net.host.HostListener; |
| 56 | import org.onosproject.net.host.HostService; | 58 | import org.onosproject.net.host.HostService; |
| 57 | import org.onosproject.openstackswitching.OpenstackNetwork; | 59 | import org.onosproject.openstackswitching.OpenstackNetwork; |
| 58 | import org.onosproject.openstackswitching.OpenstackPort; | 60 | import org.onosproject.openstackswitching.OpenstackPort; |
| 61 | +import org.onosproject.openstackswitching.OpenstackSubnet; | ||
| 59 | import org.onosproject.openstackswitching.OpenstackSwitchingService; | 62 | import org.onosproject.openstackswitching.OpenstackSwitchingService; |
| 60 | import org.onosproject.ovsdb.controller.OvsdbClientService; | 63 | import org.onosproject.ovsdb.controller.OvsdbClientService; |
| 61 | import org.onosproject.ovsdb.controller.OvsdbController; | 64 | import org.onosproject.ovsdb.controller.OvsdbController; |
| ... | @@ -71,6 +74,7 @@ import java.util.HashMap; | ... | @@ -71,6 +74,7 @@ import java.util.HashMap; |
| 71 | import java.util.List; | 74 | import java.util.List; |
| 72 | import java.util.Map; | 75 | import java.util.Map; |
| 73 | import java.util.NoSuchElementException; | 76 | import java.util.NoSuchElementException; |
| 77 | +import java.util.Objects; | ||
| 74 | import java.util.Set; | 78 | import java.util.Set; |
| 75 | import java.util.concurrent.ExecutorService; | 79 | import java.util.concurrent.ExecutorService; |
| 76 | import java.util.concurrent.Executors; | 80 | import java.util.concurrent.Executors; |
| ... | @@ -99,6 +103,7 @@ public class CordVtn implements CordVtnService { | ... | @@ -99,6 +103,7 @@ public class CordVtn implements CordVtnService { |
| 99 | .register(NodeState.class); | 103 | .register(NodeState.class); |
| 100 | private static final String DEFAULT_BRIDGE = "br-int"; | 104 | private static final String DEFAULT_BRIDGE = "br-int"; |
| 101 | private static final String VPORT_PREFIX = "tap"; | 105 | private static final String VPORT_PREFIX = "tap"; |
| 106 | + private static final String GWPORT_PREFIX = "qr-"; | ||
| 102 | private static final String DEFAULT_TUNNEL = "vxlan"; | 107 | private static final String DEFAULT_TUNNEL = "vxlan"; |
| 103 | private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() { | 108 | private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() { |
| 104 | { | 109 | { |
| ... | @@ -128,7 +133,7 @@ public class CordVtn implements CordVtnService { | ... | @@ -128,7 +133,7 @@ public class CordVtn implements CordVtnService { |
| 128 | protected DeviceAdminService adminService; | 133 | protected DeviceAdminService adminService; |
| 129 | 134 | ||
| 130 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 135 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 131 | - protected FlowObjectiveService flowObjectiveService; | 136 | + protected FlowRuleService flowRuleService; |
| 132 | 137 | ||
| 133 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 138 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 134 | protected OvsdbController controller; | 139 | protected OvsdbController controller; |
| ... | @@ -137,6 +142,12 @@ public class CordVtn implements CordVtnService { | ... | @@ -137,6 +142,12 @@ public class CordVtn implements CordVtnService { |
| 137 | protected ClusterService clusterService; | 142 | protected ClusterService clusterService; |
| 138 | 143 | ||
| 139 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 144 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 145 | + protected MastershipService mastershipService; | ||
| 146 | + | ||
| 147 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 148 | + protected GroupService groupService; | ||
| 149 | + | ||
| 150 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 140 | protected OpenstackSwitchingService openstackService; | 151 | protected OpenstackSwitchingService openstackService; |
| 141 | 152 | ||
| 142 | private final ExecutorService eventExecutor = Executors | 153 | private final ExecutorService eventExecutor = Executors |
| ... | @@ -149,8 +160,9 @@ public class CordVtn implements CordVtnService { | ... | @@ -149,8 +160,9 @@ public class CordVtn implements CordVtnService { |
| 149 | private final BridgeHandler bridgeHandler = new BridgeHandler(); | 160 | private final BridgeHandler bridgeHandler = new BridgeHandler(); |
| 150 | private final VmHandler vmHandler = new VmHandler(); | 161 | private final VmHandler vmHandler = new VmHandler(); |
| 151 | 162 | ||
| 163 | + private ApplicationId appId; | ||
| 152 | private ConsistentMap<CordVtnNode, NodeState> nodeStore; | 164 | private ConsistentMap<CordVtnNode, NodeState> nodeStore; |
| 153 | - private Map<HostId, String> hostNetworkMap = Maps.newHashMap(); | 165 | + private Map<HostId, OpenstackNetwork> hostNetMap = Maps.newHashMap(); |
| 154 | private CordVtnRuleInstaller ruleInstaller; | 166 | private CordVtnRuleInstaller ruleInstaller; |
| 155 | 167 | ||
| 156 | private enum NodeState { | 168 | private enum NodeState { |
| ... | @@ -198,15 +210,20 @@ public class CordVtn implements CordVtnService { | ... | @@ -198,15 +210,20 @@ public class CordVtn implements CordVtnService { |
| 198 | 210 | ||
| 199 | @Activate | 211 | @Activate |
| 200 | protected void activate() { | 212 | protected void activate() { |
| 201 | - ApplicationId appId = coreService.registerApplication("org.onosproject.cordvtn"); | 213 | + appId = coreService.registerApplication("org.onosproject.cordvtn"); |
| 202 | nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder() | 214 | nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder() |
| 203 | .withSerializer(Serializer.using(NODE_SERIALIZER.build())) | 215 | .withSerializer(Serializer.using(NODE_SERIALIZER.build())) |
| 204 | .withName("cordvtn-nodestore") | 216 | .withName("cordvtn-nodestore") |
| 205 | .withApplicationId(appId) | 217 | .withApplicationId(appId) |
| 206 | .build(); | 218 | .build(); |
| 207 | 219 | ||
| 208 | - ruleInstaller = new CordVtnRuleInstaller(appId, flowObjectiveService, | 220 | + ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService, |
| 209 | - driverService, DEFAULT_TUNNEL); | 221 | + deviceService, |
| 222 | + driverService, | ||
| 223 | + groupService, | ||
| 224 | + mastershipService, | ||
| 225 | + DEFAULT_TUNNEL); | ||
| 226 | + | ||
| 210 | deviceService.addListener(deviceListener); | 227 | deviceService.addListener(deviceListener); |
| 211 | hostService.addListener(hostListener); | 228 | hostService.addListener(hostListener); |
| 212 | 229 | ||
| ... | @@ -277,19 +294,29 @@ public class CordVtn implements CordVtnService { | ... | @@ -277,19 +294,29 @@ public class CordVtn implements CordVtnService { |
| 277 | } | 294 | } |
| 278 | 295 | ||
| 279 | @Override | 296 | @Override |
| 280 | - public void createServiceDependency(CordServiceId tenantCordServiceId, | 297 | + public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) { |
| 281 | - CordServiceId providerCordServiceId) { | 298 | + CordService tService = getCordService(tServiceId); |
| 282 | - CordService tenantService = getCordService(tenantCordServiceId); | 299 | + CordService pService = getCordService(pServiceId); |
| 283 | - CordService providerService = getCordService(providerCordServiceId); | ||
| 284 | 300 | ||
| 285 | - // TODO populate flow rules to create service dependency | 301 | + if (tService == null || pService == null) { |
| 302 | + log.error("Failed to create CordService for {}", tServiceId.id()); | ||
| 303 | + return; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + ruleInstaller.populateServiceDependencyRules(tService, pService); | ||
| 286 | } | 307 | } |
| 287 | 308 | ||
| 288 | @Override | 309 | @Override |
| 289 | - public void removeServiceDependency(CordServiceId tenantCordServiceId) { | 310 | + public void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) { |
| 290 | - CordService tenantService = getCordService(tenantCordServiceId); | 311 | + CordService tService = getCordService(tServiceId); |
| 312 | + CordService pService = getCordService(pServiceId); | ||
| 313 | + | ||
| 314 | + if (tService == null || pService == null) { | ||
| 315 | + log.error("Failed to create CordService for {}", tServiceId.id()); | ||
| 316 | + return; | ||
| 317 | + } | ||
| 291 | 318 | ||
| 292 | - //TODO uninstall flow rules to remove service dependency | 319 | + ruleInstaller.removeServiceDependencyRules(tService, pService); |
| 293 | } | 320 | } |
| 294 | 321 | ||
| 295 | /** | 322 | /** |
| ... | @@ -352,21 +379,13 @@ public class CordVtn implements CordVtnService { | ... | @@ -352,21 +379,13 @@ public class CordVtn implements CordVtnService { |
| 352 | * @param node cordvtn node | 379 | * @param node cordvtn node |
| 353 | */ | 380 | */ |
| 354 | private void postInit(CordVtnNode node) { | 381 | private void postInit(CordVtnNode node) { |
| 382 | + log.info("Initializing {}", node.hostname()); | ||
| 355 | disconnect(node); | 383 | disconnect(node); |
| 356 | 384 | ||
| 357 | - Set<OpenstackNetwork> vNets = Sets.newHashSet(); | 385 | + ruleInstaller.init(node.intBrId(), getTunnelPort(node.intBrId())); |
| 358 | hostService.getConnectedHosts(node.intBrId()) | 386 | hostService.getConnectedHosts(node.intBrId()) |
| 359 | .stream() | 387 | .stream() |
| 360 | - .forEach(host -> { | 388 | + .forEach(vmHandler::connected); |
| 361 | - OpenstackNetwork vNet = getOpenstackNetworkByHost(host); | ||
| 362 | - if (vNet != null) { | ||
| 363 | - log.info("VM {} is detected", host.id()); | ||
| 364 | - | ||
| 365 | - hostNetworkMap.put(host.id(), vNet.id()); | ||
| 366 | - vNets.add(vNet); | ||
| 367 | - } | ||
| 368 | - }); | ||
| 369 | - vNets.stream().forEach(this::installFlowRules); | ||
| 370 | } | 389 | } |
| 371 | 390 | ||
| 372 | /** | 391 | /** |
| ... | @@ -558,14 +577,14 @@ public class CordVtn implements CordVtnService { | ... | @@ -558,14 +577,14 @@ public class CordVtn implements CordVtnService { |
| 558 | * Returns tunnel port of the device. | 577 | * Returns tunnel port of the device. |
| 559 | * | 578 | * |
| 560 | * @param bridgeId device id | 579 | * @param bridgeId device id |
| 561 | - * @return port, null if no tunnel port exists on a given device | 580 | + * @return port number, null if no tunnel port exists on a given device |
| 562 | */ | 581 | */ |
| 563 | - private Port getTunnelPort(DeviceId bridgeId) { | 582 | + private PortNumber getTunnelPort(DeviceId bridgeId) { |
| 564 | try { | 583 | try { |
| 565 | return deviceService.getPorts(bridgeId).stream() | 584 | return deviceService.getPorts(bridgeId).stream() |
| 566 | .filter(p -> p.annotations().value("portName").contains(DEFAULT_TUNNEL) | 585 | .filter(p -> p.annotations().value("portName").contains(DEFAULT_TUNNEL) |
| 567 | && p.isEnabled()) | 586 | && p.isEnabled()) |
| 568 | - .findFirst().get(); | 587 | + .findFirst().get().number(); |
| 569 | } catch (NoSuchElementException e) { | 588 | } catch (NoSuchElementException e) { |
| 570 | return null; | 589 | return null; |
| 571 | } | 590 | } |
| ... | @@ -577,67 +596,17 @@ public class CordVtn implements CordVtnService { | ... | @@ -577,67 +596,17 @@ public class CordVtn implements CordVtnService { |
| 577 | * @param bridgeId device id | 596 | * @param bridgeId device id |
| 578 | * @return ip address, null if no such device exists | 597 | * @return ip address, null if no such device exists |
| 579 | */ | 598 | */ |
| 580 | - private IpAddress getRemoteIp(DeviceId bridgeId) { | 599 | + private Ip4Address getRemoteIp(DeviceId bridgeId) { |
| 581 | CordVtnNode node = getNodeByBridgeId(bridgeId); | 600 | CordVtnNode node = getNodeByBridgeId(bridgeId); |
| 582 | if (node != null) { | 601 | if (node != null) { |
| 583 | // TODO get data plane IP for tunneling | 602 | // TODO get data plane IP for tunneling |
| 584 | - return node.ovsdbIp(); | 603 | + return node.ovsdbIp().getIp4Address(); |
| 585 | } else { | 604 | } else { |
| 586 | return null; | 605 | return null; |
| 587 | } | 606 | } |
| 588 | } | 607 | } |
| 589 | 608 | ||
| 590 | /** | 609 | /** |
| 591 | - * Returns destination information of all ports associated with a given | ||
| 592 | - * OpenStack network. Output of the destination information is set to local | ||
| 593 | - * port or tunnel port according to a given device id. | ||
| 594 | - * | ||
| 595 | - * @param deviceId device id to install flow rules | ||
| 596 | - * @param vNet OpenStack network | ||
| 597 | - * @return list of flow information, empty list if no flow information exists | ||
| 598 | - */ | ||
| 599 | - private List<DestinationInfo> getSameNetworkPortsInfo(DeviceId deviceId, OpenstackNetwork vNet) { | ||
| 600 | - List<DestinationInfo> dstInfos = Lists.newArrayList(); | ||
| 601 | - long tunnelId = Long.valueOf(vNet.segmentId()); | ||
| 602 | - | ||
| 603 | - for (OpenstackPort vPort : openstackService.ports(vNet.id())) { | ||
| 604 | - ConnectPoint cp = getConnectPoint(vPort); | ||
| 605 | - if (cp == null) { | ||
| 606 | - log.debug("Couldn't find connection point for OpenStack port {}", vPort.id()); | ||
| 607 | - continue; | ||
| 608 | - } | ||
| 609 | - | ||
| 610 | - DestinationInfo.Builder dBuilder = cp.deviceId().equals(deviceId) ? | ||
| 611 | - DestinationInfo.builder(deviceService.getPort(cp.deviceId(), cp.port())) : | ||
| 612 | - DestinationInfo.builder(getTunnelPort(deviceId)) | ||
| 613 | - .setRemoteIp(getRemoteIp(cp.deviceId())); | ||
| 614 | - | ||
| 615 | - dBuilder.setMac(vPort.macAddress()) | ||
| 616 | - .setTunnelId(tunnelId); | ||
| 617 | - dstInfos.add(dBuilder.build()); | ||
| 618 | - } | ||
| 619 | - return dstInfos; | ||
| 620 | - } | ||
| 621 | - | ||
| 622 | - /** | ||
| 623 | - * Returns local ports associated with a given OpenStack network. | ||
| 624 | - * | ||
| 625 | - * @param bridgeId device id | ||
| 626 | - * @param vNet OpenStack network | ||
| 627 | - * @return port list, empty list if no port exists | ||
| 628 | - */ | ||
| 629 | - private List<Port> getLocalSameNetworkPorts(DeviceId bridgeId, OpenstackNetwork vNet) { | ||
| 630 | - List<Port> ports = new ArrayList<>(); | ||
| 631 | - openstackService.ports(vNet.id()).stream().forEach(port -> { | ||
| 632 | - ConnectPoint cp = getConnectPoint(port); | ||
| 633 | - if (cp != null && cp.deviceId().equals(bridgeId)) { | ||
| 634 | - ports.add(deviceService.getPort(cp.deviceId(), cp.port())); | ||
| 635 | - } | ||
| 636 | - }); | ||
| 637 | - return ports; | ||
| 638 | - } | ||
| 639 | - | ||
| 640 | - /** | ||
| 641 | * Returns OpenStack port associated with a given host. | 610 | * Returns OpenStack port associated with a given host. |
| 642 | * | 611 | * |
| 643 | * @param host host | 612 | * @param host host |
| ... | @@ -646,6 +615,10 @@ public class CordVtn implements CordVtnService { | ... | @@ -646,6 +615,10 @@ public class CordVtn implements CordVtnService { |
| 646 | private OpenstackPort getOpenstackPortByHost(Host host) { | 615 | private OpenstackPort getOpenstackPortByHost(Host host) { |
| 647 | Port port = deviceService.getPort(host.location().deviceId(), | 616 | Port port = deviceService.getPort(host.location().deviceId(), |
| 648 | host.location().port()); | 617 | host.location().port()); |
| 618 | + if (port == null) { | ||
| 619 | + log.debug("Failed to get port for {}", host.id()); | ||
| 620 | + return null; | ||
| 621 | + } | ||
| 649 | return openstackService.port(port); | 622 | return openstackService.port(port); |
| 650 | } | 623 | } |
| 651 | 624 | ||
| ... | @@ -665,6 +638,44 @@ public class CordVtn implements CordVtnService { | ... | @@ -665,6 +638,44 @@ public class CordVtn implements CordVtnService { |
| 665 | } | 638 | } |
| 666 | 639 | ||
| 667 | /** | 640 | /** |
| 641 | + * Returns hosts associated with a given OpenStack network. | ||
| 642 | + * | ||
| 643 | + * @param vNet openstack network | ||
| 644 | + * @return set of hosts | ||
| 645 | + */ | ||
| 646 | + private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) { | ||
| 647 | + checkNotNull(vNet); | ||
| 648 | + | ||
| 649 | + return openstackService.ports(vNet.id()).stream() | ||
| 650 | + .filter(port -> port.deviceOwner().contains("compute")) | ||
| 651 | + .map(port -> hostService.getHostsByMac(port.macAddress()) | ||
| 652 | + .stream() | ||
| 653 | + .findFirst() | ||
| 654 | + .orElse(null)) | ||
| 655 | + .collect(Collectors.toSet()); | ||
| 656 | + } | ||
| 657 | + | ||
| 658 | + /** | ||
| 659 | + * Returns host IP assigned by OpenStack. | ||
| 660 | + * | ||
| 661 | + * @param host host | ||
| 662 | + * @return IPv4 prefix, or null if it fails to get IP from OpenStack | ||
| 663 | + */ | ||
| 664 | + private IpAddress getHostIpFromOpenstack(Host host) { | ||
| 665 | + OpenstackPort vPort = getOpenstackPortByHost(host); | ||
| 666 | + | ||
| 667 | + if (vPort == null || vPort.fixedIps().isEmpty()) { | ||
| 668 | + log.error("Failed to get VM IP for {}", host.id()); | ||
| 669 | + return null; | ||
| 670 | + } | ||
| 671 | + // Assumes there's only one fixed IP is assigned to a port | ||
| 672 | + return (Ip4Address) vPort.fixedIps().values() | ||
| 673 | + .stream() | ||
| 674 | + .findFirst() | ||
| 675 | + .orElse(null); | ||
| 676 | + } | ||
| 677 | + | ||
| 678 | + /** | ||
| 668 | * Returns port name with OpenStack port information. | 679 | * Returns port name with OpenStack port information. |
| 669 | * | 680 | * |
| 670 | * @param vPort OpenStack port | 681 | * @param vPort OpenStack port |
| ... | @@ -676,27 +687,20 @@ public class CordVtn implements CordVtnService { | ... | @@ -676,27 +687,20 @@ public class CordVtn implements CordVtnService { |
| 676 | } | 687 | } |
| 677 | 688 | ||
| 678 | /** | 689 | /** |
| 679 | - * Returns connect point of a given OpenStack port. | 690 | + * Returns if the host is gateway interface. |
| 680 | - * It assumes there's only one physical port associated with an OpenStack port. | 691 | + * This codes should be removed after adding proxy arp for the gateway. |
| 681 | * | 692 | * |
| 682 | - * @param vPort openstack port | 693 | + * @param host host |
| 683 | - * @return connect point, null if no such port exists | 694 | + * @return true if the host is gateway |
| 684 | */ | 695 | */ |
| 685 | - private ConnectPoint getConnectPoint(OpenstackPort vPort) { | 696 | + private boolean isGateway(Host host) { |
| 686 | - try { | 697 | + Port port = deviceService.getPort(host.location().deviceId(), |
| 687 | - Host host = hostService.getHostsByMac(vPort.macAddress()) | 698 | + host.location().port()); |
| 688 | - .stream() | 699 | + return port.annotations().value("portName").contains(GWPORT_PREFIX); |
| 689 | - .findFirst() | ||
| 690 | - .get(); | ||
| 691 | - return new ConnectPoint(host.location().deviceId(), host.location().port()); | ||
| 692 | - } catch (NoSuchElementException e) { | ||
| 693 | - log.debug("Not a valid host with {}", vPort.macAddress()); | ||
| 694 | - return null; | ||
| 695 | - } | ||
| 696 | } | 700 | } |
| 697 | 701 | ||
| 698 | /** | 702 | /** |
| 699 | - * Returns OpenStack network associated with a given CORD service. | 703 | + * Returns CordService by service ID. |
| 700 | * | 704 | * |
| 701 | * @param serviceId service id | 705 | * @param serviceId service id |
| 702 | * @return cord service, or null if it fails to get network from OpenStack | 706 | * @return cord service, or null if it fails to get network from OpenStack |
| ... | @@ -708,73 +712,52 @@ public class CordVtn implements CordVtnService { | ... | @@ -708,73 +712,52 @@ public class CordVtn implements CordVtnService { |
| 708 | return null; | 712 | return null; |
| 709 | } | 713 | } |
| 710 | 714 | ||
| 711 | - // TODO create CordService with network/subnet information from Neutron | 715 | + OpenstackSubnet subnet = vNet.subnets().stream() |
| 712 | - return null; | 716 | + .findFirst() |
| 713 | - } | 717 | + .orElse(null); |
| 714 | - | 718 | + if (subnet == null) { |
| 715 | - /** | 719 | + log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id()); |
| 716 | - * Installs flow rules for a given OpenStack network. | 720 | + return null; |
| 717 | - * | 721 | + } |
| 718 | - * @param vNet OpenStack network | ||
| 719 | - */ | ||
| 720 | - private void installFlowRules(OpenstackNetwork vNet) { | ||
| 721 | - checkNotNull(vNet, "Tenant network should not be null"); | ||
| 722 | 722 | ||
| 723 | - for (Device device : deviceService.getAvailableDevices(SWITCH)) { | 723 | + Set<CordServiceId> tServices = Sets.newHashSet(); |
| 724 | - List<DestinationInfo> dstInfos = getSameNetworkPortsInfo(device.id(), vNet); | 724 | + // TODO get tenant services from XOS |
| 725 | 725 | ||
| 726 | - for (Port inPort : getLocalSameNetworkPorts(device.id(), vNet)) { | 726 | + Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet) |
| 727 | - List<DestinationInfo> localInInfos = dstInfos.stream() | 727 | + .stream() |
| 728 | - .filter(info -> !info.output().equals(inPort)) | 728 | + .collect(Collectors.toMap(host -> host, |
| 729 | - .collect(Collectors.toList()); | 729 | + host -> getRemoteIp(host.location().deviceId()))); |
| 730 | - ruleInstaller.installFlowRulesLocalIn(device.id(), inPort, localInInfos); | ||
| 731 | - } | ||
| 732 | 730 | ||
| 733 | - Port tunPort = getTunnelPort(device.id()); | 731 | + return new CordService(vNet, subnet, hosts, tServices); |
| 734 | - List<DestinationInfo> tunnelInInfos = dstInfos.stream() | ||
| 735 | - .filter(info -> !info.output().equals(tunPort)) | ||
| 736 | - .collect(Collectors.toList()); | ||
| 737 | - ruleInstaller.installFlowRulesTunnelIn(device.id(), tunPort, tunnelInInfos); | ||
| 738 | - } | ||
| 739 | } | 732 | } |
| 740 | 733 | ||
| 741 | /** | 734 | /** |
| 742 | - * Uninstalls flow rules associated with a given host for a given OpenStack network. | 735 | + * Returns CordService by OpenStack network. |
| 743 | * | 736 | * |
| 744 | * @param vNet OpenStack network | 737 | * @param vNet OpenStack network |
| 745 | - * @param host removed host | 738 | + * @return cord service |
| 746 | */ | 739 | */ |
| 747 | - private void uninstallFlowRules(OpenstackNetwork vNet, Host host) { | 740 | + private CordService getCordService(OpenstackNetwork vNet) { |
| 748 | - checkNotNull(vNet, "Tenant network should not be null"); | 741 | + checkNotNull(vNet); |
| 749 | - | 742 | + |
| 750 | - Port removedPort = deviceService.getPort(host.location().deviceId(), | 743 | + CordServiceId serviceId = CordServiceId.of(vNet.id()); |
| 751 | - host.location().port()); | 744 | + OpenstackSubnet subnet = vNet.subnets().stream() |
| 752 | - | 745 | + .findFirst() |
| 753 | - for (Device device : deviceService.getAvailableDevices(SWITCH)) { | 746 | + .orElse(null); |
| 754 | - List<DestinationInfo> dstInfos = getSameNetworkPortsInfo(device.id(), vNet); | 747 | + if (subnet == null) { |
| 755 | - | 748 | + log.warn("Couldn't find OpenStack subnet for service {}", serviceId); |
| 756 | - for (Port inPort : getLocalSameNetworkPorts(device.id(), vNet)) { | 749 | + return null; |
| 757 | - List<DestinationInfo> localInInfos = Lists.newArrayList( | 750 | + } |
| 758 | - DestinationInfo.builder(getTunnelPort(device.id())) | ||
| 759 | - .setTunnelId(Long.valueOf(vNet.segmentId())) | ||
| 760 | - .setMac(host.mac()) | ||
| 761 | - .setRemoteIp(getRemoteIp(host.location().deviceId())) | ||
| 762 | - .build()); | ||
| 763 | - ruleInstaller.uninstallFlowRules(device.id(), inPort, localInInfos); | ||
| 764 | - } | ||
| 765 | 751 | ||
| 766 | - if (device.id().equals(host.location().deviceId())) { | 752 | + Set<CordServiceId> tServices = Sets.newHashSet(); |
| 767 | - Port tunPort = getTunnelPort(device.id()); | 753 | + // TODO get tenant services from XOS |
| 768 | - List<DestinationInfo> tunnelInInfo = Lists.newArrayList( | ||
| 769 | - DestinationInfo.builder(removedPort) | ||
| 770 | - .setTunnelId(Long.valueOf(vNet.segmentId())) | ||
| 771 | - .setMac(host.mac()) | ||
| 772 | - .build()); | ||
| 773 | 754 | ||
| 774 | - ruleInstaller.uninstallFlowRules(device.id(), tunPort, tunnelInInfo); | 755 | + Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet) |
| 775 | - ruleInstaller.uninstallFlowRules(device.id(), removedPort, dstInfos); | 756 | + .stream() |
| 776 | - } | 757 | + .collect(Collectors.toMap(host -> host, |
| 777 | - } | 758 | + host -> getRemoteIp(host.location().deviceId()))); |
| 759 | + | ||
| 760 | + return new CordService(vNet, subnet, hosts, tServices); | ||
| 778 | } | 761 | } |
| 779 | 762 | ||
| 780 | private class InternalDeviceListener implements DeviceListener { | 763 | private class InternalDeviceListener implements DeviceListener { |
| ... | @@ -873,6 +856,7 @@ public class CordVtn implements CordVtnService { | ... | @@ -873,6 +856,7 @@ public class CordVtn implements CordVtnService { |
| 873 | * @param port port | 856 | * @param port port |
| 874 | */ | 857 | */ |
| 875 | public void portAdded(Port port) { | 858 | public void portAdded(Port port) { |
| 859 | + // TODO add host by updating network config | ||
| 876 | if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) { | 860 | if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) { |
| 877 | return; | 861 | return; |
| 878 | } | 862 | } |
| ... | @@ -891,6 +875,7 @@ public class CordVtn implements CordVtnService { | ... | @@ -891,6 +875,7 @@ public class CordVtn implements CordVtnService { |
| 891 | * @param port port | 875 | * @param port port |
| 892 | */ | 876 | */ |
| 893 | public void portRemoved(Port port) { | 877 | public void portRemoved(Port port) { |
| 878 | + // TODO remove host by updating network config | ||
| 894 | if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) { | 879 | if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) { |
| 895 | return; | 880 | return; |
| 896 | } | 881 | } |
| ... | @@ -907,8 +892,13 @@ public class CordVtn implements CordVtnService { | ... | @@ -907,8 +892,13 @@ public class CordVtn implements CordVtnService { |
| 907 | 892 | ||
| 908 | @Override | 893 | @Override |
| 909 | public void connected(Host host) { | 894 | public void connected(Host host) { |
| 895 | + // TODO remove check gateway here after applying network config host provider | ||
| 896 | + if (isGateway(host)) { | ||
| 897 | + return; | ||
| 898 | + } | ||
| 899 | + | ||
| 910 | CordVtnNode node = getNodeByBridgeId(host.location().deviceId()); | 900 | CordVtnNode node = getNodeByBridgeId(host.location().deviceId()); |
| 911 | - if (node == null || !getNodeState(node).equals(NodeState.COMPLETE)) { | 901 | + if (node == null || !Objects.equals(getNodeState(node), NodeState.COMPLETE)) { |
| 912 | // do nothing for the host on unregistered or unprepared device | 902 | // do nothing for the host on unregistered or unprepared device |
| 913 | return; | 903 | return; |
| 914 | } | 904 | } |
| ... | @@ -918,29 +908,43 @@ public class CordVtn implements CordVtnService { | ... | @@ -918,29 +908,43 @@ public class CordVtn implements CordVtnService { |
| 918 | return; | 908 | return; |
| 919 | } | 909 | } |
| 920 | 910 | ||
| 911 | + // TODO host ip should be set in host information after applying network config host provider | ||
| 912 | + IpAddress hostIp = getHostIpFromOpenstack(host); | ||
| 913 | + if (hostIp == null) { | ||
| 914 | + log.error("Failed to get host IP of {}", host.id()); | ||
| 915 | + return; | ||
| 916 | + } | ||
| 917 | + | ||
| 921 | log.info("VM {} is detected", host.id()); | 918 | log.info("VM {} is detected", host.id()); |
| 919 | + hostNetMap.put(host.id(), vNet); | ||
| 920 | + | ||
| 921 | + ruleInstaller.populateBasicConnectionRules( | ||
| 922 | + host, | ||
| 923 | + hostIp, | ||
| 924 | + checkNotNull(getRemoteIp(host.location().deviceId())).getIp4Address(), | ||
| 925 | + vNet); | ||
| 922 | 926 | ||
| 923 | - hostNetworkMap.put(host.id(), vNet.id()); | 927 | + // TODO add new VM to related service group if exists |
| 924 | - installFlowRules(vNet); | ||
| 925 | } | 928 | } |
| 926 | 929 | ||
| 927 | @Override | 930 | @Override |
| 928 | public void disconnected(Host host) { | 931 | public void disconnected(Host host) { |
| 929 | CordVtnNode node = getNodeByBridgeId(host.location().deviceId()); | 932 | CordVtnNode node = getNodeByBridgeId(host.location().deviceId()); |
| 930 | - if (node == null || !getNodeState(node).equals(NodeState.COMPLETE)) { | 933 | + if (node == null || !Objects.equals(getNodeState(node), NodeState.COMPLETE)) { |
| 931 | // do nothing for the host on unregistered or unprepared device | 934 | // do nothing for the host on unregistered or unprepared device |
| 932 | return; | 935 | return; |
| 933 | } | 936 | } |
| 934 | 937 | ||
| 935 | - OpenstackNetwork vNet = openstackService.network(hostNetworkMap.get(host.id())); | 938 | + OpenstackNetwork vNet = hostNetMap.get(host.id()); |
| 936 | if (vNet == null) { | 939 | if (vNet == null) { |
| 937 | return; | 940 | return; |
| 938 | } | 941 | } |
| 939 | 942 | ||
| 940 | log.info("VM {} is vanished", host.id()); | 943 | log.info("VM {} is vanished", host.id()); |
| 944 | + ruleInstaller.removeBasicConnectionRules(host); | ||
| 941 | 945 | ||
| 942 | - uninstallFlowRules(vNet, host); | 946 | + // TODO remove the VM from related service group if exists |
| 943 | - hostNetworkMap.remove(host.id()); | 947 | + hostNetMap.remove(host.id()); |
| 944 | } | 948 | } |
| 945 | } | 949 | } |
| 946 | } | 950 | } | ... | ... |
| ... | @@ -15,195 +15,859 @@ | ... | @@ -15,195 +15,859 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.cordvtn; | 16 | package org.onosproject.cordvtn; |
| 17 | 17 | ||
| 18 | +import com.google.common.collect.Lists; | ||
| 19 | +import com.google.common.collect.Maps; | ||
| 20 | +import org.onlab.packet.Ethernet; | ||
| 18 | import org.onlab.packet.Ip4Address; | 21 | import org.onlab.packet.Ip4Address; |
| 22 | +import org.onlab.packet.Ip4Prefix; | ||
| 23 | +import org.onlab.packet.IpAddress; | ||
| 24 | +import org.onlab.packet.IpPrefix; | ||
| 25 | +import org.onlab.packet.MacAddress; | ||
| 19 | import org.onlab.util.ItemNotFoundException; | 26 | import org.onlab.util.ItemNotFoundException; |
| 20 | import org.onosproject.core.ApplicationId; | 27 | import org.onosproject.core.ApplicationId; |
| 28 | +import org.onosproject.core.DefaultGroupId; | ||
| 29 | +import org.onosproject.core.GroupId; | ||
| 30 | +import org.onosproject.mastership.MastershipService; | ||
| 31 | +import org.onosproject.net.Device; | ||
| 21 | import org.onosproject.net.DeviceId; | 32 | import org.onosproject.net.DeviceId; |
| 22 | -import org.onosproject.net.Port; | 33 | +import org.onosproject.net.Host; |
| 34 | +import org.onosproject.net.PortNumber; | ||
| 23 | import org.onosproject.net.behaviour.ExtensionTreatmentResolver; | 35 | import org.onosproject.net.behaviour.ExtensionTreatmentResolver; |
| 36 | +import org.onosproject.net.device.DeviceService; | ||
| 24 | import org.onosproject.net.driver.DefaultDriverData; | 37 | import org.onosproject.net.driver.DefaultDriverData; |
| 25 | import org.onosproject.net.driver.DefaultDriverHandler; | 38 | import org.onosproject.net.driver.DefaultDriverHandler; |
| 26 | import org.onosproject.net.driver.Driver; | 39 | import org.onosproject.net.driver.Driver; |
| 27 | import org.onosproject.net.driver.DriverHandler; | 40 | import org.onosproject.net.driver.DriverHandler; |
| 28 | import org.onosproject.net.driver.DriverService; | 41 | import org.onosproject.net.driver.DriverService; |
| 42 | +import org.onosproject.net.flow.DefaultFlowRule; | ||
| 29 | import org.onosproject.net.flow.DefaultTrafficSelector; | 43 | import org.onosproject.net.flow.DefaultTrafficSelector; |
| 30 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 44 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
| 45 | +import org.onosproject.net.flow.FlowRule; | ||
| 46 | +import org.onosproject.net.flow.FlowRuleOperations; | ||
| 47 | +import org.onosproject.net.flow.FlowRuleOperationsContext; | ||
| 48 | +import org.onosproject.net.flow.FlowRuleService; | ||
| 31 | import org.onosproject.net.flow.TrafficSelector; | 49 | import org.onosproject.net.flow.TrafficSelector; |
| 32 | import org.onosproject.net.flow.TrafficTreatment; | 50 | import org.onosproject.net.flow.TrafficTreatment; |
| 51 | +import org.onosproject.net.flow.criteria.Criterion; | ||
| 52 | +import org.onosproject.net.flow.criteria.EthCriterion; | ||
| 53 | +import org.onosproject.net.flow.criteria.IPCriterion; | ||
| 54 | +import org.onosproject.net.flow.criteria.PortCriterion; | ||
| 33 | import org.onosproject.net.flow.instructions.ExtensionPropertyException; | 55 | import org.onosproject.net.flow.instructions.ExtensionPropertyException; |
| 34 | import org.onosproject.net.flow.instructions.ExtensionTreatment; | 56 | import org.onosproject.net.flow.instructions.ExtensionTreatment; |
| 35 | -import org.onosproject.net.flowobjective.DefaultForwardingObjective; | 57 | +import org.onosproject.net.flow.instructions.Instruction; |
| 36 | -import org.onosproject.net.flowobjective.FlowObjectiveService; | 58 | +import org.onosproject.net.flow.instructions.Instructions; |
| 37 | -import org.onosproject.net.flowobjective.ForwardingObjective; | 59 | +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; |
| 60 | +import org.onosproject.net.group.DefaultGroupBucket; | ||
| 61 | +import org.onosproject.net.group.DefaultGroupDescription; | ||
| 62 | +import org.onosproject.net.group.DefaultGroupKey; | ||
| 63 | +import org.onosproject.net.group.Group; | ||
| 64 | +import org.onosproject.net.group.GroupBucket; | ||
| 65 | +import org.onosproject.net.group.GroupBuckets; | ||
| 66 | +import org.onosproject.net.group.GroupDescription; | ||
| 67 | +import org.onosproject.net.group.GroupKey; | ||
| 68 | +import org.onosproject.net.group.GroupService; | ||
| 69 | +import org.onosproject.openstackswitching.OpenstackNetwork; | ||
| 70 | +import org.onosproject.openstackswitching.OpenstackSubnet; | ||
| 38 | import org.slf4j.Logger; | 71 | import org.slf4j.Logger; |
| 39 | 72 | ||
| 40 | import java.util.List; | 73 | import java.util.List; |
| 74 | +import java.util.Map; | ||
| 75 | +import java.util.NoSuchElementException; | ||
| 76 | +import java.util.Objects; | ||
| 77 | +import java.util.Set; | ||
| 78 | +import java.util.stream.Collectors; | ||
| 41 | 79 | ||
| 42 | -import static com.google.common.base.Preconditions.checkArgument; | ||
| 43 | import static com.google.common.base.Preconditions.checkNotNull; | 80 | import static com.google.common.base.Preconditions.checkNotNull; |
| 81 | +import static org.onosproject.net.Device.Type.SWITCH; | ||
| 82 | +import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT; | ||
| 83 | +import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST; | ||
| 84 | +import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC; | ||
| 44 | import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST; | 85 | import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST; |
| 86 | +import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST; | ||
| 45 | import static org.slf4j.LoggerFactory.getLogger; | 87 | import static org.slf4j.LoggerFactory.getLogger; |
| 46 | 88 | ||
| 47 | /** | 89 | /** |
| 48 | - * Populates rules for virtual tenant network. | 90 | + * Populates rules for CORD VTN service. |
| 49 | */ | 91 | */ |
| 50 | -public final class CordVtnRuleInstaller { | 92 | +public class CordVtnRuleInstaller { |
| 93 | + | ||
| 51 | protected final Logger log = getLogger(getClass()); | 94 | protected final Logger log = getLogger(getClass()); |
| 52 | 95 | ||
| 96 | + private static final int TABLE_IN_PORT = 0; | ||
| 97 | + private static final int TABLE_ACCESS_TYPE = 1; | ||
| 98 | + private static final int TABLE_IN_SERVICE = 2; | ||
| 99 | + private static final int TABLE_DST_IP = 3; | ||
| 100 | + private static final int TABLE_TUNNEL_IN = 4; | ||
| 101 | + | ||
| 53 | private static final int DEFAULT_PRIORITY = 5000; | 102 | private static final int DEFAULT_PRIORITY = 5000; |
| 103 | + private static final int LOWER_PRIORITY = 4000; | ||
| 104 | + private static final int LOWEST_PRIORITY = 0; | ||
| 54 | 105 | ||
| 55 | private final ApplicationId appId; | 106 | private final ApplicationId appId; |
| 56 | - private final FlowObjectiveService flowObjectiveService; | 107 | + private final FlowRuleService flowRuleService; |
| 108 | + private final DeviceService deviceService; | ||
| 57 | private final DriverService driverService; | 109 | private final DriverService driverService; |
| 110 | + private final GroupService groupService; | ||
| 111 | + private final MastershipService mastershipService; | ||
| 58 | private final String tunnelType; | 112 | private final String tunnelType; |
| 59 | 113 | ||
| 60 | /** | 114 | /** |
| 61 | - * Creates a new rule installer. | 115 | + * Creates a new rule populator. |
| 62 | * | 116 | * |
| 63 | * @param appId application id | 117 | * @param appId application id |
| 64 | - * @param flowObjectiveService flow objective service | 118 | + * @param flowRuleService flow rule service |
| 119 | + * @param deviceService device service | ||
| 65 | * @param driverService driver service | 120 | * @param driverService driver service |
| 66 | * @param tunnelType tunnel type | 121 | * @param tunnelType tunnel type |
| 67 | */ | 122 | */ |
| 68 | public CordVtnRuleInstaller(ApplicationId appId, | 123 | public CordVtnRuleInstaller(ApplicationId appId, |
| 69 | - FlowObjectiveService flowObjectiveService, | 124 | + FlowRuleService flowRuleService, |
| 125 | + DeviceService deviceService, | ||
| 70 | DriverService driverService, | 126 | DriverService driverService, |
| 127 | + GroupService groupService, | ||
| 128 | + MastershipService mastershipService, | ||
| 71 | String tunnelType) { | 129 | String tunnelType) { |
| 72 | this.appId = appId; | 130 | this.appId = appId; |
| 73 | - this.flowObjectiveService = flowObjectiveService; | 131 | + this.flowRuleService = flowRuleService; |
| 132 | + this.deviceService = deviceService; | ||
| 74 | this.driverService = driverService; | 133 | this.driverService = driverService; |
| 134 | + this.groupService = groupService; | ||
| 135 | + this.mastershipService = mastershipService; | ||
| 75 | this.tunnelType = checkNotNull(tunnelType); | 136 | this.tunnelType = checkNotNull(tunnelType); |
| 76 | } | 137 | } |
| 77 | 138 | ||
| 78 | /** | 139 | /** |
| 79 | - * Installs flow rules for tunnel in traffic. | 140 | + * Installs table miss rule to a give device. |
| 80 | * | 141 | * |
| 81 | - * @param deviceId device id to install flow rules | 142 | + * @param deviceId device id to install the rules |
| 82 | - * @param inPort in port | 143 | + * @param tunnelPort tunnel port number of the device |
| 83 | - * @param dstInfos list of destination info | 144 | + */ |
| 145 | + public void init(DeviceId deviceId, PortNumber tunnelPort) { | ||
| 146 | + // default is drop packets which can be accomplished without | ||
| 147 | + // a table miss entry for all table. | ||
| 148 | + populateTunnelInPortRule(deviceId, tunnelPort); | ||
| 149 | + processAccessTypeTable(deviceId); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + /** | ||
| 153 | + * Populates basic rules that connect a VM to the other VMs in the system. | ||
| 154 | + * | ||
| 155 | + * @param host host | ||
| 156 | + * @param hostIp host ip | ||
| 157 | + * @param tunnelIp tunnel ip | ||
| 158 | + * @param vNet openstack network | ||
| 159 | + */ | ||
| 160 | + public void populateBasicConnectionRules(Host host, IpAddress hostIp, IpAddress tunnelIp, | ||
| 161 | + OpenstackNetwork vNet) { | ||
| 162 | + // TODO we can get host ip from host.ip() after applying NetworkConfig host provider | ||
| 163 | + checkNotNull(host); | ||
| 164 | + checkNotNull(vNet); | ||
| 165 | + | ||
| 166 | + DeviceId deviceId = host.location().deviceId(); | ||
| 167 | + if (!mastershipService.isLocalMaster(deviceId)) { | ||
| 168 | + return; | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + PortNumber inPort = host.location().port(); | ||
| 172 | + MacAddress dstMac = host.mac(); | ||
| 173 | + long tunnelId = Long.parseLong(vNet.segmentId()); | ||
| 174 | + | ||
| 175 | + OpenstackSubnet subnet = vNet.subnets().stream() | ||
| 176 | + .findFirst() | ||
| 177 | + .orElse(null); | ||
| 178 | + | ||
| 179 | + if (subnet == null) { | ||
| 180 | + log.error("Failed to get subnet for {}", host.id()); | ||
| 181 | + return; | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + populateLocalInPortRule(deviceId, inPort, hostIp); | ||
| 185 | + populateDirectAccessRule(Ip4Prefix.valueOf(subnet.cidr()), Ip4Prefix.valueOf(subnet.cidr())); | ||
| 186 | + populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp); | ||
| 187 | + populateTunnelInRule(deviceId, inPort, dstMac, tunnelId); | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + /** | ||
| 191 | + * Populates service dependency rules. | ||
| 192 | + * | ||
| 193 | + * @param tService tenant cord service | ||
| 194 | + * @param pService provider cord service | ||
| 84 | */ | 195 | */ |
| 85 | - public void installFlowRulesTunnelIn(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) { | 196 | + public void populateServiceDependencyRules(CordService tService, CordService pService) { |
| 86 | - dstInfos.stream().forEach(dstInfo -> { | 197 | + checkNotNull(tService); |
| 87 | - ForwardingObjective.Builder fBuilder = vtnRulesSameNode(inPort, dstInfo); | 198 | + checkNotNull(pService); |
| 88 | - if (fBuilder != null) { | 199 | + |
| 89 | - flowObjectiveService.forward(deviceId, fBuilder.add()); | 200 | + Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix(); |
| 201 | + Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix(); | ||
| 202 | + Ip4Address serviceIp = pService.serviceIp().getIp4Address(); | ||
| 203 | + | ||
| 204 | + Map<DeviceId, GroupId> outGroups = Maps.newHashMap(); | ||
| 205 | + Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap(); | ||
| 206 | + | ||
| 207 | + for (Device device : deviceService.getAvailableDevices(SWITCH)) { | ||
| 208 | + GroupId groupId = createServiceGroup(device.id(), pService); | ||
| 209 | + outGroups.put(device.id(), groupId); | ||
| 210 | + | ||
| 211 | + Set<PortNumber> vms = tService.hosts().keySet() | ||
| 212 | + .stream() | ||
| 213 | + .filter(host -> host.location().deviceId().equals(device.id())) | ||
| 214 | + .map(host -> host.location().port()) | ||
| 215 | + .collect(Collectors.toSet()); | ||
| 216 | + inPorts.put(device.id(), vms); | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + populateIndirectAccessRule(srcRange, serviceIp, outGroups); | ||
| 220 | + populateDirectAccessRule(srcRange, dstRange); | ||
| 221 | + populateInServiceRule(inPorts, outGroups); | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + /** | ||
| 225 | + * Removes basic rules related to a given flow information. | ||
| 226 | + * | ||
| 227 | + * @param host host to be removed | ||
| 228 | + */ | ||
| 229 | + public void removeBasicConnectionRules(Host host) { | ||
| 230 | + checkNotNull(host); | ||
| 231 | + | ||
| 232 | + DeviceId deviceId = host.location().deviceId(); | ||
| 233 | + MacAddress mac = host.mac(); | ||
| 234 | + PortNumber port = host.location().port(); | ||
| 235 | + IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null); | ||
| 236 | + | ||
| 237 | + if (!mastershipService.isLocalMaster(deviceId)) { | ||
| 238 | + return; | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) { | ||
| 242 | + if (flowRule.deviceId().equals(deviceId)) { | ||
| 243 | + PortNumber inPort = getInPort(flowRule); | ||
| 244 | + if (inPort != null && inPort.equals(port)) { | ||
| 245 | + processFlowRule(false, flowRule); | ||
| 246 | + continue; | ||
| 247 | + } | ||
| 90 | } | 248 | } |
| 91 | - }); | 249 | + |
| 250 | + MacAddress dstMac = getDstMacFromTreatment(flowRule); | ||
| 251 | + if (dstMac != null && dstMac.equals(mac)) { | ||
| 252 | + processFlowRule(false, flowRule); | ||
| 253 | + continue; | ||
| 254 | + } | ||
| 255 | + | ||
| 256 | + dstMac = getDstMacFromSelector(flowRule); | ||
| 257 | + if (dstMac != null && dstMac.equals(mac)) { | ||
| 258 | + processFlowRule(false, flowRule); | ||
| 259 | + continue; | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + IpPrefix dstIp = getDstIpFromSelector(flowRule); | ||
| 263 | + if (dstIp != null && dstIp.equals(ip.toIpPrefix())) { | ||
| 264 | + processFlowRule(false, flowRule); | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + // TODO uninstall same network access rule in access table if no vm exists in the network | ||
| 92 | } | 270 | } |
| 93 | 271 | ||
| 94 | /** | 272 | /** |
| 95 | - * Installs flow rules for local in traffic. | 273 | + * Removes service dependency rules. |
| 96 | * | 274 | * |
| 97 | - * @param deviceId device id to install flow rules | 275 | + * @param tService tenant cord service |
| 98 | - * @param inPort in port | 276 | + * @param pService provider cord service |
| 99 | - * @param dstInfos list of destination info | ||
| 100 | */ | 277 | */ |
| 101 | - public void installFlowRulesLocalIn(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) { | 278 | + public void removeServiceDependencyRules(CordService tService, CordService pService) { |
| 102 | - dstInfos.stream().forEach(dstInfo -> { | 279 | + checkNotNull(tService); |
| 103 | - ForwardingObjective.Builder fBuilder = isTunnelPort(dstInfo.output()) ? | 280 | + checkNotNull(pService); |
| 104 | - vtnRulesRemoteNode(deviceId, inPort, dstInfo) : vtnRulesSameNode(inPort, dstInfo); | ||
| 105 | 281 | ||
| 106 | - if (fBuilder != null) { | 282 | + Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix(); |
| 107 | - flowObjectiveService.forward(deviceId, fBuilder.add()); | 283 | + Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix(); |
| 284 | + IpPrefix serviceIp = pService.serviceIp().toIpPrefix(); | ||
| 285 | + | ||
| 286 | + Map<DeviceId, GroupId> outGroups = Maps.newHashMap(); | ||
| 287 | + GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes()); | ||
| 288 | + | ||
| 289 | + deviceService.getAvailableDevices(SWITCH).forEach(device -> { | ||
| 290 | + Group group = groupService.getGroup(device.id(), groupKey); | ||
| 291 | + if (group != null) { | ||
| 292 | + outGroups.put(device.id(), group.id()); | ||
| 108 | } | 293 | } |
| 109 | }); | 294 | }); |
| 295 | + | ||
| 296 | + for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) { | ||
| 297 | + IpPrefix dstIp = getDstIpFromSelector(flowRule); | ||
| 298 | + IpPrefix srcIp = getSrcIpFromSelector(flowRule); | ||
| 299 | + | ||
| 300 | + if (dstIp != null && dstIp.equals(serviceIp)) { | ||
| 301 | + processFlowRule(false, flowRule); | ||
| 302 | + continue; | ||
| 303 | + } | ||
| 304 | + | ||
| 305 | + if (dstIp != null && srcIp != null) { | ||
| 306 | + if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) { | ||
| 307 | + processFlowRule(false, flowRule); | ||
| 308 | + continue; | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) { | ||
| 312 | + processFlowRule(false, flowRule); | ||
| 313 | + continue; | ||
| 314 | + } | ||
| 315 | + } | ||
| 316 | + | ||
| 317 | + GroupId groupId = getGroupIdFromTreatment(flowRule); | ||
| 318 | + if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) { | ||
| 319 | + processFlowRule(false, flowRule); | ||
| 320 | + } | ||
| 321 | + } | ||
| 322 | + | ||
| 323 | + // TODO remove the group if it is not in use | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + /** | ||
| 327 | + * Creates a new group for a given service. | ||
| 328 | + * | ||
| 329 | + * @param deviceId device id to create a group | ||
| 330 | + * @param service cord service | ||
| 331 | + * @return group id, or null if it fails to create | ||
| 332 | + */ | ||
| 333 | + private GroupId createServiceGroup(DeviceId deviceId, CordService service) { | ||
| 334 | + checkNotNull(service); | ||
| 335 | + | ||
| 336 | + GroupKey groupKey = getGroupKey(service.id()); | ||
| 337 | + Group group = groupService.getGroup(deviceId, groupKey); | ||
| 338 | + GroupId groupId = getGroupId(service.id(), deviceId); | ||
| 339 | + | ||
| 340 | + if (group != null) { | ||
| 341 | + log.debug("Group {} is already exist in {}", service.id(), deviceId); | ||
| 342 | + return groupId; | ||
| 343 | + } | ||
| 344 | + | ||
| 345 | + GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts()); | ||
| 346 | + GroupDescription groupDescription = new DefaultGroupDescription( | ||
| 347 | + deviceId, | ||
| 348 | + GroupDescription.Type.SELECT, | ||
| 349 | + buckets, | ||
| 350 | + groupKey, | ||
| 351 | + groupId.id(), | ||
| 352 | + appId); | ||
| 353 | + | ||
| 354 | + groupService.addGroup(groupDescription); | ||
| 355 | + | ||
| 356 | + return groupId; | ||
| 110 | } | 357 | } |
| 111 | 358 | ||
| 112 | /** | 359 | /** |
| 113 | - * Uninstalls flow rules associated with a given port from a given device. | 360 | + * Returns group buckets for a given device. |
| 114 | * | 361 | * |
| 115 | * @param deviceId device id | 362 | * @param deviceId device id |
| 116 | - * @param inPort port associated with removed host | 363 | + * @param tunnelId tunnel id |
| 117 | - * @param dstInfos list of destination info | 364 | + * @param hosts list of host |
| 365 | + * @return group buckets | ||
| 118 | */ | 366 | */ |
| 119 | - public void uninstallFlowRules(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) { | 367 | + private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) { |
| 120 | - dstInfos.stream().forEach(dstInfo -> { | 368 | + List<GroupBucket> buckets = Lists.newArrayList(); |
| 121 | - ForwardingObjective.Builder fBuilder = isTunnelPort(dstInfo.output()) ? | ||
| 122 | - vtnRulesRemoteNode(deviceId, inPort, dstInfo) : vtnRulesSameNode(inPort, dstInfo); | ||
| 123 | 369 | ||
| 124 | - if (fBuilder != null) { | 370 | + for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) { |
| 125 | - flowObjectiveService.forward(deviceId, fBuilder.remove()); | 371 | + Host host = entry.getKey(); |
| 372 | + Ip4Address remoteIp = entry.getValue().getIp4Address(); | ||
| 373 | + DeviceId hostDevice = host.location().deviceId(); | ||
| 374 | + | ||
| 375 | + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment | ||
| 376 | + .builder() | ||
| 377 | + .setEthDst(host.mac()); | ||
| 378 | + | ||
| 379 | + if (deviceId.equals(hostDevice)) { | ||
| 380 | + tBuilder.setOutput(host.location().port()); | ||
| 381 | + } else { | ||
| 382 | + ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp); | ||
| 383 | + if (tunnelDst == null) { | ||
| 384 | + continue; | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + tBuilder.extension(tunnelDst, deviceId) | ||
| 388 | + .setTunnelId(tunnelId) | ||
| 389 | + .setOutput(getTunnelPort(hostDevice)); | ||
| 126 | } | 390 | } |
| 127 | - }); | 391 | + |
| 392 | + buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); | ||
| 393 | + } | ||
| 394 | + | ||
| 395 | + return new GroupBuckets(buckets); | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + /** | ||
| 399 | + * Returns globally unique group ID. | ||
| 400 | + * | ||
| 401 | + * @param serviceId service id | ||
| 402 | + * @param deviceId device id | ||
| 403 | + * @return group id | ||
| 404 | + */ | ||
| 405 | + private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) { | ||
| 406 | + return new DefaultGroupId(Objects.hash(serviceId, deviceId)); | ||
| 128 | } | 407 | } |
| 129 | 408 | ||
| 130 | /** | 409 | /** |
| 131 | - * Returns forwarding objective builder to provision basic virtual tenant network. | 410 | + * Returns group key of a service. |
| 132 | - * This method cares for the traffics whose source and destination device is the same. | ||
| 133 | * | 411 | * |
| 412 | + * @param serviceId service id | ||
| 413 | + * @return group key | ||
| 414 | + */ | ||
| 415 | + private GroupKey getGroupKey(CordServiceId serviceId) { | ||
| 416 | + return new DefaultGroupKey(serviceId.id().getBytes()); | ||
| 417 | + } | ||
| 418 | + | ||
| 419 | + /** | ||
| 420 | + * Forward table miss rules in ACCESS_TYPE table to IN_SERVICE table. | ||
| 421 | + * | ||
| 422 | + * @param deviceId device id | ||
| 423 | + */ | ||
| 424 | + private void processAccessTypeTable(DeviceId deviceId) { | ||
| 425 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
| 426 | + .build(); | ||
| 427 | + | ||
| 428 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
| 429 | + .transition(TABLE_IN_SERVICE) | ||
| 430 | + .build(); | ||
| 431 | + | ||
| 432 | + FlowRule flowRule = DefaultFlowRule.builder() | ||
| 433 | + .fromApp(appId) | ||
| 434 | + .withSelector(selector) | ||
| 435 | + .withTreatment(treatment) | ||
| 436 | + .withPriority(LOWEST_PRIORITY) | ||
| 437 | + .forDevice(deviceId) | ||
| 438 | + .forTable(TABLE_ACCESS_TYPE) | ||
| 439 | + .makePermanent() | ||
| 440 | + .build(); | ||
| 441 | + | ||
| 442 | + processFlowRule(true, flowRule); | ||
| 443 | + } | ||
| 444 | + | ||
| 445 | + /** | ||
| 446 | + * Populates rules for tunnel flows in port in IN_PORT table. | ||
| 447 | + * All flows from tunnel port are forwarded to TUNNEL_ID table. | ||
| 448 | + * | ||
| 449 | + * @param deviceId device id to install the rules | ||
| 450 | + * @param tunnelPort tunnel port | ||
| 451 | + */ | ||
| 452 | + private void populateTunnelInPortRule(DeviceId deviceId, PortNumber tunnelPort) { | ||
| 453 | + checkNotNull(tunnelPort); | ||
| 454 | + | ||
| 455 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
| 456 | + .matchInPort(tunnelPort) | ||
| 457 | + .build(); | ||
| 458 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
| 459 | + .transition(TABLE_TUNNEL_IN) | ||
| 460 | + .build(); | ||
| 461 | + | ||
| 462 | + FlowRule flowRule = DefaultFlowRule.builder() | ||
| 463 | + .fromApp(appId) | ||
| 464 | + .withSelector(selector) | ||
| 465 | + .withTreatment(treatment) | ||
| 466 | + .withPriority(DEFAULT_PRIORITY) | ||
| 467 | + .forDevice(deviceId) | ||
| 468 | + .forTable(TABLE_IN_PORT) | ||
| 469 | + .makePermanent() | ||
| 470 | + .build(); | ||
| 471 | + | ||
| 472 | + processFlowRule(true, flowRule); | ||
| 473 | + } | ||
| 474 | + | ||
| 475 | + /** | ||
| 476 | + * Populates rules for local in port in IN_PORT table. | ||
| 477 | + * Flows from a given in port, whose source IP is service IP transition | ||
| 478 | + * to DST_TYPE table. Other flows transition to IN_SERVICE table. | ||
| 479 | + * | ||
| 480 | + * @param deviceId device id to install the rules | ||
| 134 | * @param inPort in port | 481 | * @param inPort in port |
| 135 | - * @param dstInfo destination information | 482 | + * @param srcIp source ip |
| 136 | - * @return forwarding objective builder | 483 | + */ |
| 484 | + private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) { | ||
| 485 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
| 486 | + .matchInPort(inPort) | ||
| 487 | + .matchEthType(Ethernet.TYPE_IPV4) | ||
| 488 | + .matchIPSrc(srcIp.toIpPrefix()) | ||
| 489 | + .build(); | ||
| 490 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
| 491 | + .transition(TABLE_ACCESS_TYPE) | ||
| 492 | + .build(); | ||
| 493 | + | ||
| 494 | + | ||
| 495 | + FlowRule flowRule = DefaultFlowRule.builder() | ||
| 496 | + .fromApp(appId) | ||
| 497 | + .withSelector(selector) | ||
| 498 | + .withTreatment(treatment) | ||
| 499 | + .withPriority(DEFAULT_PRIORITY) | ||
| 500 | + .forDevice(deviceId) | ||
| 501 | + .forTable(TABLE_IN_PORT) | ||
| 502 | + .makePermanent() | ||
| 503 | + .build(); | ||
| 504 | + | ||
| 505 | + processFlowRule(true, flowRule); | ||
| 506 | + | ||
| 507 | + selector = DefaultTrafficSelector.builder() | ||
| 508 | + .matchInPort(inPort) | ||
| 509 | + .build(); | ||
| 510 | + treatment = DefaultTrafficTreatment.builder() | ||
| 511 | + .transition(TABLE_IN_SERVICE) | ||
| 512 | + .build(); | ||
| 513 | + | ||
| 514 | + flowRule = DefaultFlowRule.builder() | ||
| 515 | + .fromApp(appId) | ||
| 516 | + .withSelector(selector) | ||
| 517 | + .withTreatment(treatment) | ||
| 518 | + .withPriority(LOWER_PRIORITY) | ||
| 519 | + .forDevice(deviceId) | ||
| 520 | + .forTable(TABLE_IN_PORT) | ||
| 521 | + .makePermanent() | ||
| 522 | + .build(); | ||
| 523 | + | ||
| 524 | + processFlowRule(true, flowRule); | ||
| 525 | + } | ||
| 526 | + | ||
| 527 | + /** | ||
| 528 | + * Populates direct VM access rules for ACCESS_TYPE table. | ||
| 529 | + * These rules are installed to all devices. | ||
| 530 | + * | ||
| 531 | + * @param srcRange source ip range | ||
| 532 | + * @param dstRange destination ip range | ||
| 533 | + */ | ||
| 534 | + private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) { | ||
| 535 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
| 536 | + .matchEthType(Ethernet.TYPE_IPV4) | ||
| 537 | + .matchIPSrc(srcRange) | ||
| 538 | + .matchIPDst(dstRange) | ||
| 539 | + .build(); | ||
| 540 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
| 541 | + .transition(TABLE_DST_IP) | ||
| 542 | + .build(); | ||
| 543 | + | ||
| 544 | + for (Device device : deviceService.getAvailableDevices(SWITCH)) { | ||
| 545 | + FlowRule flowRuleDirect = DefaultFlowRule.builder() | ||
| 546 | + .fromApp(appId) | ||
| 547 | + .withSelector(selector) | ||
| 548 | + .withTreatment(treatment) | ||
| 549 | + .withPriority(LOWER_PRIORITY) | ||
| 550 | + .forDevice(device.id()) | ||
| 551 | + .forTable(TABLE_ACCESS_TYPE) | ||
| 552 | + .makePermanent() | ||
| 553 | + .build(); | ||
| 554 | + | ||
| 555 | + processFlowRule(true, flowRuleDirect); | ||
| 556 | + } | ||
| 557 | + } | ||
| 558 | + | ||
| 559 | + /** | ||
| 560 | + * Populates indirect service access rules for ACCESS_TYPE table. | ||
| 561 | + * These rules are installed to all devices. | ||
| 562 | + * | ||
| 563 | + * @param srcRange source range | ||
| 564 | + * @param serviceIp service ip | ||
| 565 | + * @param outGroups list of output group | ||
| 137 | */ | 566 | */ |
| 138 | - private ForwardingObjective.Builder vtnRulesSameNode(Port inPort, DestinationInfo dstInfo) { | 567 | + private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp, |
| 139 | - checkArgument(inPort.element().id().equals(dstInfo.output().element().id())); | 568 | + Map<DeviceId, GroupId> outGroups) { |
| 569 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
| 570 | + .matchEthType(Ethernet.TYPE_IPV4) | ||
| 571 | + .matchIPSrc(srcRange) | ||
| 572 | + .matchIPDst(serviceIp.toIpPrefix()) | ||
| 573 | + .build(); | ||
| 574 | + | ||
| 575 | + for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) { | ||
| 576 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
| 577 | + .group(outGroup.getValue()) | ||
| 578 | + .build(); | ||
| 140 | 579 | ||
| 141 | - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); | 580 | + FlowRule flowRule = DefaultFlowRule.builder() |
| 142 | - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); | 581 | + .fromApp(appId) |
| 582 | + .withSelector(selector) | ||
| 583 | + .withTreatment(treatment) | ||
| 584 | + .withPriority(DEFAULT_PRIORITY) | ||
| 585 | + .forDevice(outGroup.getKey()) | ||
| 586 | + .forTable(TABLE_ACCESS_TYPE) | ||
| 587 | + .makePermanent() | ||
| 588 | + .build(); | ||
| 143 | 589 | ||
| 144 | - sBuilder.matchInPort(inPort.number()) | 590 | + processFlowRule(true, flowRule); |
| 145 | - .matchEthDst(dstInfo.mac()); | ||
| 146 | - if (isTunnelPort(inPort)) { | ||
| 147 | - sBuilder.matchTunnelId(dstInfo.tunnelId()); | ||
| 148 | } | 591 | } |
| 592 | + } | ||
| 149 | 593 | ||
| 150 | - tBuilder.setOutput(dstInfo.output().number()); | 594 | + /** |
| 595 | + * Populates flow rules for IN_SERVICE table. | ||
| 596 | + * | ||
| 597 | + * @param inPorts list of inports related to the service for each device | ||
| 598 | + * @param outGroups set of output groups | ||
| 599 | + */ | ||
| 600 | + private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) { | ||
| 601 | + checkNotNull(inPorts); | ||
| 602 | + checkNotNull(outGroups); | ||
| 151 | 603 | ||
| 152 | - return DefaultForwardingObjective.builder() | 604 | + for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) { |
| 153 | - .withSelector(sBuilder.build()) | 605 | + Set<PortNumber> ports = entry.getValue(); |
| 154 | - .withTreatment(tBuilder.build()) | 606 | + DeviceId deviceId = entry.getKey(); |
| 155 | - .withPriority(DEFAULT_PRIORITY) | 607 | + |
| 156 | - .withFlag(ForwardingObjective.Flag.VERSATILE) | 608 | + GroupId groupId = outGroups.get(deviceId); |
| 609 | + if (groupId == null) { | ||
| 610 | + continue; | ||
| 611 | + } | ||
| 612 | + | ||
| 613 | + ports.stream().forEach(port -> { | ||
| 614 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
| 615 | + .matchInPort(port) | ||
| 616 | + .build(); | ||
| 617 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
| 618 | + .group(groupId) | ||
| 619 | + .build(); | ||
| 620 | + | ||
| 621 | + FlowRule flowRule = DefaultFlowRule.builder() | ||
| 622 | + .fromApp(appId) | ||
| 623 | + .withSelector(selector) | ||
| 624 | + .withTreatment(treatment) | ||
| 625 | + .withPriority(DEFAULT_PRIORITY) | ||
| 626 | + .forDevice(deviceId) | ||
| 627 | + .forTable(TABLE_IN_SERVICE) | ||
| 628 | + .makePermanent() | ||
| 629 | + .build(); | ||
| 630 | + | ||
| 631 | + processFlowRule(true, flowRule); | ||
| 632 | + }); | ||
| 633 | + } | ||
| 634 | + } | ||
| 635 | + | ||
| 636 | + /** | ||
| 637 | + * Populates flow rules for DST_IP table. | ||
| 638 | + * | ||
| 639 | + * @param deviceId device id | ||
| 640 | + * @param inPort in port | ||
| 641 | + * @param dstMac mac address | ||
| 642 | + * @param dstIp destination ip | ||
| 643 | + * @param tunnelId tunnel id | ||
| 644 | + * @param tunnelIp tunnel remote ip | ||
| 645 | + */ | ||
| 646 | + private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac, | ||
| 647 | + IpAddress dstIp, long tunnelId, IpAddress tunnelIp) { | ||
| 648 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
| 649 | + .matchEthType(Ethernet.TYPE_IPV4) | ||
| 650 | + .matchIPDst(dstIp.toIpPrefix()) | ||
| 651 | + .build(); | ||
| 652 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
| 653 | + .setEthDst(dstMac) | ||
| 654 | + .setOutput(inPort) | ||
| 655 | + .build(); | ||
| 656 | + | ||
| 657 | + FlowRule flowRule = DefaultFlowRule.builder() | ||
| 157 | .fromApp(appId) | 658 | .fromApp(appId) |
| 158 | - .makePermanent(); | 659 | + .withSelector(selector) |
| 660 | + .withTreatment(treatment) | ||
| 661 | + .withPriority(DEFAULT_PRIORITY) | ||
| 662 | + .forDevice(deviceId) | ||
| 663 | + .forTable(TABLE_DST_IP) | ||
| 664 | + .makePermanent() | ||
| 665 | + .build(); | ||
| 666 | + | ||
| 667 | + processFlowRule(true, flowRule); | ||
| 668 | + | ||
| 669 | + for (Device device : deviceService.getAvailableDevices(SWITCH)) { | ||
| 670 | + if (device.id().equals(deviceId)) { | ||
| 671 | + continue; | ||
| 672 | + } | ||
| 673 | + | ||
| 674 | + ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address()); | ||
| 675 | + if (tunnelDst == null) { | ||
| 676 | + continue; | ||
| 677 | + } | ||
| 678 | + | ||
| 679 | + treatment = DefaultTrafficTreatment.builder() | ||
| 680 | + .setEthDst(dstMac) | ||
| 681 | + .setTunnelId(tunnelId) | ||
| 682 | + .extension(tunnelDst, device.id()) | ||
| 683 | + .setOutput(getTunnelPort(device.id())) | ||
| 684 | + .build(); | ||
| 685 | + | ||
| 686 | + flowRule = DefaultFlowRule.builder() | ||
| 687 | + .fromApp(appId) | ||
| 688 | + .withSelector(selector) | ||
| 689 | + .withTreatment(treatment) | ||
| 690 | + .withPriority(DEFAULT_PRIORITY) | ||
| 691 | + .forDevice(device.id()) | ||
| 692 | + .forTable(TABLE_DST_IP) | ||
| 693 | + .makePermanent() | ||
| 694 | + .build(); | ||
| 695 | + | ||
| 696 | + processFlowRule(true, flowRule); | ||
| 697 | + } | ||
| 159 | } | 698 | } |
| 160 | 699 | ||
| 161 | /** | 700 | /** |
| 162 | - * Returns forwarding objective builder to provision basic virtual tenant network. | 701 | + * Populates flow rules for TUNNEL_ID table. |
| 163 | - * This method cares for the traffics whose source and destination is not the same. | ||
| 164 | * | 702 | * |
| 165 | - * @param deviceId device id to install flow rules | 703 | + * @param deviceId device id |
| 166 | * @param inPort in port | 704 | * @param inPort in port |
| 167 | - * @param dstInfo destination information | 705 | + * @param mac mac address |
| 168 | - * @return forwarding objective, or null if it fails to build it | 706 | + * @param tunnelId tunnel id |
| 169 | */ | 707 | */ |
| 170 | - private ForwardingObjective.Builder vtnRulesRemoteNode(DeviceId deviceId, Port inPort, DestinationInfo dstInfo) { | 708 | + private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) { |
| 171 | - checkArgument(isTunnelPort(dstInfo.output())); | 709 | + TrafficSelector selector = DefaultTrafficSelector.builder() |
| 710 | + .matchTunnelId(tunnelId) | ||
| 711 | + .matchEthDst(mac) | ||
| 712 | + .build(); | ||
| 713 | + | ||
| 714 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
| 715 | + .setOutput(inPort) | ||
| 716 | + .build(); | ||
| 172 | 717 | ||
| 173 | - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); | 718 | + FlowRule flowRule = DefaultFlowRule.builder() |
| 174 | - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); | 719 | + .fromApp(appId) |
| 720 | + .withSelector(selector) | ||
| 721 | + .withTreatment(treatment) | ||
| 722 | + .withPriority(DEFAULT_PRIORITY) | ||
| 723 | + .forDevice(deviceId) | ||
| 724 | + .forTable(TABLE_TUNNEL_IN) | ||
| 725 | + .makePermanent() | ||
| 726 | + .build(); | ||
| 175 | 727 | ||
| 176 | - ExtensionTreatment extTreatment = | 728 | + processFlowRule(true, flowRule); |
| 177 | - getTunnelDstInstruction(deviceId, dstInfo.remoteIp().getIp4Address()); | 729 | + } |
| 178 | - if (extTreatment == null) { | 730 | + |
| 731 | + /** | ||
| 732 | + * Installs or uninstall a given rule. | ||
| 733 | + * | ||
| 734 | + * @param install true to install, false to uninstall | ||
| 735 | + * @param rule rule | ||
| 736 | + */ | ||
| 737 | + private void processFlowRule(boolean install, FlowRule rule) { | ||
| 738 | + FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder(); | ||
| 739 | + oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule); | ||
| 740 | + | ||
| 741 | + flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() { | ||
| 742 | + @Override | ||
| 743 | + public void onError(FlowRuleOperations ops) { | ||
| 744 | + log.error(String.format("Failed %s, %s", ops.toString(), rule.toString())); | ||
| 745 | + } | ||
| 746 | + })); | ||
| 747 | + } | ||
| 748 | + | ||
| 749 | + /** | ||
| 750 | + * Returns tunnel port of the device. | ||
| 751 | + * | ||
| 752 | + * @param deviceId device id | ||
| 753 | + * @return tunnel port number, or null if no tunnel port exists on a given device | ||
| 754 | + */ | ||
| 755 | + private PortNumber getTunnelPort(DeviceId deviceId) { | ||
| 756 | + try { | ||
| 757 | + return deviceService.getPorts(deviceId).stream() | ||
| 758 | + .filter(p -> p.annotations().value("portName").contains(tunnelType)) | ||
| 759 | + .findFirst().get().number(); | ||
| 760 | + } catch (NoSuchElementException e) { | ||
| 179 | return null; | 761 | return null; |
| 180 | } | 762 | } |
| 763 | + } | ||
| 181 | 764 | ||
| 182 | - sBuilder.matchInPort(inPort.number()) | 765 | + /** |
| 183 | - .matchEthDst(dstInfo.mac()); | 766 | + * Returns the inport from a given flow rule if the rule contains the match of it. |
| 767 | + * | ||
| 768 | + * @param flowRule flow rule | ||
| 769 | + * @return port number, or null if the rule doesn't have inport match | ||
| 770 | + */ | ||
| 771 | + private PortNumber getInPort(FlowRule flowRule) { | ||
| 772 | + Criterion criterion = flowRule.selector().getCriterion(IN_PORT); | ||
| 773 | + if (criterion != null && criterion instanceof PortCriterion) { | ||
| 774 | + PortCriterion port = (PortCriterion) criterion; | ||
| 775 | + return port.port(); | ||
| 776 | + } else { | ||
| 777 | + return null; | ||
| 778 | + } | ||
| 779 | + } | ||
| 184 | 780 | ||
| 185 | - tBuilder.extension(extTreatment, deviceId) | 781 | + /** |
| 186 | - .setTunnelId(dstInfo.tunnelId()) | 782 | + * Returns the destination mac address from a given flow rule if the rule |
| 187 | - .setOutput(dstInfo.output().number()); | 783 | + * contains the instruction of it. |
| 784 | + * | ||
| 785 | + * @param flowRule flow rule | ||
| 786 | + * @return mac address, or null if the rule doesn't have destination mac instruction | ||
| 787 | + */ | ||
| 788 | + private MacAddress getDstMacFromTreatment(FlowRule flowRule) { | ||
| 789 | + Instruction instruction = flowRule.treatment().allInstructions().stream() | ||
| 790 | + .filter(inst -> inst instanceof ModEtherInstruction && | ||
| 791 | + ((ModEtherInstruction) inst).subtype().equals(ETH_DST)) | ||
| 792 | + .findFirst() | ||
| 793 | + .orElse(null); | ||
| 188 | 794 | ||
| 189 | - return DefaultForwardingObjective.builder() | 795 | + if (instruction == null) { |
| 190 | - .withSelector(sBuilder.build()) | 796 | + return null; |
| 191 | - .withTreatment(tBuilder.build()) | 797 | + } |
| 192 | - .withPriority(DEFAULT_PRIORITY) | 798 | + |
| 193 | - .withFlag(ForwardingObjective.Flag.VERSATILE) | 799 | + return ((ModEtherInstruction) instruction).mac(); |
| 194 | - .fromApp(appId) | 800 | + } |
| 195 | - .makePermanent(); | 801 | + |
| 802 | + /** | ||
| 803 | + * Returns the destination mac address from a given flow rule if the rule | ||
| 804 | + * contains the match of it. | ||
| 805 | + * | ||
| 806 | + * @param flowRule flow rule | ||
| 807 | + * @return mac address, or null if the rule doesn't have destination mac match | ||
| 808 | + */ | ||
| 809 | + private MacAddress getDstMacFromSelector(FlowRule flowRule) { | ||
| 810 | + Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST); | ||
| 811 | + if (criterion != null && criterion instanceof EthCriterion) { | ||
| 812 | + EthCriterion eth = (EthCriterion) criterion; | ||
| 813 | + return eth.mac(); | ||
| 814 | + } else { | ||
| 815 | + return null; | ||
| 816 | + } | ||
| 196 | } | 817 | } |
| 197 | 818 | ||
| 198 | /** | 819 | /** |
| 199 | - * Checks if a given port is tunnel interface or not. | 820 | + * Returns the destination IP from a given flow rule if the rule contains |
| 200 | - * It assumes the tunnel interface contains tunnelType string in its name. | 821 | + * the match of it. |
| 201 | * | 822 | * |
| 202 | - * @param port port | 823 | + * @param flowRule flow rule |
| 203 | - * @return true if the port is tunnel interface, false otherwise. | 824 | + * @return ip prefix, or null if the rule doesn't have ip match |
| 204 | */ | 825 | */ |
| 205 | - private boolean isTunnelPort(Port port) { | 826 | + private IpPrefix getDstIpFromSelector(FlowRule flowRule) { |
| 206 | - return port.annotations().value("portName").contains(tunnelType); | 827 | + Criterion criterion = flowRule.selector().getCriterion(IPV4_DST); |
| 828 | + if (criterion != null && criterion instanceof IPCriterion) { | ||
| 829 | + IPCriterion ip = (IPCriterion) criterion; | ||
| 830 | + return ip.ip(); | ||
| 831 | + } else { | ||
| 832 | + return null; | ||
| 833 | + } | ||
| 834 | + } | ||
| 835 | + | ||
| 836 | + /** | ||
| 837 | + * Returns the source IP from a given flow rule if the rule contains | ||
| 838 | + * the match of it. | ||
| 839 | + * | ||
| 840 | + * @param flowRule flow rule | ||
| 841 | + * @return ip prefix, or null if the rule doesn't have ip match | ||
| 842 | + */ | ||
| 843 | + private IpPrefix getSrcIpFromSelector(FlowRule flowRule) { | ||
| 844 | + Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC); | ||
| 845 | + if (criterion != null && criterion instanceof IPCriterion) { | ||
| 846 | + IPCriterion ip = (IPCriterion) criterion; | ||
| 847 | + return ip.ip(); | ||
| 848 | + } else { | ||
| 849 | + return null; | ||
| 850 | + } | ||
| 851 | + } | ||
| 852 | + | ||
| 853 | + /** | ||
| 854 | + * Returns the group ID from a given flow rule if the rule contains the | ||
| 855 | + * treatment of it. | ||
| 856 | + * | ||
| 857 | + * @param flowRule flow rule | ||
| 858 | + * @return group id, or null if the rule doesn't have group instruction | ||
| 859 | + */ | ||
| 860 | + private GroupId getGroupIdFromTreatment(FlowRule flowRule) { | ||
| 861 | + Instruction instruction = flowRule.treatment().allInstructions().stream() | ||
| 862 | + .filter(inst -> inst instanceof Instructions.GroupInstruction) | ||
| 863 | + .findFirst() | ||
| 864 | + .orElse(null); | ||
| 865 | + | ||
| 866 | + if (instruction == null) { | ||
| 867 | + return null; | ||
| 868 | + } | ||
| 869 | + | ||
| 870 | + return ((Instructions.GroupInstruction) instruction).groupId(); | ||
| 207 | } | 871 | } |
| 208 | 872 | ||
| 209 | /** | 873 | /** |
| ... | @@ -213,19 +877,23 @@ public final class CordVtnRuleInstaller { | ... | @@ -213,19 +877,23 @@ public final class CordVtnRuleInstaller { |
| 213 | * @param remoteIp tunnel destination address | 877 | * @param remoteIp tunnel destination address |
| 214 | * @return extension treatment or null if it fails to get instruction | 878 | * @return extension treatment or null if it fails to get instruction |
| 215 | */ | 879 | */ |
| 216 | - private ExtensionTreatment getTunnelDstInstruction(DeviceId deviceId, Ip4Address remoteIp) { | 880 | + private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) { |
| 217 | try { | 881 | try { |
| 218 | Driver driver = driverService.getDriver(deviceId); | 882 | Driver driver = driverService.getDriver(deviceId); |
| 219 | - DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId)); | 883 | + DefaultDriverData driverData = new DefaultDriverData(driver, deviceId); |
| 220 | - ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class); | 884 | + DriverHandler handler = new DefaultDriverHandler(driverData); |
| 885 | + ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class); | ||
| 221 | 886 | ||
| 222 | - ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type()); | 887 | + ExtensionTreatment treatment = |
| 888 | + resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type()); | ||
| 223 | treatment.setPropertyValue("tunnelDst", remoteIp); | 889 | treatment.setPropertyValue("tunnelDst", remoteIp); |
| 224 | 890 | ||
| 225 | return treatment; | 891 | return treatment; |
| 226 | - } catch (ItemNotFoundException | UnsupportedOperationException | ExtensionPropertyException e) { | 892 | + } catch (ItemNotFoundException | UnsupportedOperationException | |
| 227 | - log.error("Failed to get extension instruction to set tunnel dst {}", deviceId); | 893 | + ExtensionPropertyException e) { |
| 894 | + log.error("Failed to get extension instruction {}", deviceId); | ||
| 228 | return null; | 895 | return null; |
| 229 | } | 896 | } |
| 230 | } | 897 | } |
| 231 | } | 898 | } |
| 899 | + | ... | ... |
| ... | @@ -69,15 +69,16 @@ public interface CordVtnService { | ... | @@ -69,15 +69,16 @@ public interface CordVtnService { |
| 69 | /** | 69 | /** |
| 70 | * Creates dependencies for a given tenant service. | 70 | * Creates dependencies for a given tenant service. |
| 71 | * | 71 | * |
| 72 | - * @param tenantCordServiceId id of the service which has a dependency | 72 | + * @param tServiceId id of the service which has a dependency |
| 73 | - * @param providerCordServiceId id of the service which provide dependency | 73 | + * @param pServiceId id of the service which provide dependency |
| 74 | */ | 74 | */ |
| 75 | - void createServiceDependency(CordServiceId tenantCordServiceId, CordServiceId providerCordServiceId); | 75 | + void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId); |
| 76 | 76 | ||
| 77 | /** | 77 | /** |
| 78 | * Removes all dependencies from a given tenant service. | 78 | * Removes all dependencies from a given tenant service. |
| 79 | * | 79 | * |
| 80 | - * @param tenantCordServiceId id of the service which has a dependency | 80 | + * @param tServiceId id of the service which has a dependency |
| 81 | + * @param pServiceId id of the service which provide dependency | ||
| 81 | */ | 82 | */ |
| 82 | - void removeServiceDependency(CordServiceId tenantCordServiceId); | 83 | + void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId); |
| 83 | } | 84 | } | ... | ... |
| 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.cordvtn; | ||
| 17 | - | ||
| 18 | -import org.onlab.packet.IpAddress; | ||
| 19 | -import org.onlab.packet.MacAddress; | ||
| 20 | -import org.onosproject.net.Port; | ||
| 21 | - | ||
| 22 | -import java.util.List; | ||
| 23 | - | ||
| 24 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
| 25 | - | ||
| 26 | -/** | ||
| 27 | - * Contains destination information. | ||
| 28 | - */ | ||
| 29 | -public final class DestinationInfo { | ||
| 30 | - | ||
| 31 | - private final Port output; | ||
| 32 | - private final List<IpAddress> ip; | ||
| 33 | - private final MacAddress mac; | ||
| 34 | - private final IpAddress remoteIp; | ||
| 35 | - private final long tunnelId; | ||
| 36 | - | ||
| 37 | - /** | ||
| 38 | - * Creates a new destination information. | ||
| 39 | - * | ||
| 40 | - * @param output output port | ||
| 41 | - * @param ip destination ip address | ||
| 42 | - * @param mac destination mac address | ||
| 43 | - * @param remoteIp tunnel remote ip address | ||
| 44 | - * @param tunnelId segment id | ||
| 45 | - */ | ||
| 46 | - public DestinationInfo(Port output, List<IpAddress> ip, MacAddress mac, | ||
| 47 | - IpAddress remoteIp, long tunnelId) { | ||
| 48 | - this.output = checkNotNull(output); | ||
| 49 | - this.ip = ip; | ||
| 50 | - this.mac = mac; | ||
| 51 | - this.remoteIp = remoteIp; | ||
| 52 | - this.tunnelId = tunnelId; | ||
| 53 | - } | ||
| 54 | - | ||
| 55 | - /** | ||
| 56 | - * Returns output port. | ||
| 57 | - * | ||
| 58 | - * @return port | ||
| 59 | - */ | ||
| 60 | - public Port output() { | ||
| 61 | - return output; | ||
| 62 | - } | ||
| 63 | - | ||
| 64 | - /** | ||
| 65 | - * Returns destination ip addresses. | ||
| 66 | - * | ||
| 67 | - * @return list of ip address | ||
| 68 | - */ | ||
| 69 | - public List<IpAddress> ip() { | ||
| 70 | - return ip; | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - /** | ||
| 74 | - * Returns destination mac address. | ||
| 75 | - * | ||
| 76 | - * @return mac address | ||
| 77 | - */ | ||
| 78 | - public MacAddress mac() { | ||
| 79 | - return mac; | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - /** | ||
| 83 | - * Returns tunnel remote ip address. | ||
| 84 | - * | ||
| 85 | - * @return ip address | ||
| 86 | - */ | ||
| 87 | - public IpAddress remoteIp() { | ||
| 88 | - return remoteIp; | ||
| 89 | - } | ||
| 90 | - | ||
| 91 | - /** | ||
| 92 | - * Returns tunnel id. | ||
| 93 | - * | ||
| 94 | - * @return tunnel id | ||
| 95 | - */ | ||
| 96 | - public long tunnelId() { | ||
| 97 | - return tunnelId; | ||
| 98 | - } | ||
| 99 | - | ||
| 100 | - /** | ||
| 101 | - * Returns a new destination info builder. | ||
| 102 | - * | ||
| 103 | - * @return destination info builder | ||
| 104 | - */ | ||
| 105 | - public static DestinationInfo.Builder builder(Port output) { | ||
| 106 | - return new Builder(output); | ||
| 107 | - } | ||
| 108 | - | ||
| 109 | - /** | ||
| 110 | - * DestinationInfo builder class. | ||
| 111 | - */ | ||
| 112 | - public static final class Builder { | ||
| 113 | - | ||
| 114 | - private final Port output; | ||
| 115 | - private List<IpAddress> ip; | ||
| 116 | - private MacAddress mac; | ||
| 117 | - private IpAddress remoteIp; | ||
| 118 | - private long tunnelId; | ||
| 119 | - | ||
| 120 | - /** | ||
| 121 | - * Creates a new destination information builder. | ||
| 122 | - * | ||
| 123 | - * @param output output port | ||
| 124 | - */ | ||
| 125 | - public Builder(Port output) { | ||
| 126 | - this.output = checkNotNull(output, "Output port cannot be null"); | ||
| 127 | - } | ||
| 128 | - | ||
| 129 | - /** | ||
| 130 | - * Sets the destination ip address. | ||
| 131 | - * | ||
| 132 | - * @param ip ip address | ||
| 133 | - * @return destination info builder | ||
| 134 | - */ | ||
| 135 | - public Builder setIp(List<IpAddress> ip) { | ||
| 136 | - this.ip = checkNotNull(ip, "IP cannot be null"); | ||
| 137 | - return this; | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | - /** | ||
| 141 | - * Sets the destination mac address. | ||
| 142 | - * | ||
| 143 | - * @param mac mac address | ||
| 144 | - * @return destination info builder | ||
| 145 | - */ | ||
| 146 | - public Builder setMac(MacAddress mac) { | ||
| 147 | - this.mac = checkNotNull(mac, "MAC address cannot be null"); | ||
| 148 | - return this; | ||
| 149 | - } | ||
| 150 | - | ||
| 151 | - /** | ||
| 152 | - * Sets the tunnel remote ip address. | ||
| 153 | - * | ||
| 154 | - * @param remoteIp ip address | ||
| 155 | - * @return destination info builder | ||
| 156 | - */ | ||
| 157 | - public Builder setRemoteIp(IpAddress remoteIp) { | ||
| 158 | - this.remoteIp = checkNotNull(remoteIp, "Remote IP address cannot be null"); | ||
| 159 | - return this; | ||
| 160 | - } | ||
| 161 | - | ||
| 162 | - /** | ||
| 163 | - * Sets the tunnel id. | ||
| 164 | - * | ||
| 165 | - * @param tunnelId tunnel id | ||
| 166 | - * @return destination info builder | ||
| 167 | - */ | ||
| 168 | - public Builder setTunnelId(long tunnelId) { | ||
| 169 | - this.tunnelId = checkNotNull(tunnelId, "Tunnel ID cannot be null"); | ||
| 170 | - return this; | ||
| 171 | - } | ||
| 172 | - | ||
| 173 | - /** | ||
| 174 | - * Build a destination information. | ||
| 175 | - * | ||
| 176 | - * @return destination info object | ||
| 177 | - */ | ||
| 178 | - public DestinationInfo build() { | ||
| 179 | - return new DestinationInfo(this); | ||
| 180 | - } | ||
| 181 | - } | ||
| 182 | - | ||
| 183 | - private DestinationInfo(Builder builder) { | ||
| 184 | - output = builder.output; | ||
| 185 | - ip = builder.ip; | ||
| 186 | - mac = builder.mac; | ||
| 187 | - remoteIp = builder.remoteIp; | ||
| 188 | - tunnelId = builder.tunnelId; | ||
| 189 | - } | ||
| 190 | -} |
| ... | @@ -58,14 +58,16 @@ public class ServiceDependencyWebResource extends AbstractWebResource { | ... | @@ -58,14 +58,16 @@ public class ServiceDependencyWebResource extends AbstractWebResource { |
| 58 | /** | 58 | /** |
| 59 | * Removes service dependencies. | 59 | * Removes service dependencies. |
| 60 | * | 60 | * |
| 61 | - * @param serviceId service id | 61 | + * @param tServiceId tenant service id |
| 62 | + * @param pServiceId provider service id | ||
| 62 | * @return 200 OK, or 400 Bad Request | 63 | * @return 200 OK, or 400 Bad Request |
| 63 | */ | 64 | */ |
| 64 | @DELETE | 65 | @DELETE |
| 65 | - @Path("{serviceId}") | 66 | + @Path("{tenantServiceId}/{providerServiceId}") |
| 66 | @Produces(MediaType.APPLICATION_JSON) | 67 | @Produces(MediaType.APPLICATION_JSON) |
| 67 | - public Response removeServiceDependency(@PathParam("serviceId") String serviceId) { | 68 | + public Response removeServiceDependency(@PathParam("tenantServiceId") String tServiceId, |
| 68 | - service.removeServiceDependency(CordServiceId.of(serviceId)); | 69 | + @PathParam("providerServiceId") String pServiceId) { |
| 70 | + service.removeServiceDependency(CordServiceId.of(tServiceId), CordServiceId.of(pServiceId)); | ||
| 69 | return Response.status(Response.Status.OK).build(); | 71 | return Response.status(Response.Status.OK).build(); |
| 70 | } | 72 | } |
| 71 | 73 | ... | ... |
-
Please register or login to post a comment