From e290f9024077b4ce8b0dc2cffb75bfc29b4cec99 Mon Sep 17 00:00:00 2001 From: Martin Bobak Date: Wed, 27 Aug 2014 23:13:35 +0200 Subject: [PATCH] Bug 1544 - Explicit LLDP flow to punt whole LLDP packets to the controller Change-Id: I2943e1d13828212f8a9912ceb3f155bc034f8808 Signed-off-by: Martin Bobak --- .../md/core/sal/OpenflowPluginProvider.java | 15 +++ .../md/lldp/LLDPPAcketPuntEnforcer.java | 127 ++++++++++++++++++ .../md/lldp/LLDPDataChangeListenerTest.java | 70 ++++++++++ 3 files changed, 212 insertions(+) create mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPPAcketPuntEnforcer.java create mode 100644 openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPDataChangeListenerTest.java diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java index 24fa9084ee..2ec7fb1458 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java @@ -10,6 +10,8 @@ package org.opendaylight.openflowplugin.openflow.md.core.sal; import java.util.Collection; import java.util.Collections; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; @@ -19,11 +21,16 @@ import org.opendaylight.openflowplugin.extension.api.ExtensionConverterRegistrat import org.opendaylight.openflowplugin.openflow.md.core.MDController; import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionConverterManagerImpl; import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionConverterManager; +import org.opendaylight.openflowplugin.openflow.md.lldp.LLDPPAcketPuntEnforcer; import org.opendaylight.openflowplugin.statistics.MessageCountCommandProvider; import org.opendaylight.openflowplugin.statistics.MessageCountDumper; import org.opendaylight.openflowplugin.statistics.MessageObservatory; import org.opendaylight.openflowplugin.statistics.MessageSpyCounterImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; @@ -91,6 +98,14 @@ public class OpenflowPluginProvider implements BindingAwareProvider, AutoCloseab LOG.debug("onSessionInitiated"); registrationManager = new SalRegistrationManager(); registrationManager.onSessionInitiated(session); + //TODO : LLDPPAcketPuntEnforcer should be instantiated and registered in separate module driven by config subsystem + InstanceIdentifier path = InstanceIdentifier.create(Nodes.class).child(Node.class); + registrationManager.getSessionManager().getDataBroker().registerDataChangeListener( + LogicalDatastoreType.OPERATIONAL, + path, + new LLDPPAcketPuntEnforcer( + session.getRpcService(SalFlowService.class)), + AsyncDataBroker.DataChangeScope.BASE); mdController = new MDController(); mdController.setSwitchConnectionProviders(switchConnectionProviders); mdController.setMessageSpyCounter(messageCountProvider); diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPPAcketPuntEnforcer.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPPAcketPuntEnforcer.java new file mode 100644 index 0000000000..f1969badec --- /dev/null +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPPAcketPuntEnforcer.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2014 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 + */ + +package org.opendaylight.openflowplugin.openflow.md.lldp; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.openflowplugin.openflow.md.OFConstants; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +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.service.rev130819.AddFlowInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags; +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.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Created by Martin Bobak mbobak@cisco.com on 8/27/14. + */ +public class LLDPPAcketPuntEnforcer implements DataChangeListener { + + private static final short TABLE_ID = (short) 0; + private static final String LLDP_PUNT_WHOLE_PACKET_FLOW = "LLDP_PUNT_WHOLE_PACKET_FLOW"; + private static final String DEFAULT_FLOW_ID = "42"; + private final SalFlowService flowService; + + public LLDPPAcketPuntEnforcer(SalFlowService flowService) { + this.flowService = flowService; + } + + @Override + public void onDataChanged(AsyncDataChangeEvent, DataObject> change) { + final Set> changedDataKeys = change.getCreatedData().keySet(); + + for (InstanceIdentifier key : changedDataKeys) { + AddFlowInputBuilder addFlowInput = new AddFlowInputBuilder(createFlow()); + addFlowInput.setNode(new NodeRef(key)); + this.flowService.addFlow(addFlowInput.build()); + } + } + + + protected Flow createFlow() { + FlowBuilder flowBuilder = new FlowBuilder(); + flowBuilder.setMatch(new MatchBuilder().build()); + flowBuilder.setInstructions(createSendToControllerInstructions().build()); + flowBuilder.setPriority(0); + + FlowKey key = new FlowKey(new FlowId(DEFAULT_FLOW_ID)); + flowBuilder.setBarrier(Boolean.FALSE); + // flow.setBufferId(new Long(12)); + BigInteger value = new BigInteger("10", 10); + // BigInteger outputPort = new BigInteger("65535", 10); + flowBuilder.setCookie(new FlowCookie(value)); + flowBuilder.setCookieMask(new FlowCookie(value)); + flowBuilder.setHardTimeout(0); + flowBuilder.setIdleTimeout(0); + flowBuilder.setInstallHw(false); + flowBuilder.setStrict(false); + flowBuilder.setContainerName(null); + flowBuilder.setFlags(new FlowModFlags(false, false, false, false, true)); + flowBuilder.setId(new FlowId("12")); + flowBuilder.setTableId(TABLE_ID); + flowBuilder.setKey(key); + flowBuilder.setFlowName(LLDP_PUNT_WHOLE_PACKET_FLOW); + + return flowBuilder.build(); + } + + private static InstructionsBuilder createSendToControllerInstructions() { + List actionList = new ArrayList(); + ActionBuilder ab = new ActionBuilder(); + + OutputActionBuilder output = new OutputActionBuilder(); + output.setMaxLength(OFConstants.OFPCML_NO_BUFFER); + Uri value = new Uri(OutputPortValues.CONTROLLER.toString()); + output.setOutputNodeConnector(value); + ab.setAction(new OutputActionCaseBuilder().setOutputAction(output.build()).build()); + ab.setOrder(0); + ab.setKey(new ActionKey(0)); + actionList.add(ab.build()); + // Create an Apply Action + ApplyActionsBuilder aab = new ApplyActionsBuilder(); + aab.setAction(actionList); + + // Wrap our Apply Action in an Instruction + InstructionBuilder ib = new InstructionBuilder(); + ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build()); + ib.setOrder(0); + ib.setKey(new InstructionKey(0)); + + // Put our Instruction in a list of Instructions + InstructionsBuilder isb = new InstructionsBuilder(); + List instructions = new ArrayList(); + instructions.add(ib.build()); + isb.setInstruction(instructions); + return isb; + } + +} diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPDataChangeListenerTest.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPDataChangeListenerTest.java new file mode 100644 index 0000000000..ad4b1f8d44 --- /dev/null +++ b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPDataChangeListenerTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014 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 + */ + +package org.opendaylight.openflowplugin.openflow.md.lldp; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase; +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.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; + +/** + * Created by Martin Bobak mbobak@cisco.com on 8/29/14. + */ +public class LLDPDataChangeListenerTest { + + @Mock + private static SalFlowService flowService; + + /** + * Test method for {@link LLDPPAcketPuntEnforcer#createFlow()} + * which ensures that LLDPDataChangeListener creates proper flow for + */ + @Test + public void testCreateFlow() { + LLDPPAcketPuntEnforcer lldpDataChangeListener = new LLDPPAcketPuntEnforcer(flowService); + evaluateFlow(lldpDataChangeListener.createFlow()); + } + + private final void evaluateFlow(Flow flow) { + evaluateInstructions(flow.getInstructions()); + } + + private final void evaluateInstructions(Instructions instructions) { + assertNotNull(instructions.getInstruction()); + assertEquals(1, instructions.getInstruction().size()); + Instruction instruction = instructions.getInstruction().get(0); + evaluateInstruction(instruction); + } + + private final void evaluateInstruction(Instruction instruction) { + if (instruction.getInstruction() instanceof ApplyActionsCase) { + ApplyActionsCase applyActionsCase = (ApplyActionsCase) instruction.getInstruction(); + assertNotNull(applyActionsCase.getApplyActions().getAction()); + assertEquals(1, applyActionsCase.getApplyActions().getAction().size()); + Action action = applyActionsCase.getApplyActions().getAction().get(0); + evaluateAction(action); + } + } + + private final void evaluateAction(Action action) { + if (action.getAction() instanceof OutputActionCase) { + OutputActionCase outputActionCase = (OutputActionCase) action.getAction(); + assertEquals("CONTROLLER", outputActionCase.getOutputAction().getOutputNodeConnector().getValue()); + assertEquals(new Integer(0xffff).intValue(), outputActionCase.getOutputAction().getMaxLength().intValue()); + } + } +} -- 2.36.6