/* * Copyright (c) 2014, 2017 by Ericsson and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.sfc.ofrenderer.utils; import java.util.List; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfName; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffDataPlaneLocatorName; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.function.base.SfDataPlaneLocator; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction; 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.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.service.function.forwarder.ServiceFunctionDictionary; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.service.function.forwarder.service.function.dictionary.SffSfDataPlaneLocator; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfg.rev150214.service.function.groups.ServiceFunctionGroup; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sft.rev140701.service.function.types.ServiceFunctionType; import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.MacAddressLocator; 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.Mac; import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.DpnIdType; import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.service.functions.service.function.sf.data.plane.locator.locator.type.LogicalInterface; import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.ofs.rev150408.SffDataPlaneLocator1; import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.ofs.rev150408.port.details.OfsPort; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* * This Abstract Base class allows us to completely isolate the * SfcOfRspProcessor and SfcOfSfgDataListener from the sfc-provider-api * and the controller data store, which makes it much easier to Unit * Test both classes. * * @author Brady Johnson */ public abstract class SfcOfBaseProviderUtils { protected static final Logger LOG = LoggerFactory.getLogger(SfcOfBaseProviderUtils.class); public abstract void addRsp(long rspId); public abstract void removeRsp(long rspId); public abstract ServiceFunction getServiceFunction(SfName sfName, long rspId); public abstract ServiceFunctionType getServiceFunctionType(SfName sfName, long rspId); public abstract ServiceFunctionForwarder getServiceFunctionForwarder(SffName sffName, long rspId); public abstract ServiceFunctionGroup getServiceFunctionGroup(String sfgName, long rspId); public abstract Long getPortNumberFromName(String bridgeName, String portName, long rspId); // Get the SFF DPLs that are not used by SFs. Useful when there are multiple // DPL types: one for the SFs and another for the SFF trunk. public abstract List<SffDataPlaneLocator> getSffNonSfDataPlaneLocators(ServiceFunctionForwarder sff); /** * Return a named SffDataPlaneLocator on a SFF. * * @param sff * - The SFF to search in * @param dplName * - The name of the DPL to look for * @return SffDataPlaneLocator or null if not found */ public SffDataPlaneLocator getSffDataPlaneLocator(ServiceFunctionForwarder sff, SffDataPlaneLocatorName dplName) { SffDataPlaneLocator sffDpl = null; if (dplName == null || dplName.getValue() == null) { return null; } List<SffDataPlaneLocator> sffDataPlanelocatorList = sff.getSffDataPlaneLocator(); for (SffDataPlaneLocator sffDataPlanelocator : sffDataPlanelocatorList) { if (sffDataPlanelocator.getName() != null) { if (sffDataPlanelocator.getName().getValue().equals(dplName.getValue())) { sffDpl = sffDataPlanelocator; break; } } } return sffDpl; } /** * Return the SfDataPlaneLocator on the SF that connects to the named SFF. * * @param sf * the ServiceFunction to search through * @param sffName * the SFF name to search for * @return SfDataPlaneLocator or null if not found */ public SfDataPlaneLocator getSfDataPlaneLocator(ServiceFunction sf, final SffName sffName) { List<SfDataPlaneLocator> sfDataPlanelocatorList = sf.getSfDataPlaneLocator(); for (SfDataPlaneLocator sfDpl : sfDataPlanelocatorList) { if (sfDpl.getServiceFunctionForwarder().equals(sffName)) { return sfDpl; } } return null; } /** * Given a ServiceFunction get the SF DPL name from the * SffSfDataPlaneLocator and return the SF DPL. * * @param sf * the ServiceFunction to search through * @param sffSfDpl * The SffSf DPL to compare against * @return SfDataPlaneLocator if found, else null */ public SfDataPlaneLocator getSfDataPlaneLocator(ServiceFunction sf, SffSfDataPlaneLocator sffSfDpl) { List<SfDataPlaneLocator> sfDataPlanelocatorList = sf.getSfDataPlaneLocator(); for (SfDataPlaneLocator sfDpl : sfDataPlanelocatorList) { if (sfDpl.getName().getValue().equals(sffSfDpl.getSfDplName().getValue())) { return sfDpl; } } return null; } /** * Return the named SF ServiceFunctionDictionary SffSfDataPlaneLocator from * the sff sf-dictionary list. * * @param sff * - The SFF to search in * @param sfName * - The name of the DPL to look for * @return SffSfDataPlaneLocator or null if not found */ public SffSfDataPlaneLocator getSffSfDataPlaneLocator(ServiceFunctionForwarder sff, SfName sfName) { SffSfDataPlaneLocator sffSfDpl = null; ServiceFunctionDictionary sffSfDict = getSffSfDictionary(sff, sfName); if (sffSfDict != null) { sffSfDpl = sffSfDict.getSffSfDataPlaneLocator(); } return sffSfDpl; } /** * Return the named SF ServiceFunctionDictionary element from the sff * sf-dictionary list. * * @param sff * the SFF to search through * @param sfName * the SF name to look for * @return A ServiceFunctionDictionary entry or null if not found */ public ServiceFunctionDictionary getSffSfDictionary(ServiceFunctionForwarder sff, SfName sfName) { ServiceFunctionDictionary sffSfDict = null; List<ServiceFunctionDictionary> sffSfDictList = sff.getServiceFunctionDictionary(); if (sffSfDictList != null) { for (ServiceFunctionDictionary dict : sffSfDictList) { if (dict.getName().getValue().equals(sfName.getValue())) { sffSfDict = dict; break; } } } return sffSfDict; } /** * Return the mac address from a SF DPL, only if its a MAC DPL. * * @param sfDpl * the SF DPL to process * @return macAddress string or null if its not a MAC DPL */ public String getSfDplMac(SfDataPlaneLocator sfDpl) { String sfMac = null; LocatorType sffLocatorType = sfDpl.getLocatorType(); Class<? extends DataContainer> implementedInterface = sffLocatorType.getImplementedInterface(); // Mac/IP and possibly VLAN if (implementedInterface.equals(Mac.class)) { if (((MacAddressLocator) sffLocatorType).getMac() != null) { sfMac = ((MacAddressLocator) sffLocatorType).getMac().getValue(); } } return sfMac; } /** * Return the mac address from a SFF DPL, only if its a MAC DPL. * * @param sfDpl the SFF DPL to process * @return macAddress string or null if its not a MAC DPL */ public String getSffDplMac(SffDataPlaneLocator sfDpl) { String sffMac = null; LocatorType sffLocatorType = sfDpl.getDataPlaneLocator().getLocatorType(); Class<? extends DataContainer> implementedInterface = sffLocatorType.getImplementedInterface(); // Mac/IP and possibly VLAN if (implementedInterface.equals(Mac.class)) { if (((MacAddressLocator) sffLocatorType).getMac() != null) { sffMac = ((MacAddressLocator) sffLocatorType).getMac().getValue(); } } return sffMac; } /** * Given an SFF object and SFF-SF dictionary entry, return the switch port * string. Looks for the SFF DPL name in the SFF-SF dictionary, then looks * up that DPL name on the SFF. * * @param sff * the SFF to process * @param dict * used to get the SFF DPL name * @return switch port string, INPORT if not augmented, INPORT if not found */ public String getDictPortInfoPort(final ServiceFunctionForwarder sff, final ServiceFunctionDictionary dict) { SffDataPlaneLocator sffDpl = getSffDataPlaneLocator(sff, dict.getSffSfDataPlaneLocator().getSffDplName()); OfsPort ofsPort = getSffPortInfoFromDpl(sffDpl); if (ofsPort == null) { // This case is most likely because the sff-of augmentation wasnt // used // assuming the packet should just be sent on the same port it was // received on return OutputPortValues.INPORT.toString(); } return ofsPort.getPortId(); } /** * Given a possibly augmented SFF DPL, return the augmented OfsPort object. * * @param sffDpl * The SFF DPL to process * @return OfsPort, null if not augmented, null if not found */ public OfsPort getSffPortInfoFromDpl(final SffDataPlaneLocator sffDpl) { if (sffDpl == null) { return null; } SffDataPlaneLocator1 ofsDpl = sffDpl.getAugmentation(SffDataPlaneLocator1.class); if (ofsDpl == null) { LOG.debug("No OFS DPL available for dpl [{}]", sffDpl.getName().getValue()); return null; } return ofsDpl.getOfsPort(); } /** * Given a possibly augmented SFF DPL, return the DPL switch port. The * augmentation will be a OfsPort object. * * @param dpl * the SFF DPL to process * @return switch port string, INPORT if not augmented, INPORT if not found */ public String getDplPortInfoPort(final SffDataPlaneLocator dpl) { OfsPort ofsPort = getSffPortInfoFromDpl(dpl); if (ofsPort == null) { // This case is most likely because the sff-of augmentation wasnt // used // assuming the packet should just be sent on the same port it was // received on return OutputPortValues.INPORT.toString(); } return ofsPort.getPortId(); } /** * Given a possibly augmented SFF DPL, return the DPL mac address. The * augmentation will be a OfsPort object. * * @param dpl * the SFF DPL to process * @return mac address string, null if not augmented, null if not found */ public String getDplPortInfoMac(final SffDataPlaneLocator dpl) { if (dpl == null) { return null; } String macStr = null; OfsPort ofsPort = getSffPortInfoFromDpl(dpl); if (ofsPort != null) { if (ofsPort.getMacAddress() != null) { macStr = ofsPort.getMacAddress().getValue(); } } if (macStr == null) { if (dpl.getDataPlaneLocator().getTransport() .equals(org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.Mac.class)) { MacAddress mac = ((MacAddressLocator) dpl.getDataPlaneLocator().getLocatorType()).getMac(); if (mac != null) { macStr = mac.getValue(); } } } return macStr; } /** * Given an SFF object and SFF-SF dictionary entry, return the SFF Mac. * Looks for the SFF DPL name in the SFF-SF dictionary, then looks up that * DPL name on the SFF. * * @param sff * The SFF to process * @param dict * contains the SFF DPL name to process * @return MAC Address string, null if the DPL is not mac, null if not found */ public String getDictPortInfoMac(final ServiceFunctionForwarder sff, final ServiceFunctionDictionary dict) { SffDataPlaneLocator sffDpl = getSffDataPlaneLocator(sff, dict.getSffSfDataPlaneLocator().getSffDplName()); String macStr = getDplPortInfoMac(sffDpl); // If the SFF DPL wasnt augmented, check if the DPL is of type mac, and // return that mac address if (macStr == null) { if (sffDpl.getDataPlaneLocator().getTransport() .equals(org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.Mac.class)) { MacAddress mac = ((MacAddressLocator) sffDpl.getDataPlaneLocator().getLocatorType()).getMac(); if (mac != null) { macStr = mac.getValue(); } } } return macStr; } /** * Given an SFF name, return the augmented OpenFlow NodeName. * * @param sffName * The SFF name to process * @param rspId * the rsp the SFF is being processed on * @return OpenFlow NodeName, null if not augmented, null if not found */ public String getSffOpenFlowNodeName(final SffName sffName, long rspId) { ServiceFunctionForwarder sff = getServiceFunctionForwarder(sffName, rspId); // TODO return more addressing type - NodeId return getSffOpenFlowNodeName(sff); } /** * Given an SFF name, return the augmented OpenFlow NodeName. * * @param sffName * The SFF name to process * @param rspId * the rsp the SFF is being processed on * @param dpnid * data plane node identifier for the switch. It is null when it * is not known; when provided, it is used directly to build the * openflow node name * @return OpenFlow NodeName, null if not augmented, null if not found */ public String getSffOpenFlowNodeName(final SffName sffName, long rspId, final DpnIdType dpnid) { if (dpnid != null) { // part of logical sff: openflow node name = "openflow:dpnid" return "openflow:" + dpnid.getValue(); } return getSffOpenFlowNodeName(sffName, rspId); } /** * Given an SFF object, return the augmented OpenFlow NodeName. * * @param sff * The SFF name to process * @return OpenFlow NodeName or null if augmented or not found */ public String getSffOpenFlowNodeName(final ServiceFunctionForwarder sff) { if (sff == null) { return null; } // Check if its an service-function-forwarder-ovs augmentation // if it is, then get the open flow node id there SffOvsBridgeAugmentation ovsSff = sff.getAugmentation(SffOvsBridgeAugmentation.class); if (ovsSff != null) { if (ovsSff.getOvsBridge() != null) { return ovsSff.getOvsBridge().getOpenflowNodeId(); } } // it its not an sff-ovs, then just return the ServiceNode return sff.getServiceNode().getValue(); } /** * Given a SF, retrieve the logical interface name. * * @param sf * The service function to use * @return String the logical interface name when the SF is using a logical * interface; null otherwise */ public String getSfLogicalInterfaceName(ServiceFunction sf) { String interfaceName = null; LOG.debug("getSfLogicalInterfaceName: called for sf {}", sf.getName()); if (sf.getSfDataPlaneLocator() != null && sf.getSfDataPlaneLocator().get(0) != null) { SfDataPlaneLocator sfdpl = sf.getSfDataPlaneLocator().get(0); LOG.debug("getSfLogicalInterfaceName: dpl 0 is not null! it is {}", sfdpl); if (sfdpl.getLocatorType() != null && sfdpl.getLocatorType().getImplementedInterface() == LogicalInterface.class) { LogicalInterface logicalInterface = (LogicalInterface) sfdpl.getLocatorType(); if (logicalInterface != null && logicalInterface.getInterfaceName() != null) { LOG.debug("getSfLogicalInterfaceName: hop is using a logical interface [{}]", logicalInterface.getInterfaceName()); interfaceName = logicalInterface.getInterfaceName(); } } } return interfaceName; } public SffDataPlaneLocator getSffSfDict_SffDpl(SfName sfName, SffName sffName, long rspId) { ServiceFunctionForwarder sff = getServiceFunctionForwarder(sffName, rspId); for (ServiceFunctionDictionary sffDict : sff.getServiceFunctionDictionary()) { if (sffDict.getName().equals(sfName)) { return getSffDataPlaneLocator(sff, sffDict.getSffSfDataPlaneLocator().getSffDplName()); } } return null; } /** * Return a named SffDataPlaneLocator on a SFF. * * @param sffName * The SFF name to search in * @param rspId * rendered service path ID * @return list of SffDataPlaneLocator or null if not found */ public List<SffDataPlaneLocator> getSffDataPlaneLocators(SffName sffName, long rspId) { ServiceFunctionForwarder sff = getServiceFunctionForwarder(sffName, rspId); if (sff == null || sff.getSffDataPlaneLocator() == null) { return null; } return sff.getSffDataPlaneLocator(); } }