package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.ovsdb; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.ovsdb.southbound.SouthboundConstants; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder; 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.TpId; 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.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; public class OfOverlayOvsdbBridgeDataChangeListener implements DataChangeListener, AutoCloseable { private static final String REMOTE_IP_VALUE = "flow"; private static final String REMOTE_IP_KEY = "remote_ip"; private static final String VNID_KEY = "key"; private static final String VNID_VALUE = "flow"; private static final String OFOVERLAY_TUNNEL = "ofoverlay-tun"; private static final String OF_PORT = "6653"; private static boolean connectController = false; private ListenerRegistration registration; private DataBroker db; private static final Logger LOG = LoggerFactory.getLogger(OfOverlayOvsdbBridgeDataChangeListener.class); public OfOverlayOvsdbBridgeDataChangeListener(DataBroker db) { this.db = db; InstanceIdentifier iid = InstanceIdentifier .create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) .child(Node.class); registration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, iid, this, DataChangeScope.BASE); } @Override public void close() throws Exception { registration.close(); } @Override public void onDataChanged( AsyncDataChangeEvent, DataObject> change) { ReadWriteTransaction transaction = db.newReadWriteTransaction(); for (Entry, DataObject> entry :change.getCreatedData().entrySet()) { if(entry.getValue() instanceof Node) { Node node = (Node)entry.getValue(); InstanceIdentifier nodeIid = (InstanceIdentifier) entry.getKey(); OvsdbBridgeAugmentation bridge = node.getAugmentation(OvsdbBridgeAugmentation.class); if(bridge!= null) { Optional connectionOptional = getConnection(transaction, bridge); if(connectionOptional.isPresent()) { List options = getOptions(); OvsdbTerminationPointAugmentation ovsdbTp = getOvsdbTerminationPointAugmentation(bridge,options); List tps = getTerminationPoints(bridge,ovsdbTp); OvsdbBridgeAugmentation ovsdbBridgeAugmentation = getOvsdbBridgeAugmentation(bridge,connectionOptional.get()); Node configNode = getNode(node, tps,ovsdbBridgeAugmentation); LOG.info("About to write nodeId {} node {}",nodeIid,configNode); transaction.merge(LogicalDatastoreType.CONFIGURATION, nodeIid, configNode); } } } } transaction.submit(); } private Node getNode(Node node, List tps, OvsdbBridgeAugmentation ovsdbBridgeAugmentation) { NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setKey(node.getKey()); nodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentation); nodeBuilder.setTerminationPoint(tps); return nodeBuilder.build(); } private OvsdbBridgeAugmentation getOvsdbBridgeAugmentation(OvsdbBridgeAugmentation bridge, OvsdbNodeAugmentation connection) { OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentation = new OvsdbBridgeAugmentationBuilder(); List controllerEntries = getControllerEntries(connection); ovsdbBridgeAugmentation.setControllerEntry(controllerEntries); ovsdbBridgeAugmentation.setBridgeName(bridge.getBridgeName()); ovsdbBridgeAugmentation.setManagedBy(bridge.getManagedBy()); return ovsdbBridgeAugmentation.build(); } private List getTerminationPoints(OvsdbBridgeAugmentation bridge, OvsdbTerminationPointAugmentation ovsdbTp) { TerminationPointBuilder tpBuilder = new TerminationPointBuilder(); tpBuilder.setTpId(new TpId(new Uri(generateTpName(bridge)))); tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, ovsdbTp); List tps = new ArrayList(); tps.add(tpBuilder.build()); return tps; } private String generateTpName(OvsdbBridgeAugmentation bridge) { return OFOVERLAY_TUNNEL; } private OvsdbTerminationPointAugmentation getOvsdbTerminationPointAugmentation(OvsdbBridgeAugmentation bridge, List options) { OvsdbTerminationPointAugmentationBuilder ovsdbTpBuilder = new OvsdbTerminationPointAugmentationBuilder(); ovsdbTpBuilder.setName(generateTpName(bridge)); ovsdbTpBuilder.setOptions(options); ovsdbTpBuilder.setInterfaceType(InterfaceTypeVxlan.class); return ovsdbTpBuilder.build(); } private void setOption(List options, String key, String value) { OptionsBuilder option = new OptionsBuilder(); option.setOption(key); option.setValue(value); options.add(option.build()); } private List getOptions() { List options = new ArrayList(); setOption(options, REMOTE_IP_KEY, REMOTE_IP_VALUE); setOption(options, VNID_KEY, VNID_VALUE); return options; } private List getControllerEntries(OvsdbNodeAugmentation connection) { ControllerEntryBuilder controllerBuilder = new ControllerEntryBuilder(); List result = new ArrayList(); if (connectController == true && connection.getConnectionInfo().getLocalIp() != null) { String localIp = String.valueOf(connection.getConnectionInfo().getLocalIp().getValue()); String targetString = "tcp:" + localIp + ":" + OF_PORT; controllerBuilder.setTarget(new Uri(targetString)); result.add(controllerBuilder.build()); } return result; } private Optional getConnection(ReadWriteTransaction transaction,OvsdbBridgeAugmentation bridge) { OvsdbNodeRef bareIId = bridge.getManagedBy(); if(bareIId != null) { if(bareIId.getValue().getTargetType().equals(Node.class)) { InstanceIdentifier iid = (InstanceIdentifier) bareIId.getValue(); CheckedFuture, ReadFailedException> connectionFuture = transaction.read(LogicalDatastoreType.OPERATIONAL, iid); try { Optional nodeOptional = connectionFuture.get(); if(nodeOptional.isPresent() && nodeOptional.get().getAugmentation(OvsdbNodeAugmentation.class) != null) { return Optional.of(nodeOptional.get().getAugmentation(OvsdbNodeAugmentation.class)); } else { LOG.warn("Could not find ovsdb-node for connection for {}",bridge); } } catch (InterruptedException | ExecutionException e) { LOG.warn("Could not find ovsdb-node for connection for {}",bridge,e); } } else { LOG.warn("Bridge 'managedBy' non-ovsdb-node. bridge {} getManagedBy() {}",bridge,bareIId.getValue()); } } else { LOG.warn("Bridge 'managedBy' is null. bridge {}",bridge); } return Optional.absent(); } }