Hyunsun Moon
Committed by Gerrit Code Review

CORD-506 Apply existing service dependency when VM is detected

Change-Id: Ib0872c823347bfb6091d6c5f872657f10b7b1083
......@@ -18,7 +18,7 @@
category="Traffic Steering" url="http://onosproject.org" title="CORD Virtual Tenant Network"
featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
features="${project.artifactId}"
apps="org.onosproject.ovsdb-base,org.onosproject.dhcp">
apps="org.onosproject.ovsdb-base,org.onosproject.dhcp,org.onosproject.xosclient">
<description>${project.description}</description>
<artifact>mvn:${project.groupId}/onos-app-cordvtn/${project.version}</artifact>
</app>
......
......@@ -103,6 +103,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-app-xos-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.53</version>
......
......@@ -43,6 +43,7 @@ public final class CordService {
private final IpAddress serviceIp;
private final Map<Host, IpAddress> hosts;
private final Set<CordServiceId> tenantServices;
private final Set<CordServiceId> providerServices;
/**
* Default constructor.
......@@ -51,9 +52,11 @@ public final class CordService {
* @param osSubnet OpenStack subnet
* @param hosts host and tunnel ip map
* @param tenantServices list of tenant service ids
* @param providerServices list of provider service ids
*/
public CordService(Network osNet, Subnet osSubnet,
Map<Host, IpAddress> hosts, Set<CordServiceId> tenantServices) {
Map<Host, IpAddress> hosts, Set<CordServiceId> tenantServices,
Set<CordServiceId> providerServices) {
this.id = CordServiceId.of(osNet.getId());
this.segmentationId = Long.parseLong(osNet.getProviderSegID());
this.serviceType = getServiceType(osNet.getName());
......@@ -61,6 +64,7 @@ public final class CordService {
this.serviceIp = IpAddress.valueOf(osSubnet.getGateway());
this.hosts = hosts;
this.tenantServices = tenantServices;
this.providerServices = providerServices;
}
/**
......@@ -126,6 +130,15 @@ public final class CordService {
return tenantServices;
}
/**
* Returns provider service IDs.
*
* @return list of provider service id
*/
public Set<CordServiceId> providerServices() {
return providerServices;
}
@Override
public int hashCode() {
return Objects.hash(id);
......@@ -152,6 +165,7 @@ public final class CordService {
.add("serviceIpRange", serviceIpRange)
.add("serviceIp", serviceIp)
.add("tenantServices", tenantServices)
.add("providerServices", providerServices)
.toString();
}
......@@ -162,7 +176,7 @@ public final class CordService {
* @param netName network name
* @return network type, or PRIVATE if it doesn't match any type
*/
private ServiceType getServiceType(String netName) {
public static ServiceType getServiceType(String netName) {
checkNotNull(netName);
String name = netName.toUpperCase();
......
......@@ -25,6 +25,7 @@ import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.config.Config;
import org.onosproject.xosclient.api.XosAccess;
import org.slf4j.Logger;
import java.util.Map;
......@@ -59,10 +60,12 @@ public class CordVtnConfig extends Config<ApplicationId> {
public static final String SSH_KEY_FILE = "sshKeyFile";
public static final String OPENSTACK = "openstack";
public static final String OPENSTACK_ENDPOINT = "endpoint";
public static final String OPENSTACK_TENANT = "tenant";
public static final String OPENSTACK_USER = "user";
public static final String OPENSTACK_PASSWORD = "password";
public static final String XOS = "xos";
public static final String ENDPOINT = "endpoint";
public static final String TENANT = "tenant";
public static final String USER = "user";
public static final String PASSWORD = "password";
/**
* Returns the set of nodes read from network config.
......@@ -183,6 +186,28 @@ public class CordVtnConfig extends Config<ApplicationId> {
}
/**
* Returns XOS access information.
*
* @return XOS access, or null
*/
public XosAccess xosAccess() {
JsonNode jsonNode = object.get(XOS);
if (jsonNode == null) {
log.error("Failed to get XOS configurations");
return null;
}
try {
return new XosAccess(getConfig(jsonNode, ENDPOINT),
getConfig(jsonNode, USER),
getConfig(jsonNode, PASSWORD));
} catch (NullPointerException e) {
log.error("Failed to get XOS access");
return null;
}
}
/**
* Returns OpenStack API access information.
*
* @return openstack config
......@@ -196,10 +221,10 @@ public class CordVtnConfig extends Config<ApplicationId> {
try {
return new OpenStackConfig(
jsonNode.path(OPENSTACK_ENDPOINT).asText(),
jsonNode.path(OPENSTACK_TENANT).asText(),
jsonNode.path(OPENSTACK_USER).asText(),
jsonNode.path(OPENSTACK_PASSWORD).asText());
jsonNode.path(ENDPOINT).asText(),
jsonNode.path(TENANT).asText(),
jsonNode.path(USER).asText(),
jsonNode.path(PASSWORD).asText());
} catch (IllegalArgumentException | NullPointerException e) {
log.error("Failed to get OpenStack configurations");
return null;
......
......@@ -30,6 +30,7 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cordvtn.api.CordService;
import org.onosproject.cordvtn.api.CordService.ServiceType;
import org.onosproject.cordvtn.api.CordServiceId;
import org.onosproject.cordvtn.api.CordVtnConfig;
import org.onosproject.cordvtn.api.CordVtnNode;
......@@ -66,6 +67,8 @@ import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.xosclient.api.XosAccess;
import org.onosproject.xosclient.api.XosClientService;
import org.openstack4j.api.OSClient;
import org.openstack4j.api.exceptions.AuthenticationException;
import org.openstack4j.model.identity.Access;
......@@ -85,6 +88,7 @@ import java.util.stream.StreamSupport;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.cordvtn.api.CordService.getServiceType;
import static org.slf4j.LoggerFactory.getLogger;
/**
......@@ -130,6 +134,9 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DhcpService dhcpService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected XosClientService xosClient;
private final ConfigFactory configFactory =
new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") {
@Override
......@@ -412,23 +419,7 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
return null;
}
// here it assumes all cord service networks has only one subnet
Subnet osSubnet = osNet.getNeutronSubnets().stream()
.findFirst()
.orElse(null);
if (osSubnet == null) {
log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
return null;
}
Set<CordServiceId> tServices = Sets.newHashSet();
// TODO get tenant services from XOS
Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(osNet)
.stream()
.collect(Collectors.toMap(host -> host, this::getTunnelIp));
return new CordService(osNet, osSubnet, hosts, tServices);
return getCordService(osNet);
}
/**
......@@ -450,14 +441,28 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
return null;
}
Set<CordServiceId> tServices = Sets.newHashSet();
// TODO get tenant services from XOS
Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(osNet)
.stream()
.collect(Collectors.toMap(host -> host, this::getTunnelIp));
return new CordService(osNet, osSubnet, hosts, tServices);
ServiceType serviceType = getServiceType(osNet.getName());
// allows working without XOS for now
Set<CordServiceId> tServices = Sets.newHashSet();
Set<CordServiceId> pServices = Sets.newHashSet();
if (xosClient.access() != null && serviceType != ServiceType.MANAGEMENT) {
tServices = xosClient.vtnServiceApi().getTenantServices(serviceId.id())
.stream()
.map(CordServiceId::of)
.collect(Collectors.toSet());
pServices = xosClient.vtnServiceApi().getProviderServices(serviceId.id())
.stream()
.map(CordServiceId::of)
.collect(Collectors.toSet());
}
return new CordService(osNet, osSubnet, hosts, tServices, pServices);
}
/**
......@@ -576,6 +581,7 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
CordService service = getCordService(osNet);
if (service == null) {
log.warn("Failed to get CordService for {}", osNet.getName());
return;
}
......@@ -587,7 +593,12 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
case PUBLIC:
default:
// TODO check if the service needs an update on its group buckets after done CORD-433
// TODO get bidirectional information from XOS once XOS supports
service.tenantServices().stream().forEach(
tServiceId -> createServiceDependency(tServiceId, service.id(), true));
service.providerServices().stream().forEach(
pServiceId -> createServiceDependency(service.id(), pServiceId, true));
ruleInstaller.updateServiceGroup(service);
// sends gratuitous ARP here for the case of adding existing VMs
// when ONOS or cordvtn app is restarted
......@@ -648,8 +659,9 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
}
case PUBLIC:
default:
// TODO check if the service needs an update on its group buckets after done CORD-433
ruleInstaller.updateServiceGroup(service);
if (!service.tenantServices().isEmpty()) {
ruleInstaller.updateServiceGroup(service);
}
break;
}
}
......@@ -717,6 +729,8 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
* @param newMac mac address to update
*/
private void setPrivateGatewayMac(MacAddress newMac) {
checkNotNull(osAccess, "OpenStack access is not set");
if (newMac == null || newMac.equals(privateGatewayMac)) {
// no updates, do nothing
return;
......@@ -725,13 +739,11 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
privateGatewayMac = newMac;
log.debug("Set service gateway MAC address to {}", privateGatewayMac.toString());
// TODO get existing service list from XOS and replace the loop below
Set<String> vNets = Sets.newHashSet();
hostService.getHosts().forEach(host -> vNets.add(host.annotations().value(SERVICE_ID)));
vNets.remove(null);
OSClient osClient = OSFactory.clientFromAccess(osAccess);
List<Network> vNets = Lists.newArrayList(osClient.networking().network().list().iterator());
vNets.stream().forEach(vNet -> {
CordService service = getCordService(CordServiceId.of(vNet));
CordService service = getCordService(vNet);
if (service != null) {
arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
arpProxy.sendGratuitousArpForGateway(service.serviceIp(), service.hosts().keySet());
......@@ -763,6 +775,8 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
* @param osConfig openstack config
*/
private void setOpenstackAccess(CordVtnConfig.OpenStackConfig osConfig) {
checkNotNull(osConfig, "OpenStack access is not configured");
log.debug("Get OpenStack access with Endpoint: {} Tenant: {} User: {} Passwd: {}",
osConfig.endpoint(),
osConfig.tenant(),
......@@ -781,6 +795,22 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
}
/**
* Sets XOS access information.
*
* @param xosAccess xos access
*/
private void setXosAccess(XosAccess xosAccess) {
checkNotNull(xosAccess, "XOS access is not configured");
log.debug("Set XOS access with Endpoint: {} User: {} Passwd: {}",
xosAccess.endpoint(),
xosAccess.username(),
xosAccess.password());
xosClient.setAccess(xosAccess);
}
/**
* Updates configurations.
*/
private void readConfiguration() {
......@@ -790,6 +820,7 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
return;
}
setXosAccess(config.xosAccess());
setOpenstackAccess(config.openstackConfig());
setPrivateGatewayMac(config.privateGatewayMac());
setPublicGatewayMac(config.publicGateways());
......
......@@ -282,12 +282,12 @@ public class CordVtnRuleInstaller {
GroupId groupId = createServiceGroup(deviceId, pService);
outGroups.put(deviceId, groupId);
Set<PortNumber> vms = tService.hosts().keySet()
Set<PortNumber> tServiceVms = tService.hosts().keySet()
.stream()
.filter(host -> host.location().deviceId().equals(deviceId))
.map(host -> host.location().port())
.collect(Collectors.toSet());
inPorts.put(deviceId, vms);
inPorts.put(deviceId, tServiceVms);
});
populateIndirectAccessRule(srcRange, serviceIp, outGroups);
......