/*
* Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.groupbasedpolicy.neutron.mapper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronAware;
import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronFloatingIpAware;
import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronNetworkAware;
import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronPortAware;
import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronRouterAware;
import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSecurityGroupAware;
import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSubnetAware;
import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule.NeutronSecurityRuleAware;
import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NetworkUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.BaseEndpointService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.NeutronBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroups;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroupsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRulesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRuleBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterators;
import com.google.common.collect.PeekingIterator;
public class NeutronMapper implements ClusteredDataTreeChangeListener<Neutron>, AutoCloseable {
private static final String EXC_MSG_UNKNOWN_MODIFICATION_TYPE_WITHIN_DATA = "Unknown modification type within data ";
private final static SecurityRuleBuilder EIG_INGRESS_IPV4_SEC_RULE_BUILDER = new SecurityRuleBuilder()
.setUuid(new Uuid("0a629f80-2408-11e6-b67b-9e71128cae77"))
.setDirection(DirectionIngress.class)
.setEthertype(EthertypeV4.class)
.setSecurityGroupId(MappingUtils.EIG_UUID);
private final static SecurityRuleBuilder EIG_EGRESS_IPV4_SEC_RULE_BUILDER = new SecurityRuleBuilder()
.setUuid(new Uuid("0f1789be-2408-11e6-b67b-9e71128cae77"))
.setDirection(DirectionEgress.class)
.setEthertype(EthertypeV4.class)
.setSecurityGroupId(MappingUtils.EIG_UUID);
private final static SecurityRuleBuilder EIG_INGRESS_IPV6_SEC_RULE_BUILDER = new SecurityRuleBuilder()
.setUuid(new Uuid("139b7f90-2408-11e6-b67b-9e71128cae77"))
.setDirection(DirectionIngress.class)
.setEthertype(EthertypeV6.class)
.setSecurityGroupId(MappingUtils.EIG_UUID);
private final static SecurityRuleBuilder EIG_EGRESS_IPV6_SEC_RULE_BUILDER = new SecurityRuleBuilder()
.setUuid(new Uuid("17517202-2408-11e6-b67b-9e71128cae77"))
.setDirection(DirectionEgress.class)
.setEthertype(EthertypeV6.class)
.setSecurityGroupId(MappingUtils.EIG_UUID);
private final static SecurityGroupBuilder EIG_SEC_GROUP_BUILDER =
new SecurityGroupBuilder().setUuid(MappingUtils.EIG_UUID);
private final NeutronNetworkAware networkAware;
private final NeutronSecurityGroupAware securityGroupAware;
private final NeutronSecurityRuleAware securityRuleAware;
private final NeutronSubnetAware subnetAware;
private final NeutronPortAware portAware;
private final NeutronRouterAware routerAware;
private final NeutronFloatingIpAware floatingIpAware;
private final ListenerRegistration<NeutronMapper> registerDataTreeChangeListener;
private Neutron neutronBefore;
private Neutron neutronAfter;
public NeutronMapper(DataBroker dataProvider, EndpointService epService, BaseEndpointService baseEpService,
@Nullable IpPrefix metadataIpPrefix, long metadataTcpPort) {
EndpointRegistrator epRegistrator = new EndpointRegistrator(epService, baseEpService);
networkAware = new NeutronNetworkAware(dataProvider, metadataTcpPort);
securityRuleAware = new NeutronSecurityRuleAware(dataProvider, epRegistrator);
securityGroupAware = new NeutronSecurityGroupAware(dataProvider, securityRuleAware);
subnetAware = new NeutronSubnetAware(dataProvider, epRegistrator);
portAware = new NeutronPortAware(dataProvider, epRegistrator, metadataIpPrefix);
routerAware = new NeutronRouterAware(dataProvider, epRegistrator);
floatingIpAware = new NeutronFloatingIpAware(dataProvider);
registerDataTreeChangeListener =
dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
InstanceIdentifier.builder(Neutron.class).build()), this);
}
@Override
public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Neutron>> changes) {
for (DataTreeModification<Neutron> change : changes) {
DataObjectModification<Neutron> neutronModif = change.getRootNode();
resolveAndSetNeutron(neutronModif);
// network
List<DataObjectModification<Network>> networkModifs =
findModifiedData(NeutronNetworkAware.NETWORK_WILDCARD_IID, neutronModif);
for (Uuid tenantFromCreatedRouterExternalNetwork : filterCreatedRouterExternalNetworksAndTransformToTenants(
networkModifs)) {
SecurityGroup eigSecGroup =
EIG_SEC_GROUP_BUILDER.setTenantId(tenantFromCreatedRouterExternalNetwork).build();
securityGroupAware.onCreated(eigSecGroup, neutronAfter);
List<SecurityRule> eigSecRules = createEigSecurityRules(tenantFromCreatedRouterExternalNetwork);
for (SecurityRule eigSecRule : eigSecRules) {
securityRuleAware.onCreated(eigSecRule, neutronAfter);
}
}
onDataObjectModification(networkModifs, networkAware);
// security group
List<DataObjectModification<SecurityGroup>> secGroupModifs =
findModifiedData(NeutronSecurityGroupAware.SECURITY_GROUP_WILDCARD_IID, neutronModif);
onDataObjectModification(secGroupModifs, securityGroupAware);
// security rules
List<DataObjectModification<SecurityRule>> secRuleModifs =
findModifiedData(NeutronSecurityRuleAware.SECURITY_RULE_WILDCARD_IID, neutronModif);
onDataObjectModification(secRuleModifs, securityRuleAware);
// subnet
List<DataObjectModification<Subnet>> subnetModifs = findModifiedData(NeutronSubnetAware.SUBNET_WILDCARD_IID, neutronModif);
onDataObjectModification(subnetModifs, subnetAware);
// port
List<DataObjectModification<Port>> portModifs = findModifiedData(NeutronPortAware.PORT_WILDCARD_IID, neutronModif);
onDataObjectModification(portModifs, portAware);
// router
List<DataObjectModification<Router>> routerModifs = findModifiedData(NeutronRouterAware.ROUTER_WILDCARD_IID, neutronModif);
onDataObjectModification(routerModifs, routerAware);
// floating IP
List<DataObjectModification<Floatingip>> floatingIpModifs = findModifiedData(NeutronFloatingIpAware.FLOATING_IP_WILDCARD_IID, neutronModif);
onDataObjectModification(floatingIpModifs, floatingIpAware);
}
}
private <T extends DataObject> void onDataObjectModification(List<DataObjectModification<T>> dataModifs,
NeutronAware<T> neutronAware) {
for (DataObjectModification<T> dataModif : dataModifs) {
final T dataBefore = dataModif.getDataBefore();
final T dataAfter = dataModif.getDataAfter();
if (dataBefore == null && dataAfter != null) {
neutronAware.onCreated(dataAfter, neutronAfter);
}
else if (dataBefore != null && dataAfter != null) {
neutronAware.onUpdated(dataBefore, dataAfter, neutronBefore, neutronAfter);
}
else if (dataBefore != null) {
neutronAware.onDeleted(dataBefore, neutronBefore, neutronAfter);
}
else {
throw new IllegalStateException(EXC_MSG_UNKNOWN_MODIFICATION_TYPE_WITHIN_DATA + dataModif);
}
}
}
private Set<Uuid> filterCreatedRouterExternalNetworksAndTransformToTenants(
List<DataObjectModification<Network>> modifiedNetworks) {
return FluentIterable.from(modifiedNetworks).filter(new Predicate<DataObjectModification<Network>>() {
@Override
public boolean apply(DataObjectModification<Network> modifiedNetwork) {
return (ModificationType.WRITE == modifiedNetwork.getModificationType()
&& NetworkUtils.isRouterExternal(modifiedNetwork.getDataAfter()));
}
}).transform(new Function<DataObjectModification<Network>, Uuid>() {
@Override
public Uuid apply(DataObjectModification<Network> modifiedNetwork) {
return modifiedNetwork.getDataAfter().getTenantId();
}
}).toSet();
}
private void resolveAndSetNeutron(DataObjectModification<Neutron> originalNeutron) {
Neutron oldNeutronBefore = originalNeutron.getDataBefore();
neutronBefore = resolveAndCreateNewNeutron(oldNeutronBefore);
Neutron oldNeutronAfter = originalNeutron.getDataAfter();
neutronAfter = resolveAndCreateNewNeutron(oldNeutronAfter);
}
private @Nullable Neutron resolveAndCreateNewNeutron(@Nullable Neutron originalNeutron) {
if (originalNeutron == null) {
return null;
}
NeutronBuilder newNeutronBuilder = new NeutronBuilder(originalNeutron);
resolveAndAddSecurityRulesAndGroups(originalNeutron, newNeutronBuilder);
return newNeutronBuilder.build();
}
private void resolveAndAddSecurityRulesAndGroups(Neutron originalNeutron, NeutronBuilder newNeutronBuilder) {
List<SecurityRule> eigSecRulesAndOriginalSecRules = new ArrayList<>();
List<SecurityGroup> eigSecGroupAndOriginalSecGroup = new ArrayList<>();
// resolve EIG sec rules and groups
List<Network> routerExternalNetworks = NetworkUtils.findRouterExternalNetworks(originalNeutron.getNetworks());
Set<Uuid> tenantsFromRouterExternalNetwork = resolveTenantsFromNetworks(routerExternalNetworks);
for (Uuid tenantFromRouterExternalNetwork : tenantsFromRouterExternalNetwork) {
eigSecRulesAndOriginalSecRules.addAll(createEigSecurityRules(tenantFromRouterExternalNetwork));
eigSecGroupAndOriginalSecGroup
.add(EIG_SEC_GROUP_BUILDER.setTenantId(tenantFromRouterExternalNetwork).build());
}
// set new sec rules
SecurityRules newSecRules = null;
if (originalNeutron.getSecurityRules() != null) {
List<SecurityRule> originalSecRules = originalNeutron.getSecurityRules().getSecurityRule();
if (originalSecRules != null) {
eigSecRulesAndOriginalSecRules.addAll(originalSecRules);
}
newSecRules = new SecurityRulesBuilder(originalNeutron.getSecurityRules())
.setSecurityRule(eigSecRulesAndOriginalSecRules).build();
} else {
newSecRules = new SecurityRulesBuilder().setSecurityRule(eigSecRulesAndOriginalSecRules).build();
}
newNeutronBuilder.setSecurityRules(newSecRules);
// set new sec groups
SecurityGroups newSecGroups = null;
if (originalNeutron.getSecurityGroups() != null) {
List<SecurityGroup> originalSecGroups = originalNeutron.getSecurityGroups().getSecurityGroup();
if (originalSecGroups != null) {
eigSecGroupAndOriginalSecGroup.addAll(originalSecGroups);
}
newSecGroups = new SecurityGroupsBuilder(originalNeutron.getSecurityGroups())
.setSecurityGroup(eigSecGroupAndOriginalSecGroup).build();
} else {
newSecGroups = new SecurityGroupsBuilder().setSecurityGroup(eigSecGroupAndOriginalSecGroup).build();
}
newNeutronBuilder.setSecurityGroups(newSecGroups);
}
private Set<Uuid> resolveTenantsFromNetworks(List<Network> networks) {
return FluentIterable.from(networks).transform(new Function<Network, Uuid>() {
@Override
public Uuid apply(Network network) {
return network.getTenantId();
}
}).toSet();
}
private List<SecurityRule> createEigSecurityRules(Uuid tenant) {
List<SecurityRule> eigSecRules = new ArrayList<>();
eigSecRules.add(EIG_INGRESS_IPV4_SEC_RULE_BUILDER.setTenantId(tenant).build());
eigSecRules.add(EIG_EGRESS_IPV4_SEC_RULE_BUILDER.setTenantId(tenant).build());
eigSecRules.add(EIG_INGRESS_IPV6_SEC_RULE_BUILDER.setTenantId(tenant).build());
eigSecRules.add(EIG_EGRESS_IPV6_SEC_RULE_BUILDER.setTenantId(tenant).build());
return eigSecRules;
}
/**
* Finds all modified subnodes of given type in {@link Neutron} node.
*
* @param <T>
* @param iid path to data in root node
* @param rootNode modified data of {@link Neutron} node
* @return {@link List} of modified subnodes
*/
private <T extends DataObject> List<DataObjectModification<T>> findModifiedData(InstanceIdentifier<T> iid,
DataObjectModification<Neutron> rootNode) {
List<DataObjectModification<T>> modDtos = new ArrayList<>();
PeekingIterator<PathArgument> pathArgs = Iterators.peekingIterator(iid.getPathArguments().iterator());
DataObjectModification<? extends DataObject> modifDto = rootNode;
while (pathArgs.hasNext()) {
pathArgs.next();
for (DataObjectModification<? extends DataObject> childDto : modifDto.getModifiedChildren()) {
if (pathArgs.hasNext() && childDto.getDataType().equals(pathArgs.peek().getType())) {
if (childDto.getDataType().equals(iid.getTargetType())) {
modDtos.add((DataObjectModification<T>) childDto);
} else {
modifDto = childDto;
break;
}
}
}
}
return modDtos;
}
@Override
public void close() {
registerDataTreeChangeListener.close();
}
}