/* * Copyright (c) 2015, 2017 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 */ /** * SfcOvsUtil class contains various wrapper and utility methods * <p> * * @author Andrej Kincel (andrej.kincel@gmail.com) * @version 0.1 * @since 2015-04-01 */ package org.opendaylight.sfc.ovs.provider; import com.google.common.base.Preconditions; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.ovsdb.southbound.SouthboundConstants; import org.opendaylight.sfc.ovs.api.SfcOvsDataStoreAPI; import org.opendaylight.sfc.ovs.api.SfcSffToOvsMappingAPI; import org.opendaylight.sfc.provider.api.SfcDataStoreAPI; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsBridgeAugmentation; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.SffOvsBridgeAugmentationBuilder; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.bridge.OvsBridge; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.bridge.OvsBridgeBuilder; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.ServiceFunctionForwarders; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.VxlanGpe; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.LocatorType; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip; 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.Ipv4Address; 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.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId; 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.InterfaceTypeDpdk; 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.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.ovsdb.port._interface.attributes.Options; 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.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.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.TerminationPointKey; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SfcOvsUtil { private static final Logger LOG = LoggerFactory.getLogger(SfcOvsUtil.class); private static final String OVSDB_BRIDGE_PREFIX = "/bridge/"; public static final String OVSDB_OPTION_LOCAL_IP = "local_ip"; public static final String OVSDB_OPTION_REMOTE_IP = "remote_ip"; public static final String OVSDB_OPTION_DST_PORT = "dst_port"; public static final String OVSDB_OPTION_NSP = "nsp"; public static final String OVSDB_OPTION_NSI = "nsi"; public static final String OVSDB_OPTION_IN_NSP = "in_nsp"; public static final String OVSDB_OPTION_IN_NSI = "in_nsi"; public static final String OVSDB_OPTION_OUT_NSP = "out_nsp"; public static final String OVSDB_OPTION_OUT_NSI = "out_nsi"; public static final String OVSDB_OPTION_NSHC1 = "nshc1"; public static final String OVSDB_OPTION_NSHC2 = "nshc2"; public static final String OVSDB_OPTION_NSHC3 = "nshc3"; public static final String OVSDB_OPTION_NSHC4 = "nshc4"; public static final String OVSDB_OPTION_KEY = "key"; public static final String OVSDB_OPTION_EXTS = "exts"; public static final String OVSDB_OPTION_GPE = "gpe"; public static final String OVSDB_OPTION_VALUE_FLOW = "flow"; public static final String DPL_NAME_DPDK = "Dpdk"; public static final String DPL_NAME_DPDKVHOST = "Dpdkvhost"; public static final String DPL_NAME_DPDKVHOSTUSER = "Dpdkvhostuser"; public static final String DPL_NAME_INTERNAL = "Internal"; public static final PortNumber NSH_VXLAN_TUNNEL_PORT = new PortNumber(6633); protected static ExecutorService executor = Executors.newFixedThreadPool(5); /** * Submits callable for execution by given ExecutorService. Thanks to this * wrapper method, boolean result will be returned instead of Future. * * <p> * * @param callable * Callable * @param executor * ExecutorService * @return true if callable completed successfully, otherwise false. */ public static Object submitCallable(Callable callable, ExecutorService executor) { Future future = null; Object result = null; future = executor.submit(callable); try { result = future.get(); } catch (InterruptedException | ExecutionException e) { LOG.warn("{} failed to: {}", callable.toString(), e); } return result; } /** * Method builds OVSDB Topology InstanceIdentifier. * * <p> * * @return InstanceIdentifier<Topology> */ public static InstanceIdentifier<Topology> buildOvsdbTopologyIID() { InstanceIdentifier<Topology> ovsdbTopologyIID = InstanceIdentifier.create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)); return ovsdbTopologyIID; } /** * Method builds OVS NodeId which is based on: 1. OVS Node * InstanceIdentifier which manages the OVS Bridge 2. OVS Bridge name * * <p> * If the two aforementioned fields are missing, NullPointerException is * raised. * * <p> * * @param ovsdbBridge * OvsdbBridgeAugmentation * @return NodeId */ private static NodeId getManagedByNodeId(OvsdbBridgeAugmentation ovsdbBridge) { Preconditions.checkNotNull(ovsdbBridge, "Cannot getManagedByNodeId, OvsdbBridgeAugmentation is null."); Preconditions.checkNotNull(ovsdbBridge.getBridgeName(), "Cannot build getManagedByNodeId, BridgeName is null."); Preconditions.checkNotNull(ovsdbBridge.getManagedBy(), "Cannot build getManagedByNodeId, ManagedBy is null."); String bridgeName = ovsdbBridge.getBridgeName().getValue(); InstanceIdentifier<Node> nodeIID = (InstanceIdentifier<Node>) ovsdbBridge.getManagedBy().getValue(); KeyedInstanceIdentifier keyedInstanceIdentifier = (KeyedInstanceIdentifier) nodeIID .firstIdentifierOf(Node.class); Preconditions.checkNotNull(keyedInstanceIdentifier, "Cannot build getManagedByNodeId, parent OVS Node is null."); NodeKey nodeKey = (NodeKey) keyedInstanceIdentifier.getKey(); String nodeId = nodeKey.getNodeId().getValue(); nodeId = nodeId.concat(OVSDB_BRIDGE_PREFIX + bridgeName); return new NodeId(nodeId); } /** * Method builds OVS Node InstanceIdentifier which is based on OVS NodeId. * * <p> * * @param ovsdbBridge * OvsdbBridgeAugmentation * @return InstanceIdentifier<Node> * @see SfcOvsUtil getManagedByNodeId */ public static InstanceIdentifier<Node> buildOvsdbNodeIID(OvsdbBridgeAugmentation ovsdbBridge) { InstanceIdentifier<Node> nodeIID = InstanceIdentifier.create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) .child(Node.class, new NodeKey(getManagedByNodeId(ovsdbBridge))); return nodeIID; } /** * Method builds OVS Node InstanceIdentifier which is based on Service * Function Forwarder name. Method will return valid InstanceIdentifier only * if the given SFF name belongs to SFF instance mapped to OVS. * * <p> * * @param serviceFunctionForwarderName * String * @return InstanceIdentifier<Node> */ public static InstanceIdentifier<Node> buildOvsdbNodeIID(String serviceFunctionForwarderName) { InstanceIdentifier<Node> nodeIID = InstanceIdentifier.create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) .child(Node.class, new NodeKey(new NodeId(serviceFunctionForwarderName))); return nodeIID; } /** * Method builds OVS Node InstanceIdentifier which is based on NodeId. * * <p> * * @param nodeId * NodeId * @return InstanceIdentifier<Node> */ public static InstanceIdentifier<Node> buildOvsdbNodeIID(NodeId nodeId) { InstanceIdentifier<Node> nodeIID = InstanceIdentifier.create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) .child(Node.class, new NodeKey(nodeId)); return nodeIID; } /** * Method builds OVS BridgeAugmentation InstanceIdentifier which is based on * OVS NodeId. * * <p> * @param ovsdbBridge * OvsdbBridgeAugmentation * @return InstanceIdentifier<OvsdbBridgeAugmentation> * @see SfcOvsUtil getManagedByNodeId */ public static InstanceIdentifier<OvsdbBridgeAugmentation> buildOvsdbBridgeIID(OvsdbBridgeAugmentation ovsdbBridge) { InstanceIdentifier<OvsdbBridgeAugmentation> bridgeEntryIID = InstanceIdentifier.create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) .child(Node.class, new NodeKey(getManagedByNodeId(ovsdbBridge))) .augmentation(OvsdbBridgeAugmentation.class); return bridgeEntryIID; } /** * Create a {@link InstanceIdentifier} {@link OvsdbBridgeAugmentation} based * on the Topology {@link NodeId}. * * @param nodeId * A topology {@link NodeId} * @return InstanceIdentifier<OvsdbBridgeAugmentation> */ public static InstanceIdentifier<OvsdbBridgeAugmentation> buildOvsdbBridgeIID(NodeId nodeId) { InstanceIdentifier<OvsdbBridgeAugmentation> bridgeEntryIID = InstanceIdentifier.create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) .child(Node.class, new NodeKey(nodeId)).augmentation(OvsdbBridgeAugmentation.class); return bridgeEntryIID; } /** * Method builds OVS BridgeAugmentation InstanceIdentifier which is based on * OVS Bridge name. * * <p> * @param serviceFunctionForwarderName * serviceFunctionForwarderName String * @return InstanceIdentifier<OvsdbBridgeAugmentation> */ public static InstanceIdentifier<OvsdbBridgeAugmentation> buildOvsdbBridgeIID(String serviceFunctionForwarderName) { InstanceIdentifier<OvsdbBridgeAugmentation> bridgeEntryIID = buildOvsdbNodeIID(serviceFunctionForwarderName) .augmentation(OvsdbBridgeAugmentation.class); return bridgeEntryIID; } /** * Method builds OVS TerminationPointAugmentation InstanceIdentifier which * is based on: 1. OVS Node InstanceIdentifier which manages the OVS Bridge, * to which the OVS TerminationPoint is attached 2. OVS Termination Point * name. * * <p> * If the two aforementioned fields are missing, NullPointerException is * raised. * * <p> * @param ovsdbBridge * OvsdbBridgeAugmentation * @param ovsdbTerminationPoint * OvsdbTerminationPointAugmentation * @return InstanceIdentifier<OvsdbTerminationPointAugmentation> */ public static InstanceIdentifier<OvsdbTerminationPointAugmentation> buildOvsdbTerminationPointAugmentationIID( OvsdbBridgeAugmentation ovsdbBridge, OvsdbTerminationPointAugmentation ovsdbTerminationPoint) { Preconditions.checkNotNull(ovsdbTerminationPoint, "Cannot build OvsdbTerminationPointAugmentation InstanceIdentifier," + " OvsdbTerminationPointAugmentation is null."); Preconditions.checkNotNull(ovsdbTerminationPoint.getName(), "Cannot build OvsdbTerminationPointAugmentation InstanceIdentifier," + " OvsdbTerminationPointAugmentation Name is null."); Preconditions.checkNotNull(ovsdbBridge, "Cannot build OvsdbTerminationPointAugmentation InstanceIdentifier, OvsdbBridgeAugmentation is null."); NodeId nodeId = getManagedByNodeId(ovsdbBridge); String terminationPointId = ovsdbTerminationPoint.getName(); InstanceIdentifier<OvsdbTerminationPointAugmentation> terminationPointIID = InstanceIdentifier .create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) .child(Node.class, new NodeKey(nodeId)) .child(TerminationPoint.class, new TerminationPointKey(new TpId(terminationPointId))) .augmentation(OvsdbTerminationPointAugmentation.class); return terminationPointIID; } /** * Method builds OVS TerminationPoint InstanceIdentifier which is based on * SFF name and SFF DataPlane locator name. Method will return valid * InstanceIdentifier only if the given SFF and SFF DataPlane locator * belongs to SFF instance mapped to OVS. * * <p> * * @param ovsdbBridgeNodeId * OVSDB bridge NodeId where the SFF DPL resides * @param sffDataPlaneLocatorName * Service Function Forwarder Data Plane locator name * @return InstanceIdentifier<TerminationPoint> */ public static InstanceIdentifier<TerminationPoint> buildOvsdbTerminationPointIID(NodeId ovsdbBridgeNodeId, String sffDataPlaneLocatorName) { InstanceIdentifier<TerminationPoint> terminationPointIID = InstanceIdentifier.create(NetworkTopology.class) .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID)) .child(Node.class, new NodeKey(new NodeId(ovsdbBridgeNodeId))) .child(TerminationPoint.class, new TerminationPointKey(new TpId(sffDataPlaneLocatorName))); return terminationPointIID; } @SuppressWarnings("checkstyle:IllegalCatch") public static IpAddress convertStringToIpAddress(String ipAddressString) { Preconditions.checkNotNull(ipAddressString, "Supplied string value of ipAddress must not be null"); try { return new IpAddress(new Ipv4Address(ipAddressString)); } catch (Exception e) { LOG.debug("Supplied string value of ipAddress ({}) is not an instance of IPv4", ipAddressString); } try { return new IpAddress(new Ipv6Address(ipAddressString)); } catch (Exception e) { LOG.debug("Supplied string value of ipAddress ({}) is not an instance of IPv6", ipAddressString); } LOG.error("Supplied string value of ipAddress ({}) cannot be converted to IpAddress object!", ipAddressString); return null; } @SuppressWarnings("checkstyle:IllegalCatch") public static String convertIpAddressToString(IpAddress ipAddress) { Preconditions.checkNotNull(ipAddress, "Supplied IpAddress value must not be null"); try { Preconditions.checkArgument(ipAddress.getIpv4Address().getValue() != null); return ipAddress.getIpv4Address().getValue(); } catch (Exception e) { LOG.debug("Supplied IpAddress value ({}) is not an instance of IPv4", ipAddress.toString()); } Preconditions.checkArgument(ipAddress.getIpv6Address().getValue() != null); return ipAddress.getIpv6Address().getValue(); } public static boolean putOvsdbTerminationPoints(OvsdbBridgeAugmentation ovsdbBridge, List<SffDataPlaneLocator> sffDataPlaneLocatorList, ExecutorService executor) { Preconditions.checkNotNull(executor); boolean result = true; List<OvsdbTerminationPointAugmentation> ovsdbTerminationPointList = SfcSffToOvsMappingAPI .buildTerminationPointAugmentationList(sffDataPlaneLocatorList); for (OvsdbTerminationPointAugmentation ovsdbTerminationPoint : ovsdbTerminationPointList) { Object[] methodParameters = { ovsdbBridge, ovsdbTerminationPoint }; SfcOvsDataStoreAPI sfcOvsDataStoreAPIPutTerminationPoint = new SfcOvsDataStoreAPI( SfcOvsDataStoreAPI.Method.PUT_OVSDB_TERMINATION_POINT, methodParameters); boolean partialResult = (boolean) SfcOvsUtil.submitCallable(sfcOvsDataStoreAPIPutTerminationPoint, executor); // once result is false, we will keep it false (it will be not // overwritten with next // partialResults) if (result) { result = partialResult; } } return result; } public static boolean putOvsdbBridge(OvsdbBridgeAugmentation ovsdbBridge, ExecutorService executor) { Preconditions.checkNotNull(executor); Object[] methodParameters = { ovsdbBridge }; SfcOvsDataStoreAPI sfcOvsDataStoreAPIPutBridge = new SfcOvsDataStoreAPI( SfcOvsDataStoreAPI.Method.PUT_OVSDB_BRIDGE, methodParameters); return (boolean) SfcOvsUtil.submitCallable(sfcOvsDataStoreAPIPutBridge, executor); } public static boolean deleteOvsdbNode(InstanceIdentifier<Node> ovsdbNodeIID, ExecutorService executor) { Preconditions.checkNotNull(executor); Object[] methodParameters = { ovsdbNodeIID }; SfcOvsDataStoreAPI sfcOvsDataStoreAPIDeleteNode = new SfcOvsDataStoreAPI( SfcOvsDataStoreAPI.Method.DELETE_OVSDB_NODE, methodParameters); return (boolean) SfcOvsUtil.submitCallable(sfcOvsDataStoreAPIDeleteNode, executor); } public static boolean deleteOvsdbTerminationPoint(InstanceIdentifier<TerminationPoint> ovsdbTerminationPointIID, ExecutorService executor) { Preconditions.checkNotNull(executor); Object[] methodParameters = { ovsdbTerminationPointIID }; SfcOvsDataStoreAPI sfcOvsDataStoreAPIDeleteTerminationPoint = new SfcOvsDataStoreAPI( SfcOvsDataStoreAPI.Method.DELETE_OVSDB_TERMINATION_POINT, methodParameters); return (boolean) SfcOvsUtil.submitCallable(sfcOvsDataStoreAPIDeleteTerminationPoint, executor); } public static ServiceFunctionForwarder augmentSffWithOpenFlowNodeId(ServiceFunctionForwarder sff) { String ofNodeId = SfcOvsUtil.getOpenFlowNodeIdForSff(sff); if (ofNodeId != null) { SffOvsBridgeAugmentationBuilder sffOvsBrAugBuilder; OvsBridgeBuilder ovsBrBuilder; // if augmentation exists, create builders based on existing data SffOvsBridgeAugmentation sffOvsBrAug = sff.getAugmentation(SffOvsBridgeAugmentation.class); if (sffOvsBrAug != null) { sffOvsBrAugBuilder = new SffOvsBridgeAugmentationBuilder(sffOvsBrAug); OvsBridge ovsBridge = sffOvsBrAug.getOvsBridge(); if (ovsBridge != null) { ovsBrBuilder = new OvsBridgeBuilder(ovsBridge); } else { ovsBrBuilder = new OvsBridgeBuilder(); } // if not, create empty builders } else { sffOvsBrAugBuilder = new SffOvsBridgeAugmentationBuilder(); ovsBrBuilder = new OvsBridgeBuilder(); } ovsBrBuilder.setOpenflowNodeId(ofNodeId); sffOvsBrAugBuilder.setOvsBridge(ovsBrBuilder.build()); ServiceFunctionForwarderBuilder sffBuilder = new ServiceFunctionForwarderBuilder(sff); sffBuilder.addAugmentation(SffOvsBridgeAugmentation.class, sffOvsBrAugBuilder.build()); return sffBuilder.build(); } else { // if the OpenFlowNodeId does not exist, return the original SFF return sff; } } /** * This gets VxlanDataLocator. * * @param sff * - Service Function Forwarder * @return Ip */ public static Ip getSffVxlanDataLocator(ServiceFunctionForwarder sff) { List<SffDataPlaneLocator> dplList = sff.getSffDataPlaneLocator(); for (SffDataPlaneLocator dpl : dplList) { if (dpl.getDataPlaneLocator() != null && dpl.getDataPlaneLocator().getTransport() == VxlanGpe.class) { return (Ip) dpl.getDataPlaneLocator().getLocatorType(); } } return null; } /** * This gets the OVSDB Manager Topology Node for the * {@link ServiceFunctionForwarder}, using the IP address found in an IP * based Data Plane Locator. If there isn't an IP based Data Plane Locator, * then this will return null. * * @param serviceFunctionForwarder * - {@link ServiceFunctionForwarder} * @param executor * - {@link ExecutorService} * @return {@link Node} */ public static Node lookupTopologyNode(ServiceFunctionForwarder serviceFunctionForwarder, ExecutorService executor) { List<SffDataPlaneLocator> sffDplList = serviceFunctionForwarder.getSffDataPlaneLocator(); IpAddress ip = null; if (sffDplList == null) { LOG.debug("No IP Data Plane Locator for Service Function Forwarder {}, ", serviceFunctionForwarder); return null; } /* * Go through the Data Plane Locators, looking for an IP-based locator. * If we find one, use the IP address from that as the IP for the OVSDB * manager connection. */ for (SffDataPlaneLocator sffDpl : sffDplList) { if (sffDpl.getDataPlaneLocator() != null && sffDpl.getDataPlaneLocator().getLocatorType() != null) { Class<? extends DataContainer> locatorType = sffDpl.getDataPlaneLocator().getLocatorType() .getImplementedInterface(); if (locatorType.isAssignableFrom(Ip.class)) { Ip ipPortLocator = (Ip) sffDpl.getDataPlaneLocator().getLocatorType(); IpAddress ipAddress = new IpAddress(ipPortLocator.getIp().getValue()); ip = ipAddress; } } } if (ip == null) { LOG.debug("Could not get IP address for Service Function Forwarder {}", serviceFunctionForwarder); return null; } return SfcOvsUtil.getManagerNodeByIp(ip, executor); } public static String getOpenFlowNodeIdForSff(ServiceFunctionForwarder serviceFunctionForwarder) { NodeId nodeId = getOvsdbAugmentationNodeIdBySff(serviceFunctionForwarder); DatapathId datapathId = getOvsDataPathId(nodeId); if (datapathId == null) { LOG.warn("No DatapathId for Service Function Forwarder {}", serviceFunctionForwarder); return null; } Long macLong = getLongFromDpid(datapathId.getValue()); return "openflow:" + String.valueOf(macLong); } public static NodeId getOvsdbAugmentationNodeIdBySff(ServiceFunctionForwarder serviceFunctionForwarder) { Node managerNode = lookupTopologyNode(serviceFunctionForwarder, executor); if (managerNode == null) { LOG.warn("No Topology Node for Service Function Forwarder {}", serviceFunctionForwarder); return null; } SffOvsBridgeAugmentation sffOvsBridgeAugmentation = serviceFunctionForwarder .getAugmentation(SffOvsBridgeAugmentation.class); if (sffOvsBridgeAugmentation == null) { LOG.warn("No SffOvsBridgeAugmentation for Service Function Forwarder {}", serviceFunctionForwarder); return null; } OvsBridge sffOvsBridge = sffOvsBridgeAugmentation.getOvsBridge(); if (sffOvsBridge == null) { LOG.warn("No OvsBridge for SffOvsBridgeAugmentation in Service Function Forwarder {}", serviceFunctionForwarder); return null; } OvsdbBridgeAugmentationBuilder builder = new OvsdbBridgeAugmentationBuilder(); OvsdbNodeRef ovsdbNodeRef = new OvsdbNodeRef(SfcOvsUtil.buildOvsdbNodeIID(managerNode.getNodeId())); builder.setManagedBy(ovsdbNodeRef); builder.setBridgeName(new OvsdbBridgeName(sffOvsBridge.getBridgeName())); return getManagedByNodeId(builder.build()); } private static DatapathId getOvsDataPathId(NodeId nodeId) { Object[] methodParams = { SfcOvsUtil.buildOvsdbBridgeIID(nodeId) }; SfcOvsDataStoreAPI readOvsdbBridge = new SfcOvsDataStoreAPI(SfcOvsDataStoreAPI.Method.READ_OVSDB_BRIDGE, methodParams); OvsdbBridgeAugmentation readBridge = (OvsdbBridgeAugmentation) SfcOvsUtil.submitCallable(readOvsdbBridge, executor); if (readBridge == null) { return null; } return readBridge.getDatapathId(); } private static Long getLongFromDpid(String dpid) { final String HEX = "0x"; String[] addressInBytes = dpid.split(":"); Long address = Long.decode(HEX + addressInBytes[2]) << 40 | Long.decode(HEX + addressInBytes[3]) << 32 | Long.decode(HEX + addressInBytes[4]) << 24 | Long.decode(HEX + addressInBytes[5]) << 16 | Long.decode(HEX + addressInBytes[6]) << 8 | Long.decode(HEX + addressInBytes[7]); return address; } public static Node getManagerNodeByIp(IpAddress ip, ExecutorService executor) { String ipAddressString = null; if (ip == null || ip.getIpv4Address() == null && ip.getIpv6Address() == null) { LOG.warn("Invalid IP address"); return null; } if (ip.getIpv4Address() != null) { ipAddressString = ip.getIpv4Address().getValue(); } else if (ip.getIpv6Address() != null) { ipAddressString = ip.getIpv6Address().getValue(); } Object[] methodParams = { ipAddressString }; SfcOvsDataStoreAPI sfcOvsDataStoreAPI = new SfcOvsDataStoreAPI(SfcOvsDataStoreAPI.Method.READ_OVSDB_NODE_BY_IP, methodParams); Node node = (Node) SfcOvsUtil.submitCallable(sfcOvsDataStoreAPI, executor); if (node != null && node.getNodeId() != null) { return node; } else { LOG.warn("OVS Node for IP address {} does not exist!", methodParams[0]); return null; } } public static OvsdbNodeAugmentation getOvsdbNodeAugmentation(OvsdbNodeRef nodeRef, ExecutorService executor) { Preconditions.checkNotNull(executor); if (nodeRef.getValue().getTargetType().equals(Node.class)) { Object[] methodParams = { nodeRef }; SfcOvsDataStoreAPI readOvsdbNode = new SfcOvsDataStoreAPI(SfcOvsDataStoreAPI.Method.READ_OVSDB_NODE_BY_REF, methodParams); Node ovsdbNode = (Node) SfcOvsUtil.submitCallable(readOvsdbNode, executor); if (ovsdbNode != null) { return ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class); } else { LOG.warn("Could not find ovsdb-node for connection for {}", ovsdbNode); } } else { LOG.warn("Bridge 'managedBy' non-ovsdb-node. nodeRef {}", nodeRef); } return null; } interface OvsdbTPComp { boolean compare(OvsdbTerminationPointAugmentation otp); } private static Long getOvsPort(String nodeName, OvsdbTPComp comp) { if (nodeName == null) { return null; } InstanceIdentifier<Topology> topoIID = buildOvsdbTopologyIID(); Topology topo = SfcDataStoreAPI.readTransactionAPI(topoIID, LogicalDatastoreType.OPERATIONAL); if (topo == null) { return null; } List<Node> nodes = topo.getNode(); if (nodes == null) { return null; } for (Node node : nodes) { OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class); List<TerminationPoint> tpList = node.getTerminationPoint(); if (ovsdbBridgeAugmentation == null || tpList == null) { continue; } Long dpid = getLongFromDpid(ovsdbBridgeAugmentation.getDatapathId().getValue()); if (nodeName.equals("openflow:" + String.valueOf(dpid))) { for (TerminationPoint tp : tpList) { OvsdbTerminationPointAugmentation otp = tp.getAugmentation(OvsdbTerminationPointAugmentation.class); if (comp.compare(otp)) { return otp.getOfport(); } } } } return null; } /** * This gets openflow port by port name. * * @param nodeName * openflow node name * @param portName * openflow port name * @return port number */ public static Long getOfPortByName(String nodeName, String portName) { class PortNameCompare implements OvsdbTPComp { private final String portName; PortNameCompare(String portName) { this.portName = portName; } @Override public boolean compare(OvsdbTerminationPointAugmentation otp) { if (otp == null) { return false; } if (portName.equals(otp.getName())) { return true; } return false; } } return getOvsPort(nodeName, new PortNameCompare(portName)); } /** * This gets vxlan openflow port. * * @param nodeName * openflow node name * @return port number */ public static Long getVxlanOfPort(String nodeName) { class VxlanPortCompare implements OvsdbTPComp { @Override public boolean compare(OvsdbTerminationPointAugmentation otp) { if (otp == null) { return false; } if (otp.getInterfaceType() == InterfaceTypeVxlan.class) { return true; } return false; } } return getOvsPort(nodeName, new VxlanPortCompare()); } /** * This gets the vxlan-gpe openflow port. * * @param nodeName * openflow node name * @return port number */ public static Long getVxlanGpeOfPort(String nodeName) { class VxlanGpePortCompare implements OvsdbTPComp { @Override public boolean compare(OvsdbTerminationPointAugmentation otp) { if (otp == null) { return false; } if (otp.getInterfaceType() == InterfaceTypeVxlanGpe.class) { return true; } // If the interface type is not VxlanGpe, then it may be Vxlan // with the option exts=gpe set List<Options> options = otp.getOptions(); if (options != null) { for (Options option : options) { if (option.getValue() != null && option.getOption() != null) { if (option.getOption().equals(OVSDB_OPTION_EXTS) && option.getValue().equals(OVSDB_OPTION_GPE)) { return true; } } } } return false; } } return getOvsPort(nodeName, new VxlanGpePortCompare()); } /** * This gets DPDK Openflow port of the given DPDK port or the first DPDK * port in the given Openflow node. * * @param nodeName * Openflow node name * @param dpdkPortName * DPDK port name * @return port number if exists, otherwise null */ public static Long getDpdkOfPort(String nodeName, String dpdkPortName) { Long dpdkOfPort = null; if (nodeName == null) { return null; } if (dpdkPortName == null) { dpdkPortName = new String("dpdk0"); } InstanceIdentifier<Topology> topoIID = buildOvsdbTopologyIID(); Topology topo = null; try { topo = SfcDataStoreAPI.readTransactionAPI(topoIID, LogicalDatastoreType.OPERATIONAL); } catch (NullPointerException e) { // Fix unit tests failure before SfcDataStoreAPI isn't initialized topo = null; } if (topo == null) { return null; } List<Node> nodes = topo.getNode(); if (nodes == null) { return null; } for (Node node : nodes) { OvsdbBridgeAugmentation ovsdbBridgeAugmentation = node.getAugmentation(OvsdbBridgeAugmentation.class); if (ovsdbBridgeAugmentation == null) { continue; } Long dpid = getLongFromDpid(ovsdbBridgeAugmentation.getDatapathId().getValue()); if (nodeName.equals("openflow:" + String.valueOf(dpid))) { if (!ovsdbBridgeAugmentation.getDatapathType().equals(DatapathTypeNetdev.class)) { break; } List<TerminationPoint> tpList = node.getTerminationPoint(); for (TerminationPoint tp : tpList) { if (tp.getTpId().getValue().equals(dpdkPortName)) { OvsdbTerminationPointAugmentation otp = tp .getAugmentation(OvsdbTerminationPointAugmentation.class); if (otp != null && otp.getInterfaceType().equals(InterfaceTypeDpdk.class)) { dpdkOfPort = otp.getOfport(); } break; } } } } return dpdkOfPort; } public static ServiceFunctionForwarder findSffByIp(ServiceFunctionForwarders sffs, final IpAddress remoteIp) { List<ServiceFunctionForwarder> serviceFunctionForwarders = sffs.getServiceFunctionForwarder(); if (serviceFunctionForwarders != null && !serviceFunctionForwarders.isEmpty()) { for (ServiceFunctionForwarder sff : serviceFunctionForwarders) { List<SffDataPlaneLocator> sffDataPlaneLocator = sff.getSffDataPlaneLocator(); if (sffDataPlaneLocator != null) { for (SffDataPlaneLocator sffLocator : sffDataPlaneLocator) { LocatorType locatorType = sffLocator.getDataPlaneLocator().getLocatorType(); if (locatorType instanceof Ip) { Ip ip = (Ip) locatorType; if (ip.getIp().equals(remoteIp)) { return sff; } } } } } } return null; } }