Refactored to handle service instance by service type
- Added service instance handler
- Implemented dummy, vsg, and olt agent instance handler
Change-Id: Id3edd5eecb1caadf0f835cb10a952100e18b283b
diff --git a/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java b/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
index cfcdc4b..efa0e4a 100644
--- a/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
+++ b/src/main/java/org/onosproject/cordvtn/impl/CordVtn.java
@@ -15,7 +15,6 @@
*/
package org.onosproject.cordvtn.impl;
-import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -27,210 +26,77 @@
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.cordvtn.api.CordVtnConfig;
+import org.onlab.packet.Ip4Prefix;
import org.onosproject.cordvtn.api.CordVtnNode;
import org.onosproject.cordvtn.api.CordVtnService;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.dhcp.DhcpService;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.cordvtn.api.Instance;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.Port;
-import org.onosproject.net.config.ConfigFactory;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.basics.SubjectFactories;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.DefaultGroupKey;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupService;
-import org.onosproject.net.host.DefaultHostDescription;
-import org.onosproject.net.host.HostDescription;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostProvider;
-import org.onosproject.net.host.HostProviderRegistry;
-import org.onosproject.net.host.HostProviderService;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.packet.PacketContext;
-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.OpenStackAccess;
-import org.onosproject.xosclient.api.VtnPort;
-import org.onosproject.xosclient.api.VtnPortApi;
-import org.onosproject.xosclient.api.VtnPortId;
import org.onosproject.xosclient.api.VtnService;
-import org.onosproject.xosclient.api.VtnServiceApi;
import org.onosproject.xosclient.api.VtnServiceId;
-import org.onosproject.xosclient.api.XosAccess;
-import org.onosproject.xosclient.api.XosClientService;
import org.slf4j.Logger;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
-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.impl.CordVtnPipeline.*;
+import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Provisions virtual tenant networks with service chaining capability
- * in OpenStack environment.
+ * Provisions service dependency capabilities between network services.
*/
@Component(immediate = true)
@Service
-public class CordVtn extends AbstractProvider implements CordVtnService, HostProvider {
+public class CordVtn extends CordVtnInstanceHandler implements CordVtnService {
protected final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected NetworkConfigRegistry configRegistry;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostProviderRegistry hostProviderRegistry;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostService hostService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected FlowRuleService flowRuleService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected PacketService packetService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected MastershipService mastershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected GroupService groupService;
- @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
- public CordVtnConfig createConfig() {
- return new CordVtnConfig();
- }
- };
-
- private static final String XOS_ACCESS_ERROR = "XOS access is not configured";
- private static final String OPENSTACK_ACCESS_ERROR = "OpenStack access is not configured";
-
- private static final String DEFAULT_TUNNEL = "vxlan";
- private static final String SERVICE_ID = "serviceId";
- private static final String PORT_ID = "vtnPortId";
- private static final String DATA_PLANE_IP = "dataPlaneIp";
- private static final String DATA_PLANE_INTF = "dataPlaneIntf";
- private static final String S_TAG = "stag";
- private static final String VSG_HOST_ID = "vsgHostId";
- private static final String CREATE_TIME = "createTime";
-
- private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
-
- private final ExecutorService eventExecutor =
- newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler"));
-
- private final PacketProcessor packetProcessor = new InternalPacketProcessor();
- private final HostListener hostListener = new InternalHostListener();
- private final NetworkConfigListener configListener = new InternalConfigListener();
-
- private ApplicationId appId;
- private HostProviderService hostProvider;
- private CordVtnRuleInstaller ruleInstaller;
- private CordVtnArpProxy arpProxy;
-
- private volatile XosAccess xosAccess = null;
- private volatile OpenStackAccess osAccess = null;
- private volatile MacAddress privateGatewayMac = MacAddress.NONE;
-
- /**
- * Creates an cordvtn host location provider.
- */
- public CordVtn() {
- super(new ProviderId("host", CORDVTN_APP_ID));
- }
-
@Activate
protected void activate() {
- appId = coreService.registerApplication(CordVtnService.CORDVTN_APP_ID);
- ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
- deviceService,
- groupService,
- hostService,
- configRegistry,
- DEFAULT_TUNNEL);
-
- arpProxy = new CordVtnArpProxy(appId, packetService, hostService);
- packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
- arpProxy.requestPacket();
-
- hostService.addListener(hostListener);
- hostProvider = hostProviderRegistry.register(this);
-
- configRegistry.registerConfigFactory(configFactory);
- configRegistry.addListener(configListener);
-
- log.info("Started");
+ eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler"));
+ hostListener = new InternalHostListener();
+ super.activate();
}
@Deactivate
protected void deactivate() {
- hostProviderRegistry.unregister(this);
- hostService.removeListener(hostListener);
-
- packetService.removeProcessor(packetProcessor);
-
- configRegistry.unregisterConfigFactory(configFactory);
- configRegistry.removeListener(configListener);
-
- eventExecutor.shutdown();
- log.info("Stopped");
- }
-
- @Override
- public void triggerProbe(Host host) {
- /*
- * Note: In CORD deployment, we assume that all hosts are configured.
- * Therefore no probe is required.
- */
+ super.deactivate();
}
@Override
public void createServiceDependency(VtnServiceId tServiceId, VtnServiceId pServiceId,
boolean isBidirectional) {
- checkNotNull(osAccess, OPENSTACK_ACCESS_ERROR);
- checkNotNull(xosAccess, XOS_ACCESS_ERROR);
-
- // TODO remove openstack access when XOS provides all information
- VtnServiceApi serviceApi = xosClient.getClient(xosAccess).vtnService();
- VtnService tService = serviceApi.service(tServiceId, osAccess);
- VtnService pService = serviceApi.service(pServiceId, osAccess);
+ VtnService tService = getVtnService(tServiceId);
+ VtnService pService = getVtnService(pServiceId);
if (tService == null || pService == null) {
log.error("Failed to create dependency between {} and {}",
@@ -239,18 +105,13 @@
}
log.info("Created dependency between {} and {}", tService.name(), pService.name());
- ruleInstaller.populateServiceDependencyRules(tService, pService, isBidirectional, true);
+ serviceDependencyRules(tService, pService, isBidirectional, true);
}
@Override
public void removeServiceDependency(VtnServiceId tServiceId, VtnServiceId pServiceId) {
- checkNotNull(osAccess, OPENSTACK_ACCESS_ERROR);
- checkNotNull(xosAccess, XOS_ACCESS_ERROR);
-
- // TODO remove openstack access when XOS provides all information
- VtnServiceApi serviceApi = xosClient.getClient(xosAccess).vtnService();
- VtnService tService = serviceApi.service(tServiceId, osAccess);
- VtnService pService = serviceApi.service(pServiceId, osAccess);
+ VtnService tService = getVtnService(tServiceId);
+ VtnService pService = getVtnService(pServiceId);
if (tService == null || pService == null) {
log.error("Failed to remove dependency between {} and {}",
@@ -259,427 +120,267 @@
}
log.info("Removed dependency between {} and {}", tService.name(), pService.name());
- ruleInstaller.populateServiceDependencyRules(tService, pService, true, false);
+ serviceDependencyRules(tService, pService, true, false);
}
@Override
- public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) {
- checkNotNull(osAccess, OPENSTACK_ACCESS_ERROR);
- checkNotNull(xosAccess, XOS_ACCESS_ERROR);
-
- Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
- String portName = port.annotations().value("portName");
-
- // TODO remove openstack access when XOS provides all information
- VtnPortApi portApi = xosClient.getClient(xosAccess).vtnPort();
- VtnPort vtnPort = portApi.vtnPort(portName, osAccess);
- if (vtnPort == null) {
- log.warn("Failed to get port information of {}", portName);
+ public void instanceDetected(Instance instance) {
+ VtnService service = getVtnService(instance.serviceId());
+ if (service == null) {
return;
}
- // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
- // existing instances.
- DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
- .set(SERVICE_ID, vtnPort.serviceId().id())
- .set(PORT_ID, vtnPort.id().id())
- .set(DATA_PLANE_IP, node.dpIp().ip().toString())
- .set(DATA_PLANE_INTF, node.dpIntf())
- .set(CREATE_TIME, String.valueOf(System.currentTimeMillis()));
+ // 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));
- // TODO address service specific task in a separate package
- String serviceVlan = getServiceVlan(vtnPort);
- if (!Strings.isNullOrEmpty(serviceVlan)) {
- annotations.set(S_TAG, serviceVlan);
- }
-
- HostDescription hostDesc = new DefaultHostDescription(
- vtnPort.mac(),
- VlanId.NONE,
- new HostLocation(connectPoint, System.currentTimeMillis()),
- Sets.newHashSet(vtnPort.ip()),
- annotations.build());
-
- HostId hostId = HostId.hostId(vtnPort.mac());
- hostProvider.hostDetected(hostId, hostDesc, false);
+ updateProviderServiceInstances(service);
}
@Override
- public void removeServiceVm(ConnectPoint connectPoint) {
- hostService.getConnectedHosts(connectPoint)
- .stream()
- .forEach(host -> hostProvider.hostVanished(host.id()));
- }
-
- @Override
- // TODO address service specific task in a separate package
- public void updateVirtualSubscriberGateways(HostId vSgHostId, String serviceVlan,
- Map<IpAddress, MacAddress> vSgs) {
- Host vSgHost = hostService.getHost(vSgHostId);
- if (vSgHost == null || !vSgHost.annotations().value(S_TAG).equals(serviceVlan)) {
- log.debug("Invalid vSG updates for {}", serviceVlan);
+ public void instanceRemoved(Instance instance) {
+ VtnService service = getVtnService(instance.serviceId());
+ if (service == null) {
return;
}
- log.info("Updates vSGs in {} with {}", vSgHost.id(), vSgs.toString());
- vSgs.entrySet().stream()
- .filter(entry -> hostService.getHostsByMac(entry.getValue()).isEmpty())
- .forEach(entry -> addVirtualSubscriberGateway(
- vSgHost,
- entry.getKey(),
- entry.getValue(),
- serviceVlan));
-
- hostService.getConnectedHosts(vSgHost.location()).stream()
- .filter(host -> !host.mac().equals(vSgHost.mac()))
- .filter(host -> !vSgs.values().contains(host.mac()))
- .forEach(host -> {
- log.info("Removed vSG {}", host.toString());
- hostProvider.hostVanished(host.id());
- });
- }
-
- /**
- * Adds virtual subscriber gateway to the system.
- *
- * @param vSgHost host virtual machine of this vSG
- * @param vSgIp vSG ip address
- * @param vSgMac vSG mac address
- * @param serviceVlan service vlan
- */
- // TODO address service specific task in a separate package
- private void addVirtualSubscriberGateway(Host vSgHost, IpAddress vSgIp, MacAddress vSgMac,
- String serviceVlan) {
- log.info("vSG with IP({}) MAC({}) added", vSgIp.toString(), vSgMac.toString());
-
- HostId hostId = HostId.hostId(vSgMac);
- DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
- .set(S_TAG, serviceVlan)
- .set(VSG_HOST_ID, vSgHost.id().toString())
- .set(CREATE_TIME, String.valueOf(System.currentTimeMillis()));
-
- HostDescription hostDesc = new DefaultHostDescription(
- vSgMac,
- VlanId.NONE,
- vSgHost.location(),
- Sets.newHashSet(vSgIp),
- annotations.build());
-
- hostProvider.hostDetected(hostId, hostDesc, false);
- }
-
- /**
- * Returns public ip addresses of vSGs running inside a give vSG host.
- *
- * @param vSgHost vSG host
- * @return map of ip and mac address, or empty map
- */
- // TODO address service specific task in a separate package
- private Map<IpAddress, MacAddress> getSubscriberGateways(Host vSgHost) {
- checkNotNull(osAccess, OPENSTACK_ACCESS_ERROR);
- checkNotNull(xosAccess, XOS_ACCESS_ERROR);
-
- String vtnPortId = vSgHost.annotations().value(PORT_ID);
- String sTag = vSgHost.annotations().value(S_TAG);
-
- if (Strings.isNullOrEmpty(vtnPortId) || Strings.isNullOrEmpty(sTag)) {
- log.warn("PORT_ID and S_TAG is not set, ignore {}", vSgHost);
- return Maps.newHashMap();
+ if (!service.providerServices().isEmpty()) {
+ removeInstanceFromTenantService(instance, service);
}
-
- // TODO remove openstack access when XOS provides all information
- VtnPortApi portApi = xosClient.getClient(xosAccess).vtnPort();
- VtnPort vtnPort = portApi.vtnPort(VtnPortId.of(vtnPortId), osAccess);
- if (vtnPort == null) {
- log.warn("Failed to get port information of {}", vSgHost);
- return Maps.newHashMap();
- }
-
- if (!sTag.equals(getServiceVlan(vtnPort))) {
- log.error("Host({}) s-tag does not match with VTN port s-tag", vSgHost);
- return Maps.newHashMap();
- }
- return vtnPort.addressPairs();
- }
-
- /**
- * Returns s-tag from a given VTN port.
- *
- * @param vtnPort vtn port
- * @return s-tag string
- */
- // TODO address service specific task in a separate package
- private String getServiceVlan(VtnPort vtnPort) {
- checkNotNull(vtnPort);
-
- String portName = vtnPort.name();
- if (portName != null && portName.startsWith(S_TAG)) {
- return portName.split("-")[1];
- } else {
- return null;
+ if (!service.tenantServices().isEmpty()) {
+ updateProviderServiceInstances(service);
}
}
- /**
- * Returns instances with a given network service.
- *
- * @param serviceId service id
- * @return set of hosts
- */
- private Set<Host> getInstances(VtnServiceId serviceId) {
- return StreamSupport.stream(hostService.getHosts().spliterator(), false)
- .filter(host -> Objects.equals(
- serviceId.id(),
- host.annotations().value(SERVICE_ID)))
+ private void updateProviderServiceInstances(VtnService service) {
+ GroupKey groupKey = getGroupKey(service.id());
+
+ Set<DeviceId> devices = nodeManager.completeNodes().stream()
+ .map(CordVtnNode::intBrId)
.collect(Collectors.toSet());
- }
- /**
- * Registers static DHCP lease for a given host.
- *
- * @param host host
- * @param service cord service
- */
- private void registerDhcpLease(Host host, VtnService service) {
- List<Ip4Address> options = Lists.newArrayList();
- options.add(Ip4Address.makeMaskPrefix(service.subnet().prefixLength()));
- options.add(service.serviceIp().getIp4Address());
- options.add(service.serviceIp().getIp4Address());
- options.add(DEFAULT_DNS);
-
- log.debug("Set static DHCP mapping for {}", host.mac());
- dhcpService.setStaticMapping(host.mac(),
- host.ipAddresses().stream().findFirst().get().getIp4Address(),
- true,
- options);
- }
-
- /**
- * Handles VM detected situation.
- *
- * @param host host
- */
- private void serviceVmAdded(Host host) {
- checkNotNull(osAccess, OPENSTACK_ACCESS_ERROR);
- checkNotNull(xosAccess, XOS_ACCESS_ERROR);
-
- // TODO address service specific task in a separate package
- String serviceVlan = host.annotations().value(S_TAG);
- if (serviceVlan != null) {
- virtualSubscriberGatewayAdded(host, serviceVlan);
- }
-
- String serviceId = host.annotations().value(SERVICE_ID);
- if (Strings.isNullOrEmpty(serviceId)) {
- // ignore this host, it is not a service instance
- return;
- }
-
- log.info("Instance is detected {}", host);
-
- // TODO remove openstack access when XOS provides all information
- VtnServiceApi serviceApi = xosClient.getClient(xosAccess).vtnService();
- VtnService service = serviceApi.service(VtnServiceId.of(serviceId), osAccess);
- if (service == null) {
- log.warn("Failed to get VtnService for {}", serviceId);
- return;
- }
-
- switch (service.networkType()) {
- case MANAGEMENT:
- ruleInstaller.populateManagementNetworkRules(host, service);
- break;
- case PRIVATE:
- arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
- case PUBLIC:
- default:
- // 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.updateProviderServiceGroup(service);
- // sends gratuitous ARP here for the case of adding existing VMs
- // when ONOS or cordvtn app is restarted
- arpProxy.sendGratuitousArpForGateway(service.serviceIp(), Sets.newHashSet(host));
- break;
- }
-
- registerDhcpLease(host, service);
- ruleInstaller.populateBasicConnectionRules(host, service, true);
- }
-
- /**
- * Handles VM removed situation.
- *
- * @param host host
- */
- private void serviceVmRemoved(Host host) {
- checkNotNull(osAccess, OPENSTACK_ACCESS_ERROR);
- checkNotNull(xosAccess, XOS_ACCESS_ERROR);
-
- // TODO address service specific task in a separate package
- if (host.annotations().value(S_TAG) != null) {
- virtualSubscriberGatewayRemoved(host);
- }
-
- String serviceId = host.annotations().value(SERVICE_ID);
- if (Strings.isNullOrEmpty(serviceId)) {
- // ignore this host, it is not a service instance
- return;
- }
-
- log.info("Instance is vanished {}", host);
-
- // TODO remove openstack access when XOS provides all information
- VtnServiceApi vtnServiceApi = xosClient.getClient(xosAccess).vtnService();
- VtnService service = vtnServiceApi.service(VtnServiceId.of(serviceId), osAccess);
- if (service == null) {
- log.warn("Failed to get VtnService for {}", serviceId);
- return;
- }
-
- // TODO need to consider the case that the service is removed also
- switch (service.networkType()) {
- case MANAGEMENT:
- break;
- case PRIVATE:
- if (getInstances(VtnServiceId.of(serviceId)).isEmpty()) {
- arpProxy.removeGateway(service.serviceIp());
- }
- case PUBLIC:
- default:
- if (!service.tenantServices().isEmpty()) {
- ruleInstaller.updateProviderServiceGroup(service);
- }
- if (!service.providerServices().isEmpty()) {
- ruleInstaller.updateTenantServiceVm(host, service);
- }
- break;
- }
-
- dhcpService.removeStaticMapping(host.mac());
- ruleInstaller.populateBasicConnectionRules(host, service, false);
- }
-
-
- /**
- * Handles virtual subscriber gateway VM or container.
- *
- * @param host new host with stag, it can be vsg VM or vsg
- * @param serviceVlan service vlan
- */
- // TODO address service specific task in a separate package
- private void virtualSubscriberGatewayAdded(Host host, String serviceVlan) {
- Map<IpAddress, MacAddress> vSgs;
- Host vSgHost;
-
- String vSgHostId = host.annotations().value(VSG_HOST_ID);
- if (vSgHostId == null) {
- log.info("vSG VM detected {}", host.id());
-
- vSgHost = host;
- vSgs = getSubscriberGateways(vSgHost);
- vSgs.entrySet().stream().forEach(entry -> addVirtualSubscriberGateway(
- vSgHost,
- entry.getKey(),
- entry.getValue(),
- serviceVlan));
- } else {
- vSgHost = hostService.getHost(HostId.hostId(vSgHostId));
- if (vSgHost == null) {
- return;
+ for (DeviceId deviceId : devices) {
+ Group group = groupService.getGroup(deviceId, groupKey);
+ if (group == null) {
+ log.trace("No group exists for service {} in {}", service.id(), deviceId);
+ continue;
}
- log.info("vSG detected {}", host.id());
- vSgs = getSubscriberGateways(vSgHost);
- }
+ List<GroupBucket> oldBuckets = group.buckets().buckets();
+ List<GroupBucket> newBuckets = getServiceGroupBuckets(
+ deviceId, service.vni(), getInstances(service.id())).buckets();
- ruleInstaller.populateSubscriberGatewayRules(vSgHost, vSgs.keySet());
- }
-
- /**
- * Handles virtual subscriber gateway removed.
- *
- * @param vSg vsg host to remove
- */
- // TODO address service specific task in a separate package
- private void virtualSubscriberGatewayRemoved(Host vSg) {
- String vSgHostId = vSg.annotations().value(VSG_HOST_ID);
- if (vSgHostId == null) {
- return;
- }
-
- Host vSgHost = hostService.getHost(HostId.hostId(vSgHostId));
- if (vSgHost == null) {
- return;
- }
-
- log.info("vSG removed {}", vSg.id());
- Map<IpAddress, MacAddress> vSgs = getSubscriberGateways(vSgHost);
- ruleInstaller.populateSubscriberGatewayRules(vSgHost, vSgs.keySet());
- }
-
- /**
- * Sets service network gateway MAC address and sends out gratuitous ARP to all
- * VMs to update the gateway MAC address.
- *
- * @param newMac mac address to update
- */
- private void setPrivateGatewayMac(MacAddress newMac) {
- checkNotNull(osAccess, OPENSTACK_ACCESS_ERROR);
- checkNotNull(xosAccess, XOS_ACCESS_ERROR);
-
- if (newMac == null || newMac.equals(privateGatewayMac)) {
- // no updates, do nothing
- return;
- }
-
- privateGatewayMac = newMac;
- log.debug("Set service gateway MAC address to {}", privateGatewayMac.toString());
-
- VtnServiceApi vtnServiceApi = xosClient.getClient(xosAccess).vtnService();
- vtnServiceApi.services().stream().forEach(serviceId -> {
- VtnService service = vtnServiceApi.service(serviceId, osAccess);
- if (service != null) {
- arpProxy.addGateway(service.serviceIp(), privateGatewayMac);
- arpProxy.sendGratuitousArpForGateway(service.serviceIp(), getInstances(serviceId));
+ if (oldBuckets.equals(newBuckets)) {
+ continue;
}
+
+ List<GroupBucket> bucketsToRemove = Lists.newArrayList(oldBuckets);
+ bucketsToRemove.removeAll(newBuckets);
+ if (!bucketsToRemove.isEmpty()) {
+ groupService.removeBucketsFromGroup(
+ deviceId,
+ groupKey,
+ new GroupBuckets(bucketsToRemove),
+ groupKey, appId);
+ }
+
+ List<GroupBucket> bucketsToAdd = Lists.newArrayList(newBuckets);
+ bucketsToAdd.removeAll(oldBuckets);
+ if (!bucketsToAdd.isEmpty()) {
+ groupService.addBucketsToGroup(
+ deviceId,
+ groupKey,
+ new GroupBuckets(bucketsToAdd),
+ groupKey, appId);
+ }
+ }
+ }
+
+ private void removeInstanceFromTenantService(Instance instance, VtnService service) {
+ service.providerServices().stream().forEach(pServiceId -> {
+ Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
+ Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
+
+ inPorts.put(instance.deviceId(), Sets.newHashSet(instance.portNumber()));
+ outGroups.put(instance.deviceId(), getGroupId(pServiceId, instance.deviceId()));
+
+ inServiceRule(inPorts, outGroups, false);
});
}
- /**
- * Sets public gateway MAC address.
- *
- * @param publicGateways gateway ip and mac address pairs
- */
- private void setPublicGatewayMac(Map<IpAddress, MacAddress> publicGateways) {
- publicGateways.entrySet()
- .stream()
- .forEach(entry -> {
- arpProxy.addGateway(entry.getKey(), entry.getValue());
- log.debug("Added public gateway IP {}, MAC {}",
- entry.getKey().toString(), entry.getValue().toString());
- });
- // TODO notice gateway MAC change to VMs holds this gateway IP
+ private void serviceDependencyRules(VtnService tService, VtnService pService,
+ boolean isBidirectional, boolean install) {
+ Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
+ Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
+
+ nodeManager.completeNodes().stream().forEach(node -> {
+ DeviceId deviceId = node.intBrId();
+ GroupId groupId = createServiceGroup(deviceId, pService);
+ outGroups.put(deviceId, groupId);
+
+ Set<PortNumber> tServiceInstances = getInstances(tService.id())
+ .stream()
+ .filter(instance -> instance.deviceId().equals(deviceId))
+ .map(Instance::portNumber)
+ .collect(Collectors.toSet());
+ inPorts.put(deviceId, tServiceInstances);
+ });
+
+ Ip4Prefix srcRange = tService.subnet().getIp4Prefix();
+ Ip4Prefix dstRange = pService.subnet().getIp4Prefix();
+
+ indirectAccessRule(srcRange, pService.serviceIp().getIp4Address(), outGroups, install);
+ directAccessRule(srcRange, dstRange, install);
+ if (isBidirectional) {
+ directAccessRule(dstRange, srcRange, install);
+ }
+ inServiceRule(inPorts, outGroups, install);
}
- /**
- * Updates configurations.
- */
- private void readConfiguration() {
- CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
- if (config == null) {
- log.debug("No configuration found");
- return;
+ private void indirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
+ Map<DeviceId, GroupId> outGroups, boolean install) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPSrc(srcRange)
+ .matchIPDst(serviceIp.toIpPrefix())
+ .build();
+
+ for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .group(outGroup.getValue())
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(PRIORITY_HIGH)
+ .forDevice(outGroup.getKey())
+ .forTable(TABLE_ACCESS_TYPE)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRule);
+ }
+ }
+
+ private void directAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange, boolean install) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPSrc(srcRange)
+ .matchIPDst(dstRange)
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .transition(TABLE_DST_IP)
+ .build();
+
+ nodeManager.completeNodes().stream().forEach(node -> {
+ DeviceId deviceId = node.intBrId();
+ FlowRule flowRuleDirect = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(PRIORITY_DEFAULT)
+ .forDevice(deviceId)
+ .forTable(TABLE_ACCESS_TYPE)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRuleDirect);
+ });
+ }
+
+ private void inServiceRule(Map<DeviceId, Set<PortNumber>> inPorts,
+ Map<DeviceId, GroupId> outGroups, boolean install) {
+ for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
+ Set<PortNumber> ports = entry.getValue();
+ DeviceId deviceId = entry.getKey();
+
+ GroupId groupId = outGroups.get(deviceId);
+ if (groupId == null) {
+ continue;
+ }
+
+ ports.stream().forEach(port -> {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPort(port)
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .group(groupId)
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(PRIORITY_DEFAULT)
+ .forDevice(deviceId)
+ .forTable(TABLE_IN_SERVICE)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRule);
+ });
+ }
+ }
+
+ private GroupId getGroupId(VtnServiceId serviceId, DeviceId deviceId) {
+ return new DefaultGroupId(Objects.hash(serviceId, deviceId));
+ }
+
+ private GroupKey getGroupKey(VtnServiceId serviceId) {
+ return new DefaultGroupKey(serviceId.id().getBytes());
+ }
+
+ private GroupId createServiceGroup(DeviceId deviceId, VtnService service) {
+ GroupKey groupKey = getGroupKey(service.id());
+ Group group = groupService.getGroup(deviceId, groupKey);
+ GroupId groupId = getGroupId(service.id(), deviceId);
+
+ if (group != null) {
+ log.debug("Group {} is already exist in {}", service.id(), deviceId);
+ return groupId;
}
- xosAccess = config.xosAccess();
- osAccess = config.openstackAccess();
+ GroupBuckets buckets = getServiceGroupBuckets(
+ deviceId, service.vni(), getInstances(service.id()));
+ GroupDescription groupDescription = new DefaultGroupDescription(
+ deviceId,
+ GroupDescription.Type.SELECT,
+ buckets,
+ groupKey,
+ groupId.id(),
+ appId);
- setPrivateGatewayMac(config.privateGatewayMac());
- setPublicGatewayMac(config.publicGateways());
+ groupService.addGroup(groupDescription);
+ return groupId;
+ }
+
+ private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId,
+ Set<Instance> instances) {
+ List<GroupBucket> buckets = Lists.newArrayList();
+ instances.stream().forEach(instance -> {
+ Ip4Address tunnelIp = nodeManager.dpIp(instance.deviceId()).getIp4Address();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ if (deviceId.equals(instance.deviceId())) {
+ tBuilder.setEthDst(instance.mac())
+ .setOutput(instance.portNumber());
+ } else {
+ ExtensionTreatment tunnelDst =
+ pipeline.tunnelDstTreatment(deviceId, tunnelIp);
+ tBuilder.setEthDst(instance.mac())
+ .extension(tunnelDst, deviceId)
+ .setTunnelId(tunnelId)
+ .setOutput(nodeManager.tunnelPort(instance.deviceId()));
+ }
+ buckets.add(createSelectGroupBucket(tBuilder.build()));
+ });
+ return new GroupBuckets(buckets);
}
private class InternalHostListener implements HostListener {
@@ -692,50 +393,14 @@
return;
}
+ Instance instance = Instance.of(host);
switch (event.type()) {
case HOST_UPDATED:
case HOST_ADDED:
- eventExecutor.execute(() -> serviceVmAdded(host));
+ eventExecutor.execute(() -> instanceDetected(instance));
break;
case HOST_REMOVED:
- eventExecutor.execute(() -> serviceVmRemoved(host));
- break;
- default:
- break;
- }
- }
- }
-
- private class InternalPacketProcessor implements PacketProcessor {
-
- @Override
- public void process(PacketContext context) {
- if (context.isHandled()) {
- return;
- }
-
- Ethernet ethPacket = context.inPacket().parsed();
- if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
- return;
- }
-
- arpProxy.processArpPacket(context, ethPacket);
- }
- }
-
- private class InternalConfigListener implements NetworkConfigListener {
-
- @Override
- public void event(NetworkConfigEvent event) {
- if (!event.configClass().equals(CordVtnConfig.class)) {
- return;
- }
-
- switch (event.type()) {
- case CONFIG_ADDED:
- case CONFIG_UPDATED:
- log.info("Network configuration changed");
- eventExecutor.execute(CordVtn.this::readConfiguration);
+ eventExecutor.execute(() -> instanceRemoved(instance));
break;
default:
break;