/* * Copyright (c) 2016 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.sxp.ep.provider.impl; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.JdkFutureAdapters; import com.google.common.util.concurrent.ListenableFuture; import java.util.Collections; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.groupbasedpolicy.sxp.ep.provider.impl.util.SxpListenerUtil; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.BaseEndpointService; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.Endpoints; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainment; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainmentBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainmentBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.AddressEndpoints; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointReg; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointRegBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L3Context; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ep.provider.model.rev160302.sxp.ep.mapper.EndpointForwardingTemplateBySubnet; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ep.provider.model.rev160302.sxp.ep.mapper.EndpointPolicyTemplateBySgt; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBinding; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Purpose: exclusively processes sxp master database changes and EGP templates changes */ public class SxpMapperReactorImpl implements SxpMapperReactor { private static final Logger LOG = LoggerFactory.getLogger(SxpMapperReactorImpl.class); private final BaseEndpointService l3EndpointService; private final DataBroker dataBroker; public SxpMapperReactorImpl(final BaseEndpointService l3EndpointService, final DataBroker dataBroker) { this.l3EndpointService = Preconditions.checkNotNull(l3EndpointService, "l3Endpoint service missing"); this.dataBroker = Preconditions.checkNotNull(dataBroker, "dataBroker missing"); } @Override public ListenableFuture<RpcResult<Void>> processTemplatesAndSxpMasterDB( final EndpointPolicyTemplateBySgt epPolicyTemplate, final EndpointForwardingTemplateBySubnet epForwardingTemplate, final MasterDatabaseBinding masterDBBinding) { LOG.debug("processing ep-templates + sxpMasterDB entry: {} - {}", masterDBBinding.getSecurityGroupTag(), masterDBBinding.getIpPrefix()); // apply sxpMasterDB to policy template final Ipv4Prefix address = new Ipv4Prefix(epForwardingTemplate.getIpPrefix().getIpv4Prefix().getValue()); final NetworkContainment networkContainment = new NetworkContainmentBuilder() .setContainment(new NetworkDomainContainmentBuilder() .setNetworkDomainType(epForwardingTemplate.getNetworkContainment().getNetworkDomainType()) .setNetworkDomainId(epForwardingTemplate.getNetworkContainment().getNetworkDomainId()) .build()) .build(); final RegisterEndpointInput epInput = new RegisterEndpointInputBuilder().setAddressEndpointReg( Collections.singletonList(new AddressEndpointRegBuilder().setAddressType(IpPrefixType.class) .setAddress(address.getValue()) .setContextType(L3Context.class) .setContextId(epForwardingTemplate.getL3Context()) .setNetworkContainment(networkContainment) .setCondition(epPolicyTemplate.getConditions()) .setTenant(epPolicyTemplate.getTenant()) .setEndpointGroup(epPolicyTemplate.getEndpointGroups()) .build())) .build(); epForwardingTemplate.getL3Context(); return chainL3EPServiceIfEpAbsent(epInput); } private CheckedFuture<Optional<AddressEndpoint>, ReadFailedException> findExistingEndPoint(final ContextId containment, final String address) { KeyedInstanceIdentifier<AddressEndpoint, AddressEndpointKey> addressEndpointPath = InstanceIdentifier.create(Endpoints.class).child(AddressEndpoints.class).child(AddressEndpoint.class, new AddressEndpointKey(address, IpPrefixType.class, containment, L3Context.class)); final ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction(); final CheckedFuture<Optional<AddressEndpoint>, ReadFailedException> read = rTx.read( LogicalDatastoreType.OPERATIONAL, addressEndpointPath); Futures.addCallback(read, SxpListenerUtil.createTxCloseCallback(rTx)); return read; } private ListenableFuture<RpcResult<Void>> chainL3EPServiceIfEpAbsent(final RegisterEndpointInput epInput) { AddressEndpointReg addressEndpoint = epInput.getAddressEndpointReg().get(0); CheckedFuture<Optional<AddressEndpoint>, ReadFailedException> existingEndpointFuture = findExistingEndPoint(addressEndpoint.getContextId(), addressEndpoint.getAddress()); return Futures.transform(existingEndpointFuture, new AsyncFunction<Optional<AddressEndpoint>, RpcResult<Void>>() { @Override public ListenableFuture<RpcResult<Void>> apply(final Optional<AddressEndpoint> input) throws Exception { final ListenableFuture<RpcResult<Void>> nextResult; if (input == null || !input.isPresent() || !isSameEpg(epInput, input.get())) { // invoke service return JdkFutureAdapters.listenInPoolThread(l3EndpointService.registerEndpoint(epInput)); } else { final String existingL3EpMsg = String.format("address-endpoint for given key already exists: %s | %s", addressEndpoint.getContextId(), addressEndpoint.getAddress() ); nextResult = Futures.immediateFailedFuture(new IllegalStateException(existingL3EpMsg)); } return nextResult; } }); } private boolean isSameEpg(RegisterEndpointInput epInput, AddressEndpoint input) { if (epInput == null || epInput.getAddressEndpointReg() == null || epInput.getAddressEndpointReg().isEmpty()) { return true; } final AddressEndpointReg epInputAddressEndpoint = epInput.getAddressEndpointReg().get(0); if (epInputAddressEndpoint.getEndpointGroup() == null || epInputAddressEndpoint.getEndpointGroup().isEmpty()) { return true; } if (input == null || input.getEndpointGroup() == null || input.getEndpointGroup().isEmpty()) { return true; } final EndpointGroupId addressEndpointGroupId = epInputAddressEndpoint.getEndpointGroup().get(0); final EndpointGroupId existingEndpointGroupId = input.getEndpointGroup().get(0); return addressEndpointGroupId.equals(existingEndpointGroupId); } }