Bug 1544 - Explicit LLDP flow to punt whole LLDP packets to the controller 78/10478/4
authorMartin Bobak <mbobak@cisco.com>
Wed, 27 Aug 2014 21:13:35 +0000 (23:13 +0200)
committermichal rehak <mirehak@cisco.com>
Mon, 1 Sep 2014 12:11:09 +0000 (12:11 +0000)
Change-Id: I2943e1d13828212f8a9912ceb3f155bc034f8808
Signed-off-by: Martin Bobak <mbobak@cisco.com>
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPPAcketPuntEnforcer.java [new file with mode: 0644]
openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPDataChangeListenerTest.java [new file with mode: 0644]

index 24fa9084ee9b7af299d9c71c794835d8ee3c56a5..2ec7fb1458656a1d0d4bf3315371cd6a9d1f57cb 100644 (file)
@@ -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.<SalFlowService>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 (file)
index 0000000..f1969ba
--- /dev/null
@@ -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<InstanceIdentifier<?>, DataObject> change) {
+        final Set<InstanceIdentifier<?>> 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<Action> actionList = new ArrayList<Action>();
+        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<Instruction> instructions = new ArrayList<Instruction>();
+        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 (file)
index 0000000..ad4b1f8
--- /dev/null
@@ -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());
+        }
+    }
+}