/* * 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.ip.sgt.distribution.service.impl; import com.google.common.base.Preconditions; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.sxp.util.time.TimeConv; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; 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.DateAndTime; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.IpSgtDistributionService; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.RemoveIpSgtBindingFromPeerInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SendIpSgtBindingToPeerInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.rpc.fields.Binding; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.rpc.fields.binding.PeerNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.SxpControllerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBinding; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.peer.sequence.fields.PeerSequenceBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.SxpNodeIdentity; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.SxpDomains; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomain; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomainKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.databases.fields.MasterDatabase; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.NodeId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class IpSgtDistributionServiceImpl implements AutoCloseable, IpSgtDistributionService { private static final Logger LOG = LoggerFactory.getLogger(IpSgtDistributionServiceImpl.class); public static final String SXP_NODE_DESCRIPTION = "ODL-GBP SXP node"; public static final String SXP_TOPOLOGY_ID = "sxp"; private final String SXP_NODE_ID; private DataBroker dataBroker; private IpAddress sourceIp; private SxpCapableNodeListener nodeCollector; public IpSgtDistributionServiceImpl(DataBroker dataBroker, SxpControllerService sxpService, IpAddress sourceIp) { this.dataBroker = Preconditions.checkNotNull(dataBroker); this.sourceIp = Preconditions.checkNotNull(sourceIp); Preconditions.checkNotNull(sxpService); if (sourceIp.getIpv4Address() != null) { SXP_NODE_ID = sourceIp.getIpv4Address().getValue(); } else { SXP_NODE_ID = sourceIp.getIpv6Address().getValue(); } createSxpNode(sxpService); nodeCollector = new SxpCapableNodeListener(dataBroker, SXP_NODE_ID); } private void createSxpNode(SxpControllerService sxpService) { AddNodeInput addNodeInput = new AddNodeInputBuilder().setNodeId(new NodeId(SXP_NODE_ID)) .setSourceIp(sourceIp) .setDescription(SXP_NODE_DESCRIPTION) .build(); Future<RpcResult<AddNodeOutput>> addNodeResult = sxpService.addNode(addNodeInput); try { if (! addNodeResult.get().getResult().isResult()) { LOG.error("RPC add-node wasn't successfull"); } } catch (Exception e) { LOG.error("RPC add-node wasn't successfull"); } } @Override public Future<RpcResult<Void>> sendIpSgtBindingToPeer(SendIpSgtBindingToPeerInput input) { Map<String, Multimap<Sgt, IpPrefix>> bindingsMap = new HashMap<>(); boolean success = true; for (Binding binding : input.getBinding()) { success = transformChanges(binding, bindingsMap); if (! success) { break; } } if (! success) { return Futures.immediateCheckedFuture(RpcResultBuilder.<Void>failed().build()); } WriteTransaction wtx = dataBroker.newWriteOnlyTransaction(); bindingsMap.entrySet().forEach(bindingEntries -> { String domainId = bindingEntries.getKey(); bindingEntries.getValue().entries().forEach(binding -> writeBinding(binding, domainId, wtx)); }); ListenableFuture<Void> submit = wtx.submit(); SettableFuture<RpcResult<Void>> future = SettableFuture.create(); Futures.addCallback(submit, new FutureCallback<Void>() { @Override public void onSuccess(Void result) { future.set(RpcResultBuilder.<Void>success().build()); } @Override public void onFailure(Throwable t) { future.set(RpcResultBuilder.<Void>failed().build()); } }); return future; } private boolean transformChanges(Binding binding, Map<String, Multimap<Sgt, IpPrefix>> bindingsMap) { Sgt sgt = binding.getSgt(); IpPrefix addr = binding.getIpPrefix(); for (PeerNode peer : binding.getPeerNode()) { String domainId = nodeCollector.getDomainIdForPeer((InstanceIdentifier<Node>) peer.getNodeIid()); if (domainId == null) { LOG.debug("Node {} is not SXP capable", peer.getNodeIid()); return false; } Multimap<Sgt, IpPrefix> domainBindingMap = bindingsMap.get(domainId); if (domainBindingMap == null) { domainBindingMap = ArrayListMultimap.create(); bindingsMap.put(domainId, domainBindingMap); } domainBindingMap.get(sgt).add(addr); } return true; } private void writeBinding(Entry<Sgt, IpPrefix> binding, String domainId, WriteTransaction wtx) { IpPrefix addr = binding.getValue(); InstanceIdentifier<MasterDatabaseBinding> iid = bindingIid(domainId, addr); MasterDatabaseBinding newBinding = createBinding(binding); wtx.put(LogicalDatastoreType.CONFIGURATION, iid, newBinding); } private InstanceIdentifier<MasterDatabaseBinding> bindingIid(String domainId, IpPrefix prefix) { return InstanceIdentifier.builder(NetworkTopology.class) .child(Topology.class, new TopologyKey(new TopologyId(SXP_TOPOLOGY_ID))) .child(Node.class, new NodeKey( new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId( SXP_NODE_ID))) .augmentation(SxpNodeIdentity.class) .child(SxpDomains.class) .child(SxpDomain.class, new SxpDomainKey(domainId)) .child(MasterDatabase.class) .child(MasterDatabaseBinding.class, new MasterDatabaseBindingKey(prefix)) .build(); } private MasterDatabaseBinding createBinding(Entry<Sgt, IpPrefix> binding) { final DateAndTime nowDateTime = TimeConv.toDt(System.currentTimeMillis()); return new MasterDatabaseBindingBuilder() .setIpPrefix(binding.getValue()) .setSecurityGroupTag(binding.getKey()) .setPeerSequence(new PeerSequenceBuilder().build()) .setTimestamp(nowDateTime) .build(); } @Override public Future<RpcResult<Void>> removeIpSgtBindingFromPeer(RemoveIpSgtBindingFromPeerInput input) { Map<String, Multimap<Sgt, IpPrefix>> bindingsMap = new HashMap<>(); boolean success = true; for (Binding binding : input.getBinding()) { success = transformChanges(binding, bindingsMap); if (! success) { break; } } if (! success) { return Futures.immediateCheckedFuture(RpcResultBuilder.<Void>failed().build()); } WriteTransaction wtx = dataBroker.newWriteOnlyTransaction(); bindingsMap.entrySet().forEach(bindingEntries -> { String domainId = bindingEntries.getKey(); bindingEntries.getValue().entries().forEach(binding -> removeBinding(binding, domainId, wtx)); }); ListenableFuture<Void> submit = wtx.submit(); SettableFuture<RpcResult<Void>> future = SettableFuture.create(); Futures.addCallback(submit, new FutureCallback<Void>() { @Override public void onSuccess(Void result) { future.set(RpcResultBuilder.<Void>success().build()); } @Override public void onFailure(Throwable t) { future.set(RpcResultBuilder.<Void>failed().build()); } }); return future; } private void removeBinding(Entry<Sgt, IpPrefix> binding, String domainId, WriteTransaction wtx) { IpPrefix addr = binding.getValue(); InstanceIdentifier<MasterDatabaseBinding> iid = bindingIid(domainId, addr); wtx.delete(LogicalDatastoreType.CONFIGURATION, iid); } @Override public void close() throws Exception { nodeCollector.close(); } }