Hyunsun Moon

[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
...@@ -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); 300 +
301 + if (tService == null || pService == null) {
302 + log.error("Failed to create CordService for {}", tServiceId.id());
303 + return;
304 + }
284 305
285 - // TODO populate flow rules to create service dependency 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()
716 + .findFirst()
717 + .orElse(null);
718 + if (subnet == null) {
719 + log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
712 return null; 720 return null;
713 } 721 }
714 722
715 - /** 723 + Set<CordServiceId> tServices = Sets.newHashSet();
716 - * Installs flow rules for a given OpenStack network. 724 + // TODO get tenant services from XOS
717 - *
718 - * @param vNet OpenStack network
719 - */
720 - private void installFlowRules(OpenstackNetwork vNet) {
721 - checkNotNull(vNet, "Tenant network should not be null");
722 -
723 - for (Device device : deviceService.getAvailableDevices(SWITCH)) {
724 - List<DestinationInfo> dstInfos = getSameNetworkPortsInfo(device.id(), vNet);
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 -
750 - Port removedPort = deviceService.getPort(host.location().deviceId(),
751 - host.location().port());
752 742
753 - for (Device device : deviceService.getAvailableDevices(SWITCH)) { 743 + CordServiceId serviceId = CordServiceId.of(vNet.id());
754 - List<DestinationInfo> dstInfos = getSameNetworkPortsInfo(device.id(), vNet); 744 + OpenstackSubnet subnet = vNet.subnets().stream()
755 - 745 + .findFirst()
756 - for (Port inPort : getLocalSameNetworkPorts(device.id(), vNet)) { 746 + .orElse(null);
757 - List<DestinationInfo> localInInfos = Lists.newArrayList( 747 + if (subnet == null) {
758 - DestinationInfo.builder(getTunnelPort(device.id())) 748 + log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
759 - .setTunnelId(Long.valueOf(vNet.segmentId())) 749 + return null;
760 - .setMac(host.mac())
761 - .setRemoteIp(getRemoteIp(host.location().deviceId()))
762 - .build());
763 - ruleInstaller.uninstallFlowRules(device.id(), inPort, localInInfos);
764 } 750 }
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
84 */ 144 */
85 - public void installFlowRulesTunnelIn(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) { 145 + public void init(DeviceId deviceId, PortNumber tunnelPort) {
86 - dstInfos.stream().forEach(dstInfo -> { 146 + // default is drop packets which can be accomplished without
87 - ForwardingObjective.Builder fBuilder = vtnRulesSameNode(inPort, dstInfo); 147 + // a table miss entry for all table.
88 - if (fBuilder != null) { 148 + populateTunnelInPortRule(deviceId, tunnelPort);
89 - flowObjectiveService.forward(deviceId, fBuilder.add()); 149 + processAccessTypeTable(deviceId);
90 } 150 }
91 - }); 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);
92 } 188 }
93 189
94 /** 190 /**
95 - * Installs flow rules for local in traffic. 191 + * Populates service dependency rules.
96 * 192 *
97 - * @param deviceId device id to install flow rules 193 + * @param tService tenant cord service
98 - * @param inPort in port 194 + * @param pService provider cord service
99 - * @param dstInfos list of destination info 195 + */
196 + public void populateServiceDependencyRules(CordService tService, CordService pService) {
197 + checkNotNull(tService);
198 + checkNotNull(pService);
199 +
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
100 */ 228 */
101 - public void installFlowRulesLocalIn(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) { 229 + public void removeBasicConnectionRules(Host host) {
102 - dstInfos.stream().forEach(dstInfo -> { 230 + checkNotNull(host);
103 - ForwardingObjective.Builder fBuilder = isTunnelPort(dstInfo.output()) ? 231 +
104 - vtnRulesRemoteNode(deviceId, inPort, dstInfo) : vtnRulesSameNode(inPort, dstInfo); 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);
105 236
106 - if (fBuilder != null) { 237 + if (!mastershipService.isLocalMaster(deviceId)) {
107 - flowObjectiveService.forward(deviceId, fBuilder.add()); 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 + }
248 + }
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
270 + }
271 +
272 + /**
273 + * Removes service dependency rules.
274 + *
275 + * @param tService tenant cord service
276 + * @param pService provider cord service
277 + */
278 + public void removeServiceDependencyRules(CordService tService, CordService pService) {
279 + checkNotNull(tService);
280 + checkNotNull(pService);
281 +
282 + Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
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()) ? 369 +
122 - vtnRulesRemoteNode(deviceId, inPort, dstInfo) : vtnRulesSameNode(inPort, dstInfo); 370 + for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
371 + Host host = entry.getKey();
372 + Ip4Address remoteIp = entry.getValue().getIp4Address();
373 + DeviceId hostDevice = host.location().deviceId();
123 374
124 - if (fBuilder != null) { 375 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
125 - flowObjectiveService.forward(deviceId, fBuilder.remove()); 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;
126 } 385 }
127 - }); 386 +
387 + tBuilder.extension(tunnelDst, deviceId)
388 + .setTunnelId(tunnelId)
389 + .setOutput(getTunnelPort(hostDevice));
390 + }
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));
407 + }
408 +
409 + /**
410 + * Returns group key of a service.
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);
128 } 473 }
129 474
130 /** 475 /**
131 - * Returns forwarding objective builder to provision basic virtual tenant network. 476 + * Populates rules for local in port in IN_PORT table.
132 - * This method cares for the traffics whose source and destination device is the same. 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.
133 * 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
137 */ 533 */
138 - private ForwardingObjective.Builder vtnRulesSameNode(Port inPort, DestinationInfo dstInfo) { 534 + private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
139 - checkArgument(inPort.element().id().equals(dstInfo.output().element().id())); 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();
140 543
141 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); 544 + for (Device device : deviceService.getAvailableDevices(SWITCH)) {
142 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); 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();
143 554
144 - sBuilder.matchInPort(inPort.number()) 555 + processFlowRule(true, flowRuleDirect);
145 - .matchEthDst(dstInfo.mac()); 556 + }
146 - if (isTunnelPort(inPort)) {
147 - sBuilder.matchTunnelId(dstInfo.tunnelId());
148 } 557 }
149 558
150 - tBuilder.setOutput(dstInfo.output().number()); 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
566 + */
567 + private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
568 + Map<DeviceId, GroupId> outGroups) {
569 + TrafficSelector selector = DefaultTrafficSelector.builder()
570 + .matchEthType(Ethernet.TYPE_IPV4)
571 + .matchIPSrc(srcRange)
572 + .matchIPDst(serviceIp.toIpPrefix())
573 + .build();
151 574
152 - return DefaultForwardingObjective.builder() 575 + for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
153 - .withSelector(sBuilder.build()) 576 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
154 - .withTreatment(tBuilder.build()) 577 + .group(outGroup.getValue())
578 + .build();
579 +
580 + FlowRule flowRule = DefaultFlowRule.builder()
581 + .fromApp(appId)
582 + .withSelector(selector)
583 + .withTreatment(treatment)
155 .withPriority(DEFAULT_PRIORITY) 584 .withPriority(DEFAULT_PRIORITY)
156 - .withFlag(ForwardingObjective.Flag.VERSATILE) 585 + .forDevice(outGroup.getKey())
586 + .forTable(TABLE_ACCESS_TYPE)
587 + .makePermanent()
588 + .build();
589 +
590 + processFlowRule(true, flowRule);
591 + }
592 + }
593 +
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);
603 +
604 + for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
605 + Set<PortNumber> ports = entry.getValue();
606 + DeviceId deviceId = entry.getKey();
607 +
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()
157 .fromApp(appId) 622 .fromApp(appId)
158 - .makePermanent(); 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 + }
159 } 634 }
160 635
161 /** 636 /**
162 - * Returns forwarding objective builder to provision basic virtual tenant network. 637 + * Populates flow rules for DST_IP table.
163 - * This method cares for the traffics whose source and destination is not the same.
164 * 638 *
165 - * @param deviceId device id to install flow rules 639 + * @param deviceId device id
166 * @param inPort in port 640 * @param inPort in port
167 - * @param dstInfo destination information 641 + * @param dstMac mac address
168 - * @return forwarding objective, or null if it fails to build it 642 + * @param dstIp destination ip
643 + * @param tunnelId tunnel id
644 + * @param tunnelIp tunnel remote ip
169 */ 645 */
170 - private ForwardingObjective.Builder vtnRulesRemoteNode(DeviceId deviceId, Port inPort, DestinationInfo dstInfo) { 646 + private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
171 - checkArgument(isTunnelPort(dstInfo.output())); 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();
172 656
173 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); 657 + FlowRule flowRule = DefaultFlowRule.builder()
174 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); 658 + .fromApp(appId)
659 + .withSelector(selector)
660 + .withTreatment(treatment)
661 + .withPriority(DEFAULT_PRIORITY)
662 + .forDevice(deviceId)
663 + .forTable(TABLE_DST_IP)
664 + .makePermanent()
665 + .build();
175 666
176 - ExtensionTreatment extTreatment = 667 + processFlowRule(true, flowRule);
177 - getTunnelDstInstruction(deviceId, dstInfo.remoteIp().getIp4Address()); 668 +
178 - if (extTreatment == null) { 669 + for (Device device : deviceService.getAvailableDevices(SWITCH)) {
179 - return null; 670 + if (device.id().equals(deviceId)) {
671 + continue;
180 } 672 }
181 673
182 - sBuilder.matchInPort(inPort.number()) 674 + ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
183 - .matchEthDst(dstInfo.mac()); 675 + if (tunnelDst == null) {
676 + continue;
677 + }
184 678
185 - tBuilder.extension(extTreatment, deviceId) 679 + treatment = DefaultTrafficTreatment.builder()
186 - .setTunnelId(dstInfo.tunnelId()) 680 + .setEthDst(dstMac)
187 - .setOutput(dstInfo.output().number()); 681 + .setTunnelId(tunnelId)
682 + .extension(tunnelDst, device.id())
683 + .setOutput(getTunnelPort(device.id()))
684 + .build();
188 685
189 - return DefaultForwardingObjective.builder() 686 + flowRule = DefaultFlowRule.builder()
190 - .withSelector(sBuilder.build()) 687 + .fromApp(appId)
191 - .withTreatment(tBuilder.build()) 688 + .withSelector(selector)
689 + .withTreatment(treatment)
192 .withPriority(DEFAULT_PRIORITY) 690 .withPriority(DEFAULT_PRIORITY)
193 - .withFlag(ForwardingObjective.Flag.VERSATILE) 691 + .forDevice(device.id())
692 + .forTable(TABLE_DST_IP)
693 + .makePermanent()
694 + .build();
695 +
696 + processFlowRule(true, flowRule);
697 + }
698 + }
699 +
700 + /**
701 + * Populates flow rules for TUNNEL_ID table.
702 + *
703 + * @param deviceId device id
704 + * @param inPort in port
705 + * @param mac mac address
706 + * @param tunnelId tunnel id
707 + */
708 + private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
709 + TrafficSelector selector = DefaultTrafficSelector.builder()
710 + .matchTunnelId(tunnelId)
711 + .matchEthDst(mac)
712 + .build();
713 +
714 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
715 + .setOutput(inPort)
716 + .build();
717 +
718 + FlowRule flowRule = DefaultFlowRule.builder()
194 .fromApp(appId) 719 .fromApp(appId)
195 - .makePermanent(); 720 + .withSelector(selector)
721 + .withTreatment(treatment)
722 + .withPriority(DEFAULT_PRIORITY)
723 + .forDevice(deviceId)
724 + .forTable(TABLE_TUNNEL_IN)
725 + .makePermanent()
726 + .build();
727 +
728 + processFlowRule(true, flowRule);
196 } 729 }
197 730
198 /** 731 /**
199 - * Checks if a given port is tunnel interface or not. 732 + * Installs or uninstall a given rule.
200 - * It assumes the tunnel interface contains tunnelType string in its name.
201 * 733 *
202 - * @param port port 734 + * @param install true to install, false to uninstall
203 - * @return true if the port is tunnel interface, false otherwise. 735 + * @param rule rule
204 */ 736 */
205 - private boolean isTunnelPort(Port port) { 737 + private void processFlowRule(boolean install, FlowRule rule) {
206 - return port.annotations().value("portName").contains(tunnelType); 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) {
761 + return null;
762 + }
763 + }
764 +
765 + /**
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 + }
780 +
781 + /**
782 + * Returns the destination mac address from a given flow rule if the rule
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);
794 +
795 + if (instruction == null) {
796 + return null;
797 + }
798 +
799 + return ((ModEtherInstruction) instruction).mac();
800 + }
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 + }
817 + }
818 +
819 + /**
820 + * Returns the destination IP from a given flow rule if the rule contains
821 + * the match of it.
822 + *
823 + * @param flowRule flow rule
824 + * @return ip prefix, or null if the rule doesn't have ip match
825 + */
826 + private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
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);
884 + DriverHandler handler = new DefaultDriverHandler(driverData);
220 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class); 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
......