X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=utils%2Fsouthbound-utils%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fovsdb%2Futils%2Fsouthbound%2Futils%2FSouthboundUtils.java;h=77bacdc2b8f2060497a16c53d1d4fcd136c4fad0;hb=2eea33c2efaa563d8f113784ebf378fecc02c6bd;hp=7ac9a396bb8c244232eb5788dd3aab3b48ffda90;hpb=685f586c67dc369259fc53a001f3d8297c6d8351;p=ovsdb.git diff --git a/utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java b/utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java index 7ac9a396b..77bacdc2b 100644 --- a/utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java +++ b/utils/southbound-utils/src/main/java/org/opendaylight/ovsdb/utils/southbound/utils/SouthboundUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Red Hat, Inc. and others. All rights reserved. + * Copyright (c) 2015 - 2017 Red Hat, 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, @@ -8,119 +8,293 @@ package org.opendaylight.ovsdb.utils.southbound.utils; -import com.google.common.collect.ImmutableBiMap; +import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.UnknownHostException; +import java.security.InvalidParameterException; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; - +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.ovsdb.southbound.SouthboundConstants; -import org.opendaylight.ovsdb.southbound.SouthboundMapper; +import org.opendaylight.ovsdb.utils.config.ConfigProperties; import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil; +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.Ipv6Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeNetdev; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdk; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkr; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkvhost; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkvhostuser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeDpdkvhostuserclient; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGeneve; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre64; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeInternal; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeIpsecGre; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeIpsecGre64; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeLisp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypePatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeSystem; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeTap; +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.InterfaceTypeVxlanGpe; 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.OvsdbBridgeName; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolBase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow10; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow11; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow12; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow13; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow14; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow15; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeBase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeSecure; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeStandalone; 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.OvsdbNodeAugmentationBuilder; 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.BridgeExternalIds; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder; 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.bridge.attributes.ProtocolEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagedNodeEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsKey; +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.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey; 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.NodeId; +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.NodeKey; +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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.collect.ImmutableBiMap; + public class SouthboundUtils { private static final Logger LOG = LoggerFactory.getLogger(SouthboundUtils.class); private static final int OVSDB_UPDATE_TIMEOUT = 1000; - private static final String DEFAULT_OPENFLOW_PORT = "6653"; - private static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp"; - private MdsalUtils mdsalUtils; + public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1")); + private final MdsalUtils mdsalUtils; + public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp"; + public static short OPENFLOW_PORT = 6653; + public static final String OVSDB_URI_PREFIX = "ovsdb"; + public static final String BRIDGE_URI_PREFIX = "bridge"; + private static final String DISABLE_IN_BAND = "disable-in-band"; + private static final String PATCH_PORT_TYPE = "patch"; + // External ID key used for mapping between an OVSDB port and an interface name + private static final String EXTERNAL_INTERFACE_ID_KEY = "iface-id"; + + private static final String FORMAT = "(\\d+)\\.(\\d+)\\.(\\d+)"; + private static final Pattern PATTERN = Pattern.compile(FORMAT); + public SouthboundUtils(MdsalUtils mdsalUtils) { this.mdsalUtils = mdsalUtils; } - public NodeId createNodeId(IpAddress ip, PortNumber port) { - String uriString = SouthboundConstants.OVSDB_URI_PREFIX + "://" - + new String(ip.getValue()) + ":" + port.getValue(); + public static final ImmutableBiMap> OVSDB_INTERFACE_TYPE_MAP + = new ImmutableBiMap.Builder>() + .put("internal", InterfaceTypeInternal.class) + .put("vxlan", InterfaceTypeVxlan.class) + .put("vxlan-gpe", InterfaceTypeVxlanGpe.class) + .put("patch", InterfaceTypePatch.class) + .put("system", InterfaceTypeSystem.class) + .put("tap", InterfaceTypeTap.class) + .put("geneve", InterfaceTypeGeneve.class) + .put("gre", InterfaceTypeGre.class) + .put("ipsec_gre", InterfaceTypeIpsecGre.class) + .put("gre64", InterfaceTypeGre64.class) + .put("ipsec_gre64", InterfaceTypeIpsecGre64.class) + .put("lisp", InterfaceTypeLisp.class) + .put("dpdk", InterfaceTypeDpdk.class) + .put("dpdkr", InterfaceTypeDpdkr.class) + .put("dpdkvhost", InterfaceTypeDpdkvhost.class) + .put("dpdkvhostuser", InterfaceTypeDpdkvhostuser.class) + .put("dpdkvhostuserclient", InterfaceTypeDpdkvhostuserclient.class) + .build(); + + public static final ImmutableBiMap,String> OVSDB_PROTOCOL_MAP + = new ImmutableBiMap.Builder,String>() + .put(OvsdbBridgeProtocolOpenflow10.class,"OpenFlow10") + .put(OvsdbBridgeProtocolOpenflow11.class,"OpenFlow11") + .put(OvsdbBridgeProtocolOpenflow12.class,"OpenFlow12") + .put(OvsdbBridgeProtocolOpenflow13.class,"OpenFlow13") + .put(OvsdbBridgeProtocolOpenflow14.class,"OpenFlow14") + .put(OvsdbBridgeProtocolOpenflow15.class,"OpenFlow15") + .build(); + + private static final ImmutableBiMap,String> OVSDB_FAIL_MODE_MAP + = new ImmutableBiMap.Builder,String>() + .put(OvsdbFailModeStandalone.class,"standalone") + .put(OvsdbFailModeSecure.class,"secure") + .build(); + + public static NodeId createNodeId(IpAddress ip, PortNumber port) { + String uriString = OVSDB_URI_PREFIX + "://" + + String.valueOf(ip.getValue()) + ":" + port.getValue(); Uri uri = new Uri(uriString); return new NodeId(uri); } - public Node createNode(ConnectionInfo key) { + public static Node createNode(ConnectionInfo key) { NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setNodeId(createNodeId(key.getRemoteIp(), key.getRemotePort())); nodeBuilder.addAugmentation(OvsdbNodeAugmentation.class, createOvsdbAugmentation(key)); return nodeBuilder.build(); } - public OvsdbNodeAugmentation createOvsdbAugmentation(ConnectionInfo key) { + public static OvsdbNodeAugmentation createOvsdbAugmentation(ConnectionInfo key) { OvsdbNodeAugmentationBuilder ovsdbNodeBuilder = new OvsdbNodeAugmentationBuilder(); ovsdbNodeBuilder.setConnectionInfo(key); return ovsdbNodeBuilder.build(); } - public InstanceIdentifier createInstanceIdentifier(ConnectionInfo key) { + public static InstanceIdentifier createInstanceIdentifier(NodeId nodeId) { + return InstanceIdentifier + .create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID)) + .child(Node.class,new NodeKey(nodeId)); + } + + public static InstanceIdentifier createInstanceIdentifier(NodeKey ovsdbNodeKey, String bridgeName) { + return createInstanceIdentifier(createManagedNodeId(ovsdbNodeKey.getNodeId(), bridgeName)); + } + + public static NodeId createManagedNodeId(NodeId ovsdbNodeId, String bridgeName) { + return new NodeId(ovsdbNodeId.getValue() + + "/" + BRIDGE_URI_PREFIX + "/" + bridgeName); + } + + public static InstanceIdentifier createInstanceIdentifier(ConnectionInfo key) { return createInstanceIdentifier(key.getRemoteIp(), key.getRemotePort()); } - public InstanceIdentifier createInstanceIdentifier(IpAddress ip, PortNumber port) { + public static InstanceIdentifier createInstanceIdentifier(IpAddress ip, PortNumber port) { InstanceIdentifier path = InstanceIdentifier .create(NetworkTopology.class) - .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) + .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID)) .child(Node.class,createNodeKey(ip,port)); LOG.debug("Created ovsdb path: {}",path); return path; } - public InstanceIdentifier createInstanceIdentifier(ConnectionInfo key,OvsdbBridgeName bridgeName) { - return SouthboundMapper.createInstanceIdentifier(createManagedNodeId(key, bridgeName)); + public static InstanceIdentifier createInstanceIdentifier(ConnectionInfo key,OvsdbBridgeName bridgeName) { + return createInstanceIdentifier(createManagedNodeId(key, bridgeName)); + } + + public static InstanceIdentifier createInstanceIdentifier(ConnectionInfo key, String bridgeName) { + return createInstanceIdentifier(key, new OvsdbBridgeName(bridgeName)); + } + + public InstanceIdentifier createTerminationPointInstanceIdentifier(Node node, String portName){ + + InstanceIdentifier terminationPointPath = InstanceIdentifier + .create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID)) + .child(Node.class,node.getKey()) + .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName))); + + LOG.debug("Termination point InstanceIdentifier generated : {}",terminationPointPath); + return terminationPointPath; } - public NodeKey createNodeKey(IpAddress ip, PortNumber port) { + public static NodeKey createNodeKey(IpAddress ip, PortNumber port) { return new NodeKey(createNodeId(ip, port)); } - public NodeId createManagedNodeId(ConnectionInfo key, OvsdbBridgeName bridgeName) { + public static NodeId createManagedNodeId(ConnectionInfo key, OvsdbBridgeName bridgeName) { return createManagedNodeId(key.getRemoteIp(), key.getRemotePort(), bridgeName); } - public NodeId createManagedNodeId(IpAddress ip, PortNumber port, OvsdbBridgeName bridgeName) { + public static NodeId createManagedNodeId(IpAddress ip, PortNumber port, OvsdbBridgeName bridgeName) { return new NodeId(createNodeId(ip,port).getValue() - + "/" + SouthboundConstants.BRIDGE_URI_PREFIX + "/" + bridgeName.getValue()); + + "/" + BRIDGE_URI_PREFIX + "/" + bridgeName.getValue()); + } + + public static NodeId createManagedNodeId(InstanceIdentifier iid) { + NodeKey nodeKey = iid.firstKeyOf(Node.class); + return nodeKey.getNodeId(); + } + + public ConnectionInfo getConnectionInfo(Node ovsdbNode) { + ConnectionInfo connectionInfo = null; + OvsdbNodeAugmentation ovsdbNodeAugmentation = extractOvsdbNode(ovsdbNode); + if (ovsdbNodeAugmentation != null) { + connectionInfo = ovsdbNodeAugmentation.getConnectionInfo(); + } + return connectionInfo; + } + + public OvsdbNodeAugmentation extractOvsdbNode(Node node) { + return node.getAugmentation(OvsdbNodeAugmentation.class); } - public ConnectionInfo getConnectionInfo(final String addressStr, final String portStr) { + public static IpAddress createIpAddress(InetAddress address) { + IpAddress ip = null; + if (address instanceof Inet4Address) { + ip = createIpAddress((Inet4Address)address); + } else if (address instanceof Inet6Address) { + ip = createIpAddress((Inet6Address)address); + } + return ip; + } + + public static IpAddress createIpAddress(Inet4Address address) { + return IetfInetUtil.INSTANCE.ipAddressFor(address); + } + + public static IpAddress createIpAddress(Inet6Address address) { + Ipv6Address ipv6 = new Ipv6Address(address.getHostAddress()); + return new IpAddress(ipv6); + } + + public static ConnectionInfo getConnectionInfo(final String addressStr, final String portStr) { InetAddress inetAddress = null; try { inetAddress = InetAddress.getByName(addressStr); } catch (UnknownHostException e) { - LOG.warn("Could not allocate InetAddress"); + LOG.warn("Could not allocate InetAddress", e); } - IpAddress address = SouthboundMapper.createIpAddress(inetAddress); + IpAddress address = createIpAddress(inetAddress); PortNumber port = new PortNumber(Integer.parseInt(portStr)); LOG.info("connectionInfo: {}", new ConnectionInfoBuilder() @@ -133,48 +307,70 @@ public class SouthboundUtils { .build(); } - public String connectionInfoToString(final ConnectionInfo connectionInfo) { - return new String(connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue(); + public static String connectionInfoToString(final ConnectionInfo connectionInfo) { + return String.valueOf( + connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue(); } public boolean addOvsdbNode(final ConnectionInfo connectionInfo) { + return addOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT); + } + + public boolean addOvsdbNode(final ConnectionInfo connectionInfo, long timeout) { boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, createInstanceIdentifier(connectionInfo), createNode(connectionInfo)); - try { - Thread.sleep(OVSDB_UPDATE_TIMEOUT); - } catch (InterruptedException e) { - e.printStackTrace(); + if (timeout != 0) { + try { + Thread.sleep(timeout); + } catch (InterruptedException e) { + LOG.warn("Interrupted while waiting after adding OVSDB node {}", + connectionInfoToString(connectionInfo), e); + } } return result; } public Node getOvsdbNode(final ConnectionInfo connectionInfo) { - Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, + return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, createInstanceIdentifier(connectionInfo)); - return node; } public boolean deleteOvsdbNode(final ConnectionInfo connectionInfo) { + return deleteOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT); + } + + public boolean deleteOvsdbNode(final ConnectionInfo connectionInfo, long timeout) { boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, createInstanceIdentifier(connectionInfo)); - try { - Thread.sleep(OVSDB_UPDATE_TIMEOUT); - } catch (InterruptedException e) { - e.printStackTrace(); + if (timeout != 0) { + try { + Thread.sleep(timeout); + } catch (InterruptedException e) { + LOG.warn("Interrupted while waiting after deleting OVSDB node {}", + connectionInfoToString(connectionInfo), e); + } } return result; } public Node connectOvsdbNode(final ConnectionInfo connectionInfo) { - addOvsdbNode(connectionInfo); + return connectOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT); + } + + public Node connectOvsdbNode(final ConnectionInfo connectionInfo, long timeout) { + addOvsdbNode(connectionInfo, timeout); Node node = getOvsdbNode(connectionInfo); LOG.info("Connected to {}", connectionInfoToString(connectionInfo)); return node; } public boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) { - deleteOvsdbNode(connectionInfo); + return disconnectOvsdbNode(connectionInfo, OVSDB_UPDATE_TIMEOUT); + } + + public boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo, long timeout) { + deleteOvsdbNode(connectionInfo, timeout); LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo)); return true; } @@ -233,14 +429,70 @@ public class SouthboundUtils { return mdsalUtils.read(store, bridgeIid); } + public Node getBridgeNode(Node node, String bridgeName) { + OvsdbBridgeAugmentation bridge = extractBridgeAugmentation(node); + if (bridge != null && bridge.getBridgeName().getValue().equals(bridgeName)) { + return node; + } else { + return readBridgeNode(node, bridgeName); + } + } + + public Node readBridgeNode(Node node, String name) { + Node ovsdbNode = node; + if (extractNodeAugmentation(ovsdbNode) == null) { + ovsdbNode = readOvsdbNode(node); + if (ovsdbNode == null) { + return null; + } + } + Node bridgeNode = null; + ConnectionInfo connectionInfo = getConnectionInfo(ovsdbNode); + if (connectionInfo != null) { + InstanceIdentifier bridgeIid = + createInstanceIdentifier(node.getKey(), name); + bridgeNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeIid); + } + return bridgeNode; + } + + public OvsdbNodeAugmentation extractNodeAugmentation(Node node) { + return node.getAugmentation(OvsdbNodeAugmentation.class); + } + + public OvsdbBridgeAugmentation extractBridgeAugmentation(Node node) { + if (node == null) { + return null; + } + return node.getAugmentation(OvsdbBridgeAugmentation.class); + } + + public Node readOvsdbNode(Node bridgeNode) { + Node ovsdbNode = null; + OvsdbBridgeAugmentation bridgeAugmentation = extractBridgeAugmentation(bridgeNode); + if (bridgeAugmentation != null) { + InstanceIdentifier ovsdbNodeIid = + (InstanceIdentifier) bridgeAugmentation.getManagedBy().getValue(); + ovsdbNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, ovsdbNodeIid); + }else{ + LOG.debug("readOvsdbNode: Provided node is not a bridge node : {}",bridgeNode); + } + return ovsdbNode; + } + public boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName) { + return deleteBridge(connectionInfo, bridgeName, OVSDB_UPDATE_TIMEOUT); + } + public boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName, long timeout) { boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName))); - try { - Thread.sleep(OVSDB_UPDATE_TIMEOUT); - } catch (InterruptedException e) { - e.printStackTrace(); + if (timeout != 0) { + try { + Thread.sleep(timeout); + } catch (InterruptedException e) { + LOG.warn("Interrupted while waiting after deleting bridge {}", bridgeName, e); + } } return result; } @@ -248,11 +500,23 @@ public class SouthboundUtils { public List createMdsalProtocols() { List protocolList = new ArrayList<>(); ImmutableBiMap> mapper = - SouthboundConstants.OVSDB_PROTOCOL_MAP.inverse(); + OVSDB_PROTOCOL_MAP.inverse(); protocolList.add(new ProtocolEntryBuilder().setProtocol(mapper.get("OpenFlow13")).build()); return protocolList; } + public boolean addBridge(final ConnectionInfo connectionInfo, InstanceIdentifier bridgeIid, + final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries, + final Class failMode, final boolean setManagedBy, + final Class dpType, + final List externalIds, + final List controllerEntries, + final List otherConfigs, + final String dpid) throws InterruptedException { + return addBridge(connectionInfo, bridgeIid, bridgeName, bridgeNodeId, setProtocolEntries, failMode, + setManagedBy, dpType, externalIds, controllerEntries, otherConfigs, dpid); + } + /* * base method for adding test bridges. Other helper methods used to create bridges should utilize this method. * @@ -270,19 +534,20 @@ public class SouthboundUtils { * @throws InterruptedException */ public boolean addBridge(final ConnectionInfo connectionInfo, InstanceIdentifier bridgeIid, - final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries, - final Class failMode, final boolean setManagedBy, - final Class dpType, - final List externalIds, - final List controllerEntries, - final List otherConfigs) throws InterruptedException { + final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries, + final Class failMode, final boolean setManagedBy, + final Class dpType, + final List externalIds, + final List controllerEntries, + final List otherConfigs, + final String dpid, long timeout) throws InterruptedException { NodeBuilder bridgeNodeBuilder = new NodeBuilder(); if (bridgeIid == null) { bridgeIid = createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName)); } if (bridgeNodeId == null) { - bridgeNodeId = SouthboundMapper.createManagedNodeId(bridgeIid); + bridgeNodeId = createManagedNodeId(bridgeIid); } bridgeNodeBuilder.setNodeId(bridgeNodeId); OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder(); @@ -308,18 +573,699 @@ public class SouthboundUtils { if (otherConfigs != null) { ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(otherConfigs); } + if (dpid != null && !dpid.isEmpty()) { + DatapathId datapathId = new DatapathId(dpid); + ovsdbBridgeAugmentationBuilder.setDatapathId(datapathId); + } bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build()); LOG.debug("Built with the intent to store bridge data {}", ovsdbBridgeAugmentationBuilder.toString()); boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid, bridgeNodeBuilder.build()); - Thread.sleep(OVSDB_UPDATE_TIMEOUT); + if (timeout != 0) { + Thread.sleep(OVSDB_UPDATE_TIMEOUT); + } + return result; + } + + /** + * Set the controllers of an existing bridge node + * @param ovsdbNode where the bridge is + * @param bridgeName Name of the bridge + * @param controllers controller strings + * @return success if the write to md-sal was successful + */ + public boolean setBridgeController(Node ovsdbNode, String bridgeName, List controllers) { + return setBridgeController(ovsdbNode, bridgeName, controllers, null, null); + } + /** + * Set the controllers of an existing bridge node + * @param ovsdbNode where the bridge is + * @param bridgeName Name of the bridge + * @param controllers controller strings + * @param maxBackoff Max backoff in milliseconds + * @param inactivityProbe inactivity probe in milliseconds + * @return success if the write to md-sal was successful + */ + public boolean setBridgeController(Node ovsdbNode, String bridgeName, List controllers, + Long maxBackoff, Long inactivityProbe) { + LOG.debug("setBridgeController: ovsdbNode: {}, bridgeNode: {}, controller(s): {}", + ovsdbNode, bridgeName, controllers); + + InstanceIdentifier bridgeNodeIid = createInstanceIdentifier(ovsdbNode.getKey(), bridgeName); + Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, bridgeNodeIid); + if (bridgeNode == null) { + LOG.info("setBridgeController could not find bridge in configuration {}", bridgeNodeIid); + return false; + } + + OvsdbBridgeAugmentation bridgeAug = extractBridgeAugmentation(bridgeNode); + + //Only add controller entries that do not already exist on this bridge + List existingControllerEntries = bridgeAug.getControllerEntry(); + List newControllerEntries = new ArrayList<>(); + if(existingControllerEntries != null) { + NEW_ENTRY_LOOP: + for (ControllerEntry newEntry : createControllerEntries(controllers, maxBackoff, inactivityProbe)) { + for (ControllerEntry existingEntry : existingControllerEntries) { + if (newEntry.getTarget().equals(existingEntry.getTarget())) { + continue NEW_ENTRY_LOOP; + } + } + newControllerEntries.add(newEntry); + } + } else { + newControllerEntries = createControllerEntries(controllers,maxBackoff, inactivityProbe); + } + + if(newControllerEntries.isEmpty()) { + return true; + } + + NodeBuilder nodeBuilder = new NodeBuilder(bridgeNode); + OvsdbBridgeAugmentationBuilder augBuilder = new OvsdbBridgeAugmentationBuilder(bridgeAug); + + augBuilder.setControllerEntry(newControllerEntries); + nodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, augBuilder.build()); + InstanceIdentifier bridgeIid = createInstanceIdentifier(ovsdbNode.getKey(), bridgeName); + return mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid, nodeBuilder.build()); + } + + public boolean addBridge(Node ovsdbNode, String bridgeName, List controllersStr, + final Class dpType, String mac) { + return addBridge(ovsdbNode, bridgeName, controllersStr, dpType, mac, null, null); + } + + public boolean addBridge(Node ovsdbNode, String bridgeName, List controllersStr, + final Class dpType, String mac, + Long maxBackoff, Long inactivityProbe) { + List otherConfigs = new ArrayList<>(); + if (mac != null) { + BridgeOtherConfigsBuilder macOtherConfigBuilder = new BridgeOtherConfigsBuilder(); + macOtherConfigBuilder.setBridgeOtherConfigKey("hwaddr"); + macOtherConfigBuilder.setBridgeOtherConfigValue(mac); + otherConfigs.add(macOtherConfigBuilder.build()); + } + + return addBridge(ovsdbNode, bridgeName, controllersStr, dpType, otherConfigs, null, null); + } + + public boolean addBridge(Node ovsdbNode, String bridgeName, List controllersStr, + final Class dpType, + List otherConfigs, + Long maxBackoff, Long inactivityProbe) { + boolean result; + + LOG.info("addBridge: node: {}, bridgeName: {}, controller(s): {}", ovsdbNode, bridgeName, controllersStr); + ConnectionInfo connectionInfo = getConnectionInfo(ovsdbNode); + if (connectionInfo != null) { + NodeBuilder bridgeNodeBuilder = new NodeBuilder(); + InstanceIdentifier bridgeIid = createInstanceIdentifier(ovsdbNode.getKey(), bridgeName); + NodeId bridgeNodeId = createManagedNodeId(bridgeIid); + bridgeNodeBuilder.setNodeId(bridgeNodeId); + OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder(); + ovsdbBridgeAugmentationBuilder.setControllerEntry(createControllerEntries( + controllersStr, maxBackoff, inactivityProbe)); + ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName)); + ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols()); + ovsdbBridgeAugmentationBuilder.setFailMode( OVSDB_FAIL_MODE_MAP.inverse().get("secure")); + // TODO: Currently netvirt relies on this function to set disabled-in-band=true. However, + // TODO (cont): a better design would be to have netvirt pass that in. That way this function + // TODO (cont): can take a null otherConfigs to erase other_configs. + if (otherConfigs == null) { + otherConfigs = new ArrayList<>(); + } + BridgeOtherConfigsBuilder bridgeOtherConfigsBuilder = new BridgeOtherConfigsBuilder(); + bridgeOtherConfigsBuilder.setBridgeOtherConfigKey(DISABLE_IN_BAND); + bridgeOtherConfigsBuilder.setBridgeOtherConfigValue("true"); + otherConfigs.add(bridgeOtherConfigsBuilder.build()); + ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(otherConfigs); + setManagedByForBridge(ovsdbBridgeAugmentationBuilder, ovsdbNode.getKey()); + if (dpType != null) { + ovsdbBridgeAugmentationBuilder.setDatapathType(dpType); + } + if (isOvsdbNodeDpdk(ovsdbNode)) { + ovsdbBridgeAugmentationBuilder.setDatapathType(DatapathTypeNetdev.class); + } + bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build()); + + Node node = bridgeNodeBuilder.build(); + result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, bridgeIid, node); + LOG.info("addBridge: result: {}", result); + } else { + throw new InvalidParameterException("Could not find ConnectionInfo"); + } return result; } + private void setManagedBy(final OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder, final ConnectionInfo connectionInfo) { InstanceIdentifier connectionNodePath = createInstanceIdentifier(connectionInfo); ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath)); } + + public boolean addTerminationPoint( + Node bridgeNode, String portName, String type, Map options, + Map externalIds) { + return addTerminationPoint(bridgeNode, portName, type, options, externalIds, null); + } + + public boolean addTerminationPoint( + Node bridgeNode, String portName, String type, Map options, Map externalIds, + Long ofPort) { + InstanceIdentifier tpIid = createTerminationPointInstanceIdentifier(bridgeNode, portName); + OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder(); + + tpAugmentationBuilder.setName(portName); + tpAugmentationBuilder.setOfport(ofPort); + if (type != null) { + tpAugmentationBuilder.setInterfaceType(OVSDB_INTERFACE_TYPE_MAP.get(type)); + } + + if (options != null && options.size() > 0) { + List optionsList = new ArrayList<>(); + for (Map.Entry entry : options.entrySet()) { + OptionsBuilder optionsBuilder = new OptionsBuilder(); + optionsBuilder.setKey(new OptionsKey(entry.getKey())); + optionsBuilder.setOption(entry.getKey()); + optionsBuilder.setValue(entry.getValue()); + optionsList.add(optionsBuilder.build()); + } + tpAugmentationBuilder.setOptions(optionsList); + } + + if (externalIds != null && externalIds.size() > 0) { + List externalIdsList = new ArrayList<>(); + for (Map.Entry entry : externalIds.entrySet()) { + InterfaceExternalIdsBuilder interfaceExternalIdsBuilder = new InterfaceExternalIdsBuilder(); + interfaceExternalIdsBuilder.setKey(new InterfaceExternalIdsKey(entry.getKey())); + interfaceExternalIdsBuilder.setExternalIdKey(entry.getKey()); + interfaceExternalIdsBuilder.setExternalIdValue(entry.getValue()); + externalIdsList.add(interfaceExternalIdsBuilder.build()); + } + tpAugmentationBuilder.setInterfaceExternalIds(externalIdsList); + } + + TerminationPointBuilder tpBuilder = new TerminationPointBuilder(); + tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid)); + tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build()); + /* TODO SB_MIGRATION should this be merge or mdsalUtils.put */ + return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build()); + } + + public Boolean addTerminationPoint(Node bridgeNode, String portName, String type) { + return addTerminationPoint(bridgeNode, portName, type, Collections.EMPTY_MAP, null); + } + + public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName, + String type, Map options) { + InstanceIdentifier tpIid = createTerminationPointInstanceIdentifier( + bridgeNode, portName); + OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder(); + + tpAugmentationBuilder.setName(portName); + if (type != null) { + tpAugmentationBuilder.setInterfaceType(OVSDB_INTERFACE_TYPE_MAP.get(type)); + } + + List optionsList = new ArrayList<>(); + for (Map.Entry entry : options.entrySet()) { + OptionsBuilder optionsBuilder = new OptionsBuilder(); + optionsBuilder.setKey(new OptionsKey(entry.getKey())); + optionsBuilder.setOption(entry.getKey()); + optionsBuilder.setValue(entry.getValue()); + optionsList.add(optionsBuilder.build()); + } + tpAugmentationBuilder.setOptions(optionsList); + + TerminationPointBuilder tpBuilder = new TerminationPointBuilder(); + tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid)); + tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build()); + /* TODO SB_MIGRATION should this be merge or mdsalUtils.put */ + return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build()); + } + + public Boolean addTerminationPoint(Node bridgeNode, String bridgeName, String portName, String type) { + InstanceIdentifier tpIid = createTerminationPointInstanceIdentifier(bridgeNode, portName); + OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = + new OvsdbTerminationPointAugmentationBuilder(); + + tpAugmentationBuilder.setName(portName); + if (type != null) { + tpAugmentationBuilder.setInterfaceType(OVSDB_INTERFACE_TYPE_MAP.get(type)); + } + TerminationPointBuilder tpBuilder = new TerminationPointBuilder(); + tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid)); + tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build()); + return mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build()); + } + + public Boolean addPatchTerminationPoint(Node node, String bridgeName, String portName, String peerPortName) { + Map option = new HashMap<>(); + option.put("peer", peerPortName); + return addTerminationPoint(node, bridgeName, portName, PATCH_PORT_TYPE, option); + } + + private String getControllerIPAddress() { + String addressString = ConfigProperties.getProperty(this.getClass(), "ovsdb.controller.address"); + if (addressString != null) { + try { + if (InetAddress.getByName(addressString) != null) { + return addressString; + } + } catch (UnknownHostException e) { + LOG.error("Host {} is invalid", addressString, e); + } + } + + addressString = ConfigProperties.getProperty(this.getClass(), "of.address"); + if (addressString != null) { + try { + if (InetAddress.getByName(addressString) != null) { + return addressString; + } + } catch (UnknownHostException e) { + LOG.error("Host {} is invalid", addressString, e); + } + } + + return null; + } + + private short getControllerOFPort() { + short openFlowPort = OPENFLOW_PORT; + String portString = ConfigProperties.getProperty(this.getClass(), "of.listenPort"); + if (portString != null) { + try { + openFlowPort = Short.parseShort(portString); + } catch (NumberFormatException e) { + LOG.warn("Invalid port:{}, use default({})", portString, + openFlowPort, e); + } + } + return openFlowPort; + } + + public List getControllersFromOvsdbNode(Node node) { + List controllersStr = new ArrayList<>(); + + String controllerIpStr = getControllerIPAddress(); + if (controllerIpStr != null) { + // If codepath makes it here, the ip address to be used was explicitly provided. + // Being so, also fetch openflowPort provided via ConfigProperties. + controllersStr.add(OPENFLOW_CONNECTION_PROTOCOL + + ":" + controllerIpStr + ":" + getControllerOFPort()); + } else { + // Check if ovsdb node has manager entries + OvsdbNodeAugmentation ovsdbNodeAugmentation = extractOvsdbNode(node); + if (ovsdbNodeAugmentation != null) { + List managerEntries = ovsdbNodeAugmentation.getManagerEntry(); + if (managerEntries != null && !managerEntries.isEmpty()) { + for (ManagerEntry managerEntry : managerEntries) { + if (managerEntry == null || managerEntry.getTarget() == null) { + continue; + } + String[] tokens = managerEntry.getTarget().getValue().split(":"); + if (tokens.length == 3 && tokens[0].equalsIgnoreCase("tcp")) { + controllersStr.add(OPENFLOW_CONNECTION_PROTOCOL + + ":" + tokens[1] + ":" + getControllerOFPort()); + } else if (tokens[0].equalsIgnoreCase("ptcp")) { + ConnectionInfo connectionInfo = ovsdbNodeAugmentation.getConnectionInfo(); + if (connectionInfo != null && connectionInfo.getLocalIp() != null) { + controllerIpStr = String.valueOf(connectionInfo.getLocalIp().getValue()); + controllersStr.add(OPENFLOW_CONNECTION_PROTOCOL + + ":" + controllerIpStr + ":" + OPENFLOW_PORT); + } else { + LOG.warn("Ovsdb Node does not contain connection info: {}", node); + } + } else { + LOG.trace("Skipping manager entry {} for node {}", + managerEntry.getTarget(), node.getNodeId().getValue()); + } + } + } else { + LOG.warn("Ovsdb Node does not contain manager entries : {}", node); + } + } + } + + if (controllersStr.isEmpty()) { + // Neither user provided ip nor ovsdb node has manager entries. Lets use local machine ip address. + LOG.debug("Use local machine ip address as a OpenFlow Controller ip address"); + controllerIpStr = getLocalControllerHostIpAddress(); + if (controllerIpStr != null) { + controllersStr.add(OPENFLOW_CONNECTION_PROTOCOL + + ":" + controllerIpStr + ":" + OPENFLOW_PORT); + } + } + + if (controllersStr.isEmpty()) { + LOG.warn("Failed to determine OpenFlow controller ip address"); + } else if (LOG.isDebugEnabled()) { + controllerIpStr = ""; + for (String currControllerIpStr : controllersStr) { + controllerIpStr += " " + currControllerIpStr; + } + LOG.debug("Found {} OpenFlow Controller(s) :{}", controllersStr.size(), controllerIpStr); + } + + return controllersStr; + } + + private String getLocalControllerHostIpAddress() { + String ipaddress = null; + try{ + for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();){ + NetworkInterface iface = ifaces.nextElement(); + + for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) { + InetAddress inetAddr = inetAddrs.nextElement(); + if (!inetAddr.isLoopbackAddress() && inetAddr.isSiteLocalAddress()) { + ipaddress = inetAddr.getHostAddress(); + break; + } + } + } + }catch (Exception e){ + LOG.warn("Exception while fetching local host ip address ", e); + } + return ipaddress; + } + + public long getDataPathId(Node node) { + long dpid = 0L; + String datapathId = getDatapathId(node); + if (datapathId != null) { + dpid = new BigInteger(datapathId.replaceAll(":", ""), 16).longValue(); + } + return dpid; + } + + public String getDataPathIdStr(final Node node) { + if (node != null) { + long dpId = getDataPathId(node); + if (dpId != 0) { + return String.valueOf(dpId); + } + } + + return null; + } + + public String getDatapathId(Node node) { + OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class); + return getDatapathId(ovsdbBridgeAugmentation); + } + + public String getDatapathId(OvsdbBridgeAugmentation ovsdbBridgeAugmentation) { + String datapathId = null; + if (ovsdbBridgeAugmentation != null && ovsdbBridgeAugmentation.getDatapathId() != null) { + datapathId = ovsdbBridgeAugmentation.getDatapathId().getValue(); + } + return datapathId; + } + + public String extractBridgeName(Node node) { + return node.getAugmentation(OvsdbBridgeAugmentation.class).getBridgeName().getValue(); + } + + public boolean isBridgeOnOvsdbNode(Node ovsdbNode, String bridgeName) { + boolean found = false; + OvsdbNodeAugmentation ovsdbNodeAugmentation = extractNodeAugmentation(ovsdbNode); + if (ovsdbNodeAugmentation != null) { + List managedNodes = ovsdbNodeAugmentation.getManagedNodeEntry(); + if (managedNodes != null) { + for (ManagedNodeEntry managedNode : managedNodes) { + InstanceIdentifier bridgeIid = managedNode.getBridgeRef().getValue(); + if (bridgeIid.toString().contains(bridgeName)) { + found = true; + break; + } + } + } + } + return found; + } + + public OvsdbBridgeAugmentation getBridgeFromConfig(Node node, String bridge) { + OvsdbBridgeAugmentation ovsdbBridgeAugmentation = null; + InstanceIdentifier bridgeIid = + createInstanceIdentifier(node.getKey(), bridge); + Node bridgeNode = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, bridgeIid); + if (bridgeNode != null) { + ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class); + } + return ovsdbBridgeAugmentation; + } + + private void setManagedByForBridge(OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder, + NodeKey ovsdbNodeKey) { + InstanceIdentifier connectionNodePath = createInstanceIdentifier(ovsdbNodeKey.getNodeId()); + ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath)); + } + + public boolean isOvsdbNodeDpdk(Node ovsdbNode) { + boolean found = false; + OvsdbNodeAugmentation ovsdbNodeAugmentation = extractNodeAugmentation(ovsdbNode); + if (ovsdbNodeAugmentation != null) { + List ifTypes = ovsdbNodeAugmentation.getInterfaceTypeEntry(); + if (ifTypes != null) { + for (InterfaceTypeEntry ifType : ifTypes) { + if (ifType.getInterfaceType().equals(InterfaceTypeDpdk.class)) { + found = true; + break; + } + } + } + } + return found; + } + + private List createControllerEntries(List controllersStr, + Long maxBackoff, Long inactivityProbe) { + List controllerEntries = new ArrayList<>(); + if (controllersStr != null) { + for (String controllerStr : controllersStr) { + ControllerEntryBuilder controllerEntryBuilder = new ControllerEntryBuilder(); + controllerEntryBuilder.setTarget(new Uri(controllerStr)); + if (maxBackoff != null) { + controllerEntryBuilder.setMaxBackoff(maxBackoff); + } + if (inactivityProbe != null) { + controllerEntryBuilder.setInactivityProbe(inactivityProbe); + } + controllerEntries.add(controllerEntryBuilder.build()); + } + } + return controllerEntries; + } + + public OvsdbTerminationPointAugmentation extractTerminationPointAugmentation(Node bridgeNode, String portName) { + if (bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class) != null) { + List tpAugmentations = extractTerminationPointAugmentations(bridgeNode); + for (OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation : tpAugmentations) { + if (ovsdbTerminationPointAugmentation.getName().equals(portName)) { + return ovsdbTerminationPointAugmentation; + } + } + } + return null; + } + + public List extractTerminationPointAugmentations( Node node ) { + List tpAugmentations = new ArrayList<>(); + if (node == null) { + LOG.error("extractTerminationPointAugmentations: Node value is null"); + return Collections.emptyList(); + } + List terminationPoints = node.getTerminationPoint(); + if(terminationPoints != null && !terminationPoints.isEmpty()){ + for(TerminationPoint tp : terminationPoints){ + OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation = + tp.getAugmentation(OvsdbTerminationPointAugmentation.class); + if (ovsdbTerminationPointAugmentation != null) { + tpAugmentations.add(ovsdbTerminationPointAugmentation); + } + } + } + return tpAugmentations; + } + + /** + * Extract the OvsdbTerminationPointAugmentation for the particular node identified by + * portName. + * + * @param node + * @param portName + * @return + */ + public OvsdbTerminationPointAugmentation getTerminationPointOfBridge(Node node, String portName) { + OvsdbTerminationPointAugmentation tpAugmentation = extractTerminationPointAugmentation(node,portName); + if(tpAugmentation == null){ + List tpAugmentations = readTerminationPointAugmentations(node); + if(tpAugmentations != null){ + for(OvsdbTerminationPointAugmentation ovsdbTpAugmentation : tpAugmentations){ + if(ovsdbTpAugmentation.getName().equals(portName)){ + return ovsdbTpAugmentation; + } + } + } + } + return tpAugmentation; + } + + /** + * read the list of OvsdbTerminationPointAugmentation for the particular node. + * + * @param node + * @return + */ + public List readTerminationPointAugmentations(Node node) { + if (node == null) { + LOG.error("readTerminationPointAugmentations: Node value is null"); + return Collections.emptyList(); + } + Node operNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier + .create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID)) + .child(Node.class, new NodeKey(node.getNodeId()))); + if (operNode != null) { + return extractTerminationPointAugmentations(operNode); + } + return new ArrayList<>(); + } + + /** + * Get all OVSDB nodes from topology. + * @return a list of nodes or null if the topology could not found + */ + public List getOvsdbNodes() { + InstanceIdentifier inst = InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, + new TopologyKey(OVSDB_TOPOLOGY_ID)); + Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, inst); + return topology != null ? topology.getNode() : null; + } + + /** + * Get OpenvSwitch other-config by key. + * @param node OVSDB node + * @param key key to extract from other-config + * @return the value for key or null if key not found + */ + public String getOpenvswitchOtherConfig(Node node, String key) { + OvsdbNodeAugmentation ovsdbNode = node.getAugmentation(OvsdbNodeAugmentation.class); + if (ovsdbNode == null) { + Node nodeFromReadOvsdbNode = readOvsdbNode(node); + if (nodeFromReadOvsdbNode != null) { + ovsdbNode = nodeFromReadOvsdbNode.getAugmentation(OvsdbNodeAugmentation.class); + } + } + + if (ovsdbNode != null && ovsdbNode.getOpenvswitchOtherConfigs() != null) { + for (OpenvswitchOtherConfigs openvswitchOtherConfigs : ovsdbNode.getOpenvswitchOtherConfigs()) { + if (openvswitchOtherConfigs.getOtherConfigKey().equals(key)) { + return openvswitchOtherConfigs.getOtherConfigValue(); + } + } + } + + return null; + } + + public static TerminationPoint getTerminationPointByExternalId(final Node bridgeNode, final String interfaceName) { + if (bridgeNode.getTerminationPoint() != null) { + for (TerminationPoint tp : bridgeNode.getTerminationPoint()) { + OvsdbTerminationPointAugmentation ovsdbTp = tp.getAugmentation(OvsdbTerminationPointAugmentation.class); + String externalIdValue = getExternalInterfaceIdValue(ovsdbTp); + if (externalIdValue != null && externalIdValue.equals(interfaceName)) { + LOG.debug("Found matching termination point with iface-id {} on bridgeNode {}, returning tp {}", + interfaceName, bridgeNode, tp); + return tp; + } + } + } + return null; + } + + // This utility shouldn't be called often, as it reads all OVSDB nodes each time - not good for scale + public Node getNodeByTerminationPointExternalId(final String interfaceName) { + List nodes = getOvsdbNodes(); + if (nodes != null) { + for (Node node : nodes) { + TerminationPoint tp = getTerminationPointByExternalId(node, interfaceName); + if (tp != null) { + return node; + } + } + } + return null; + } + + public static String getExternalInterfaceIdValue(final OvsdbTerminationPointAugmentation ovsdbTp) { + if (ovsdbTp != null) { + List ifaceExtIds = ovsdbTp.getInterfaceExternalIds(); + if (ifaceExtIds != null) { + for (InterfaceExternalIds entry : ifaceExtIds) { + if (entry.getExternalIdKey().equals(EXTERNAL_INTERFACE_ID_KEY)) { + return entry.getExternalIdValue(); + } + } + } + } + return null; + } + + public String getDatapathIdFromNodeInstanceId(InstanceIdentifier nodeInstanceId) { + Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodeInstanceId); + String dpId = node != null ? getDataPathIdStr(node) : null; + if (dpId != null) { + return dpId; + } + return null; + } + + public static boolean compareDbVersionToMinVersion(final String dbVersion, final String minVersion) { + final Matcher dbVersionMatcher = PATTERN.matcher(dbVersion); + final Matcher minVersionMatcher = PATTERN.matcher(minVersion); + LOG.debug("dbVersion {}, minVersion {}", dbVersion, minVersion); + if (!dbVersionMatcher.find()){ + LOG.error("Invalid DB version format {}", dbVersion); + return false; + } + if (!minVersionMatcher.find()){ + LOG.error("Invalid Min DB version format {}", minVersion); + return false; + } + + if (dbVersion != null && !dbVersion.isEmpty() && minVersion != null + && !minVersion.isEmpty()) { + if (Integer.valueOf(dbVersionMatcher.group(1)).equals(Integer.valueOf(minVersionMatcher.group(1))) && + Integer.valueOf(dbVersionMatcher.group(2)).equals(Integer.valueOf(minVersionMatcher.group(2))) && + Integer.valueOf(dbVersionMatcher.group(3)).equals(Integer.valueOf(minVersionMatcher.group(3)))) { + return true; + } + + if (Integer.valueOf(dbVersionMatcher.group(1)).intValue() > Integer.valueOf(minVersionMatcher.group(1)).intValue()) { + return true; + } + + if (Integer.valueOf(dbVersionMatcher.group(1)).intValue() < Integer.valueOf(minVersionMatcher.group(1)).intValue()) { + return false; + } + + // major version is equal + if (Integer.valueOf(dbVersionMatcher.group(2)).intValue() > Integer.valueOf(minVersionMatcher.group(2)).intValue()) { + return true; + } + if (Integer.valueOf(dbVersionMatcher.group(2)).intValue() < Integer.valueOf(minVersionMatcher.group(2)).intValue()) { + return false; + } + + if (Integer.valueOf(dbVersionMatcher.group(3)).intValue() > Integer.valueOf(minVersionMatcher.group(3)).intValue()) { + return true; + } + } + return false; + } }