Static Pipeline is constructed with the help of AbstractServiceInstance and PipelineO... 46/10546/1
authorMadhu Venugopal <mavenugo@gmail.com>
Sun, 31 Aug 2014 14:04:05 +0000 (07:04 -0700)
committerMadhu Venugopal <mavenugo@gmail.com>
Sun, 31 Aug 2014 14:04:05 +0000 (07:04 -0700)
- Since we decided to implement the Static pipeline, there is no datapath requirement to keep a Director.
  Since the pipeline is static, the PipelineOrchestrator coordinages with the AbstractServiceInstance to program the direct path between the Tables
  without any involvement from the Concrete Service that is implemented on top of AbstractServiceInstance.
  Hence, this change removes Director table from the pipeline. But, the software design remains intact wherein the logic of pipeline datapath management
  still resides in AbstractServiceInstance, which the Concrete Service class need not be worried about.
- Implemented a sample L2RewriteService that extends from AbstractServiceInstance and registers itself with PipelineOrchestratorImpl through regular OSGi Service Registry

Change-Id: Ib27a795ebd428fc0a3b97aa3d18d825fe8427246
Signed-off-by: Madhu Venugopal <mavenugo@gmail.com>
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/Activator.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/AbstractServiceInstance.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestrator.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestratorImpl.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/L2RewriteService.java [new file with mode: 0644]
openstack/net-virt-providers/src/test/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/PipelineOrchestratorTest.java

index 7d118f3afd4c68a987e6163d36a8b24f8554dc81..c4c5d172292555702fff4a1fa9ff44e882da6886 100644 (file)
@@ -10,6 +10,9 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.providers;
 
+import java.util.Properties;
+
+import org.apache.felix.dm.Component;
 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
@@ -19,14 +22,16 @@ import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow10.OF10Provider;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.MdsalConsumer;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.MdsalConsumerImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.OF13Provider;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestratorImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.L2RewriteService;
 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
-import org.apache.felix.dm.Component;
-
-import java.util.Properties;
 
 /**
  * OSGi Bundle Activator for the Neutron providers
@@ -62,7 +67,9 @@ public class Activator extends ComponentActivatorAbstractBase {
     public Object[] getImplementations() {
         Object[] res = {MdsalConsumerImpl.class,
                         OF10Provider.class,
-                        OF13Provider.class};
+                        OF13Provider.class,
+                        PipelineOrchestratorImpl.class,
+                        L2RewriteService.class};
         return res;
     }
 
@@ -132,5 +139,24 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.add(createServiceDependency().setService(OvsdbConnectionService.class).setRequired(true));
             c.add(createServiceDependency().setService(MdsalConsumer.class).setRequired(true));
         }
+
+        if (imp.equals(L2RewriteService.class)) {
+            Properties properties = new Properties();
+            properties.put(AbstractServiceInstance.SERVICE_PROPERTY, Service.L2_REWRITE);
+            c.setInterface(AbstractServiceInstance.class.getName(), properties);
+
+            c.add(createServiceDependency()
+                          .setService(PipelineOrchestrator.class)
+                          .setRequired(true));
+            c.add(createServiceDependency().setService(MdsalConsumer.class).setRequired(true));
+        }
+
+        if (imp.equals(PipelineOrchestratorImpl.class)) {
+            c.setInterface(PipelineOrchestrator.class.getName(), null);
+            c.add(createServiceDependency()
+                           .setService(AbstractServiceInstance.class)
+                           .setCallbacks("registerService", "unregisterService"));
+        }
+
     }
 }
index 3e6cf2365b2c05a9c19cbaba42afc8e8175e704e..b977875bdf0f2dc7c72107f0fd0d3fe93735478d 100644 (file)
@@ -9,8 +9,51 @@
  */
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
 
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+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;
+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.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.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.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.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * Any ServiceInstance class that extends AbstractServiceInstance to be a part of the pipeline
+ * have 2 basic requirements : <br>
+ * 1. Program a default pipeline flow to take any unmatched traffic to the next table in the pipeline. <br>
+ * 2. Get Pipeline Instructions from AbstractServiceInstance (using getMutablePipelineInstructionBuilder) and
+ *    use it in any matching flows that needs to be further processed by next service in the pipeline.
+ *
+ */
 public abstract class AbstractServiceInstance {
-    Service service;
+    public static final String SERVICE_PROPERTY ="serviceProperty";
+    private Service service;
+    private volatile PipelineOrchestrator orchestrator;
+
     public AbstractServiceInstance (Service service) {
         this.service = service;
     }
@@ -18,4 +61,113 @@ public abstract class AbstractServiceInstance {
     public int getTable() {
         return service.getTable();
     }
+
+    public Service getService() {
+        return service;
+    }
+
+    public void setService(Service service) {
+        this.service = service;
+    }
+
+    private NodeBuilder createNodeBuilder(String nodeId) {
+        NodeBuilder builder = new NodeBuilder();
+        builder.setId(new NodeId(nodeId));
+        builder.setKey(new NodeKey(builder.getId()));
+        return builder;
+    }
+
+    /**
+     * This method returns the required Pipeline Instructions to by used by any matching flows that needs
+     * to be further processed by next service in the pipeline.
+     *
+     * Important to note that this is a convenience method which returns a mutable instructionBuilder which
+     * needs to be further adjusted by the concrete ServiceInstance class such as setting the Instruction Order, etc.
+     * @return Newly created InstructionBuilder to be used along with other instructions on the main flow
+     */
+    protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
+        Service nextService = orchestrator.getNextServiceInPipeline(service);
+        if (nextService != null) {
+            return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
+        } else {
+            return InstructionUtils.createDropInstructions(new InstructionBuilder());
+        }
+    }
+
+    private static final Logger logger = LoggerFactory.getLogger(AbstractServiceInstance.class);
+    private volatile MdsalConsumer mdsalConsumer;
+
+    public void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
+        Preconditions.checkNotNull(mdsalConsumer);
+        if (mdsalConsumer == null) {
+            logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
+            return;
+        }
+
+        DataBroker dataBroker = mdsalConsumer.getDataBroker();
+        if (dataBroker == null) {
+            logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
+            return;
+        }
+
+        ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
+        InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
+                new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
+
+        //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
+        modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(), true /*createMissingParents*/);
+
+
+        CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
+        try {
+            commitFuture.get();  // TODO: Make it async (See bug 1362)
+            logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
+        } catch (InterruptedException|ExecutionException e) {
+            logger.error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Program Default Pipeline Flow.
+     *
+     * @param nodeId Node on which the default pipeline flow is programmed.
+     */
+    protected void programDefaultPipelineRule(String nodeId) {
+        MatchBuilder matchBuilder = new MatchBuilder();
+        FlowBuilder flowBuilder = new FlowBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeId);
+
+        // Create the OF Actions and Instructions
+        InstructionsBuilder isb = new InstructionsBuilder();
+
+        // Instructions List Stores Individual Instructions
+        List<Instruction> instructions = Lists.newArrayList();
+
+        // Call the InstructionBuilder Methods Containing Actions
+        InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
+        ib.setOrder(0);
+        ib.setKey(new InstructionKey(0));
+        instructions.add(ib.build());
+
+        // Add InstructionBuilder to the Instruction(s)Builder List
+        isb.setInstruction(instructions);
+
+        // Add InstructionsBuilder to FlowBuilder
+        flowBuilder.setInstructions(isb.build());
+
+        String flowId = "DEFAULT_PIPELINE_FLOW";
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setMatch(matchBuilder.build());
+        flowBuilder.setPriority(0);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(service.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        writeFlow(flowBuilder, nodeBuilder);
+    }
+
 }
index b64a882519063a67226a3607db329ebbf247a867..b2d97dd7dd2c336141076e8bd0307c39142cddf9 100644 (file)
@@ -15,8 +15,6 @@ package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
  * to share a common OpenFlow 1.3 based multi-table pipeline.
  */
 public interface PipelineOrchestrator {
-    void registerService(Service service, AbstractServiceInstance serviceInstance);
-    void unregisterService(Service service);
     public Service getNextServiceInPipeline(Service service);
     AbstractServiceInstance getServiceInstance(Service service);
 }
index 696601b1b7236f4ebcd4bb702829de315e973e12..3b5165c7d732abe99d7279deff6a312e85da58fd 100644 (file)
@@ -13,6 +13,8 @@ package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
 import java.util.List;
 import java.util.Map;
 
+import org.osgi.framework.ServiceReference;
+
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
@@ -20,7 +22,6 @@ public class PipelineOrchestratorImpl implements PipelineOrchestrator {
 
     private List<Service> staticPipeline = Lists.newArrayList(
                                                                 Service.CLASSIFIER,
-                                                                Service.DIRECTOR,
                                                                 Service.ARP_RESPONDER,
                                                                 Service.INBOUND_NAT,
                                                                 Service.INGRESS_ACL,
@@ -35,17 +36,15 @@ public class PipelineOrchestratorImpl implements PipelineOrchestrator {
 
     public PipelineOrchestratorImpl() {
     }
-    @Override
-    public void registerService(Service service,
-            AbstractServiceInstance serviceInstance) {
+
+    public void registerService(final ServiceReference ref, AbstractServiceInstance serviceInstance){
+        Service service = (Service)ref.getProperty(AbstractServiceInstance.SERVICE_PROPERTY);
         serviceRegistry.put(service, serviceInstance);
     }
 
-    @Override
-    public void unregisterService(Service service) {
-        serviceRegistry.remove(service);
+    public void unregisterService(final ServiceReference ref) {
+        serviceRegistry.remove(ref.getProperty(AbstractServiceInstance.SERVICE_PROPERTY));
     }
-
     @Override
     public Service getNextServiceInPipeline(Service service) {
         int index = staticPipeline.indexOf(service);
diff --git a/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/L2RewriteService.java b/openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/L2RewriteService.java
new file mode 100644 (file)
index 0000000..29a95b2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors : Madhu Venugopal
+ */
+package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
+
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
+import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+
+public class L2RewriteService extends AbstractServiceInstance {
+    public L2RewriteService() {
+        super(Service.L2_REWRITE);
+    }
+
+    public L2RewriteService(Service service) {
+        super(service);
+    }
+}
index 9707cdcfe72e8028abc6b6b96ee536ce0f6e3f85..7aec1eeaf47ae1e8f590bc7d67a3ebf80ba2a9b9 100644 (file)
@@ -15,8 +15,7 @@ public class PipelineOrchestratorTest {
 
     @Test
     public void testPipeline() {
-        assertEquals(orchestrator.getNextServiceInPipeline(Service.CLASSIFIER), Service.DIRECTOR);
-        assertEquals(orchestrator.getNextServiceInPipeline(Service.DIRECTOR), Service.ARP_RESPONDER);
+        assertEquals(orchestrator.getNextServiceInPipeline(Service.CLASSIFIER), Service.ARP_RESPONDER);
         assertEquals(orchestrator.getNextServiceInPipeline(Service.ARP_RESPONDER), Service.INBOUND_NAT);
         assertEquals(orchestrator.getNextServiceInPipeline(Service.INBOUND_NAT), Service.INGRESS_ACL);
         assertEquals(orchestrator.getNextServiceInPipeline(Service.INGRESS_ACL), Service.LOAD_BALANCER);