/* * Copyright (c) 2016, 2017 Ericsson Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.sfc.scfofrenderer.utils; import java.util.ArrayList; import java.util.List; import org.opendaylight.sfc.util.macchaining.VirtualMacAddress; import org.opendaylight.sfc.util.openflow.OpenflowConstants; import org.opendaylight.sfc.util.openflow.SfcOpenflowUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; public class SfcScfOfUtils { // TODO this must be defined somewhere else; link to 'it' rather than have // it here private static final short TABLE_INDEX_CLASSIFIER = 0; private static final short TABLE_INDEX_INGRESS_TRANSPORT = 1; public static final int FLOW_PRIORITY_CLASSIFIER = 1000; public static final int FLOW_PRIORITY_MATCH_ANY = 5; public static final short NSH_MDTYPE_ONE = 0x1; public static final short NSH_NP_ETH = 0x3; /** * Get a FlowBuilder object that install the table-miss in the classifier * table. * * @return the FlowBuilder object, with a MatchAny match, and a single * GotoTable (transport ingress) instruction */ public static FlowBuilder initClassifierTable() { MatchBuilder match = new MatchBuilder(); InstructionsBuilder isb = SfcOpenflowUtils.appendGotoTableInstruction(new InstructionsBuilder(), TABLE_INDEX_INGRESS_TRANSPORT); return SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_CLASSIFIER, FLOW_PRIORITY_MATCH_ANY, "MatchAny", match, isb); } /** * create classifier DPDK output flow. * * @param outPort * flow out port * @return the {@link FlowBuilder} object */ public static FlowBuilder initClassifierDpdkOutputFlow(Long outPort) { // Create the match criteria MatchBuilder match = new MatchBuilder(); SfcOpenflowUtils.addMatchInPort(match, new NodeConnectorId(OutputPortValues.LOCAL.toString())); // Action output List<Action> actionList = new ArrayList<>(); String outPortStr = "output:" + outPort.toString(); actionList.add(SfcOpenflowUtils.createActionOutPort(outPortStr, actionList.size())); InstructionsBuilder isb = SfcOpenflowUtils.wrapActionsIntoApplyActionsInstruction(actionList); // Create and configure the FlowBuilder return SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_CLASSIFIER, FLOW_PRIORITY_CLASSIFIER, "classifier_dpdk_output", match, isb); } /** * create classifier DPDK input flow. * * @param nodeName * flow table node name * @param inPort * flow in port * @return the {@link FlowBuilder} object */ public static FlowBuilder initClassifierDpdkInputFlow(String nodeName, Long inPort) { // Create the match criteria MatchBuilder match = new MatchBuilder(); SfcOpenflowUtils.addMatchInPort(match, new NodeId(nodeName), inPort); // Action NORMAL List<Action> actionList = new ArrayList<>(); actionList.add(SfcOpenflowUtils.createActionNormal(actionList.size())); InstructionsBuilder isb = SfcOpenflowUtils.wrapActionsIntoApplyActionsInstruction(actionList); // Create and configure the FlowBuilder return SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_CLASSIFIER, FLOW_PRIORITY_CLASSIFIER, "classifier_dpdk_input", match, isb); } /** * create classifier out flow. The function returns true if successful. The * function returns false if unsuccessful. Get a FlowBuilder object w/ the * classifier 'out' flow. * * @param flowKey * flow key * @param match * flow match * @param sfcNshHeader * nsh header * @param outPort * flow out port * @return create flow result */ public static FlowBuilder createClassifierOutFlow(String flowKey, Match match, SfcNshHeader sfcNshHeader, Long outPort) { if (flowKey == null || sfcNshHeader == null || sfcNshHeader.getVxlanIpDst() == null) { return null; } String dstIp = sfcNshHeader.getVxlanIpDst().getValue(); List<Action> theActions = new ArrayList<>(); theActions.add(SfcOpenflowUtils.createActionNxPushNsh(theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxLoadNshMdtype(NSH_MDTYPE_ONE, theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxLoadNshNp(NSH_NP_ETH, theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxSetNsp(sfcNshHeader.getNshNsp(), theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxSetNsi(sfcNshHeader.getNshStartNsi(), theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxSetNshc1(sfcNshHeader.getNshMetaC1(), theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxSetNshc1(sfcNshHeader.getNshMetaC2(), theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxSetNshc1(sfcNshHeader.getNshMetaC3(), theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxSetNshc1(sfcNshHeader.getNshMetaC4(), theActions.size())); theActions .add(SfcOpenflowUtils.createActionNxLoadTunGpeNp(OpenflowConstants.TUN_GPE_NP_NSH, theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxSetTunIpv4Dst(dstIp, theActions.size())); theActions.add(outPort == null ? SfcOpenflowUtils.createActionOutPort(OutputPortValues.INPORT.toString(), theActions.size()) : SfcOpenflowUtils.createActionOutPort(outPort.intValue(), theActions.size())); InstructionsBuilder isb = SfcOpenflowUtils.wrapActionsIntoApplyActionsInstruction(theActions); FlowBuilder flowb = new FlowBuilder(); flowb.setId(new FlowId(flowKey)).setTableId(TABLE_INDEX_CLASSIFIER).setKey(new FlowKey(new FlowId(flowKey))) .setPriority(FLOW_PRIORITY_CLASSIFIER).setMatch(match).setInstructions(isb.build()); return flowb; } /** * Get a FlowBuilder object w/ the classifier 'in' flow. * * @param flowKey * flow key * @param sfcNshHeader * nsh header * @param outPort * flow out port * @return create in result */ public static FlowBuilder createClassifierInFlow(String flowKey, SfcNshHeader sfcNshHeader, Long outPort) { if (flowKey == null || sfcNshHeader == null || sfcNshHeader.getVxlanIpDst() == null) { return null; } MatchBuilder mb = SfcOpenflowUtils.getNshMatches(sfcNshHeader.getNshNsp(), sfcNshHeader.getNshEndNsi()); List<Action> theActions = new ArrayList<>(); theActions.add(SfcOpenflowUtils.createActionNxPopNsh(theActions.size())); theActions.add(outPort == null ? SfcOpenflowUtils.createActionOutPort(OutputPortValues.INPORT.toString(), theActions.size()) : SfcOpenflowUtils.createActionOutPort(outPort.intValue(), theActions.size())); InstructionsBuilder isb = SfcOpenflowUtils.wrapActionsIntoApplyActionsInstruction(theActions); FlowBuilder flowb = new FlowBuilder(); flowb.setId(new FlowId(flowKey)).setTableId(TABLE_INDEX_CLASSIFIER).setKey(new FlowKey(new FlowId(flowKey))) .setPriority(FLOW_PRIORITY_CLASSIFIER).setMatch(mb.build()).setInstructions(isb.build()); return flowb; } /** * Get a FlowBuilder object w/ the classifier relay flow. * * @param flowKey * flow key * @param sfcNshHeader * nsh header * @return the FlowBuilder containing the classifier relay flow */ public static FlowBuilder createClassifierRelayFlow(String flowKey, SfcNshHeader sfcNshHeader) { if (flowKey == null || sfcNshHeader == null || sfcNshHeader.getVxlanIpDst() == null) { return null; } String dstIp = sfcNshHeader.getVxlanIpDst().getValue(); List<Action> theActions = new ArrayList<>(); theActions .add(SfcOpenflowUtils.createActionNxLoadTunGpeNp(OpenflowConstants.TUN_GPE_NP_NSH, theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxSetTunIpv4Dst(dstIp, theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxMoveNsp(theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxMoveNsi(theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxMoveNsc1(theActions.size())); theActions.add(SfcOpenflowUtils.createActionNxMoveNsc2(theActions.size())); theActions.add(SfcOpenflowUtils.createActionOutPort(OutputPortValues.INPORT.toString(), theActions.size())); InstructionsBuilder isb = SfcOpenflowUtils.wrapActionsIntoApplyActionsInstruction(theActions); FlowBuilder flowb = new FlowBuilder(); MatchBuilder mb = SfcOpenflowUtils.getNshMatches(sfcNshHeader.getNshNsp(), sfcNshHeader.getNshEndNsi()); flowb.setId(new FlowId(flowKey)).setTableId(TABLE_INDEX_CLASSIFIER).setKey(new FlowKey(new FlowId(flowKey))) .setPriority(FLOW_PRIORITY_CLASSIFIER).setMatch(mb.build()).setInstructions(isb.build()); return flowb; } /** * delete classifier flow. The function returns true if successful. The * function returns false if unsuccessful. * * @param nodeName * flow table node name * @param flowKey * flow key * @return delete result */ public static boolean deleteClassifierFlow(String nodeName, String flowKey) { if (nodeName == null || flowKey == null) { return false; } return SfcOpenflowUtils.removeFlowFromDataStore(nodeName, new TableKey(TABLE_INDEX_CLASSIFIER), new FlowKey(new FlowId(flowKey))); } /** * create classifier out flow for MAC Chaining. * The function returns true if successful. * The function returns false if unsuccessful. * * @param nodeName flow table node name * @param flowKey flow key * @param match flow match * @param outPort flow out port * @param pathId chain path ID * @param startIndex Firt hop in the chain * @return create flow result */ public static FlowBuilder createMacChainClassifierOutFlow(String nodeName, String flowKey, Match match, String outPort, Long pathId, short startIndex) { int order = 0; VirtualMacAddress vmac = VirtualMacAddress.getForwardAddress(pathId, 0); if ((nodeName == null) || (flowKey == null)) { return null; } Action macDst = SfcOpenflowUtils.createActionSetDlDst(vmac.getHop(startIndex).getValue(), order++); Action out = SfcOpenflowUtils.createActionOutPort(Integer.parseInt(outPort), order++); FlowBuilder flowb = new FlowBuilder(); flowb.setId(new FlowId(flowKey)) .setTableId(TABLE_INDEX_CLASSIFIER) .setKey(new FlowKey(new FlowId(flowKey))) .setPriority(Integer.valueOf(FLOW_PRIORITY_CLASSIFIER)) .setMatch(match) .setInstructions(SfcOpenflowUtils.createInstructionsBuilder(SfcOpenflowUtils .createActionsInstructionBuilder(macDst, out)) .build()); return flowb; //return SfcOpenflowUtils.writeFlowToDataStore(nodeName, flowb); } /** * create classifier relay flow for MAC Chaining. * The function returns true if successful. * The function returns false if unsuccessful. * * @param nodeName flow table node name * @param flowKey flow key * @param outPort flow out port * @param pathId chain path ID * @param startIndex Firt hop in the chain * @param lastIndex Last hop in the chain * @return create relay result */ public static FlowBuilder createClassifierMacChainingRelayFlow(String nodeName, String flowKey, String outPort, Long pathId, short startIndex, short lastIndex) { int order = 0; VirtualMacAddress vmac = VirtualMacAddress.getForwardAddress(pathId, 0); if ((nodeName == null) || (flowKey == null)) { return null; } MatchBuilder mb = new MatchBuilder(); SfcOpenflowUtils.addMatchDstMac(mb, vmac.getHop(lastIndex).getValue()); Action macDst = SfcOpenflowUtils.createActionSetDlDst(vmac.getHop(startIndex).getValue(), order++); Action out = SfcOpenflowUtils.createActionOutPort(Integer.parseInt(outPort), order++); FlowBuilder flowb = new FlowBuilder(); flowb.setId(new FlowId(flowKey)) .setTableId(TABLE_INDEX_CLASSIFIER) .setKey(new FlowKey(new FlowId(flowKey))) .setPriority(Integer.valueOf(FLOW_PRIORITY_CLASSIFIER)) .setMatch(mb.build()) .setInstructions(SfcOpenflowUtils.createInstructionsBuilder(SfcOpenflowUtils .createActionsInstructionBuilder(macDst, out)) .build()); return flowb; //return SfcOpenflowUtils.writeFlowToDataStore(nodeName, flowb); } /** * create classifier out flow for MAC Chaining. * The function returns true if successful. * The function returns false if unsuccessful. * * @param nodeName flow table node name * @param flowKey flow key * @param outPort flow out port * @param gwMac Gateway MAC to recovery original MAC addresses * @param pathId chain path ID * @param startIndex Firt hop in the chain * @return create flow result */ public static FlowBuilder createMacChainClassifierInFlow(String nodeName, String flowKey, String outPort, String gwMac, Long pathId, short startIndex) { int order = 0; VirtualMacAddress vmac = VirtualMacAddress.getForwardAddress(pathId, 0); if ((nodeName == null) || (flowKey == null)) { return null; } MatchBuilder mb = new MatchBuilder(); SfcOpenflowUtils.addMatchDstMac(mb, vmac.getHop(startIndex).getValue()); //set here the gateway MAC to end the chain Action macDst = SfcOpenflowUtils.createActionSetDlDst(gwMac, order++); Action out = SfcOpenflowUtils.createActionOutPort(Integer.parseInt(outPort), order++); FlowBuilder flowb = new FlowBuilder(); flowb.setId(new FlowId(flowKey)) .setTableId(TABLE_INDEX_CLASSIFIER) .setKey(new FlowKey(new FlowId(flowKey))) .setPriority(Integer.valueOf(FLOW_PRIORITY_CLASSIFIER + 1)) .setMatch(mb.build()) .setInstructions(SfcOpenflowUtils.createInstructionsBuilder(SfcOpenflowUtils .createActionsInstructionBuilder(macDst, out)) .build()); return flowb; //return SfcOpenflowUtils.writeFlowToDataStore(nodeName, flowb); } }