Initial code to handle changes to DS 29/17929/2
authorVishal Thapar <vishal.thapar@ericsson.com>
Wed, 8 Apr 2015 14:19:25 +0000 (19:49 +0530)
committerVishal Thapar <vishal.thapar@ericsson.com>
Wed, 8 Apr 2015 14:37:22 +0000 (20:07 +0530)
1. Added InterfaceManager class to handle Data Change Notifications.
2. Added META-INF to .gitignore
3. Modified odl-interfaces.yang to use augment-identifiers
4. Added interfacemgr-api to features

Change-Id: I787c49267476175b55b154e1bb526777e425f84a
Signed-off-by: Vishal Thapar <vishal.thapar@ericsson.com>
.gitignore
features/pom.xml
features/src/main/features/features.xml
interfacemgr/interfacemgr-api/pom.xml
interfacemgr/interfacemgr-api/src/main/yang/odl-interface.yang
interfacemgr/interfacemgr-impl/pom.xml
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfaceManager.java [new file with mode: 0644]
interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfacemgrProvider.java

index 76a4e1efca3e60e7b493b90c23592cd0fb9056fc..bbbe4f26f3abe0b23dee1b6e864860e7031f384a 100644 (file)
@@ -21,3 +21,4 @@ yang-gen-config
 yang-gen-sal
 classes
 maven-metadata-local.xml
+META-INF
index 93656e5f16c7d2bae465cd3f127ef6a1c1eb0a0f..791a11a07faa24f850e346f4d10c9f2c18142771 100644 (file)
@@ -93,6 +93,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <classifier>config</classifier>
       <type>xml</type>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>interfacemgr-api</artifactId>
+      <version>${interfacemgr.version}</version>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>vpnmanager-api</artifactId>
index cf0d91c7cfd1f64fd636ad703cec30036a304b45..390fbaa6c0dd991b51e6e16662cce0431f653a51 100644 (file)
@@ -19,6 +19,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <feature version='${mdsal.version}'>odl-flow-model</feature>
     <bundle>mvn:org.opendaylight.vpnservice/model-bgp/2013.07.15.7-SNAPSHOT</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/vpnmanager-api/${project.version}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-api/${interfacemgr.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/bgpmanager-api/${project.version}</bundle>
   </feature>
   <feature name='odl-vpnservice-impl' version='${project.version}' description='OpenDaylight :: vpnservice :: impl '>
index 955f3c2e48583bb610de1fc4bf2be0ca9cf33cf5..f1dce5500de13c293fdd4027018aed43dcfa30e3 100644 (file)
@@ -40,6 +40,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>yang-common</artifactId>
       <version>${yangtools.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>yang-ext</artifactId>
+      <version>${yang.ext.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.yangtools.model</groupId>
       <artifactId>ietf-inet-types</artifactId>
index 591f31fc184bbf51456fb103d5c5f929dedfd1e3..f1483dba2f25bc5b7104cc7c03f8d83158ba4713 100644 (file)
 
 module odl-interface {
-       namespace "urn:opendaylight:vpnservice:interfacemgr";
+    namespace "urn:opendaylight:vpnservice:interfacemgr";
 
-       prefix "odlif";
+    prefix "odlif";
 
-       import ietf-interfaces {
-               prefix if;
-       }
-       import iana-if-type {
-               prefix ianaift;
-       }
+    import ietf-interfaces {
+        prefix if;
+    }
+
+    import yang-ext {
+        prefix ext;
+    }
+
+    import iana-if-type {
+        prefix ianaift;
+    }
+
+    import ietf-inet-types {
+        prefix inet;
+    }
 
-       import ietf-inet-types {
-               prefix inet;
-       }
-       revision "2015-03-31" {
+    import opendaylight-inventory {
+        prefix inv; revision-date "2013-08-19";
+    }
+
+    revision "2015-03-31" {
         description "ODL Interface Manager Module";
     }
 
-       identity stacked-vlan {
-               base if:interface-type;
-               reference
-               "Q-in-Q interface";
-       }
-       
-       identity l3tunnel {
-               base if:interface-type;
-               reference
-               "l3 tunnel interface";
-       }
-
-       identity mpls {
-               base if:interface-type;
-               reference
-               "MPLS interface";
-       }
-
-       /* l3Tunnel (GRE, VxLAN) logical port */
-       identity tunnel-type-base {
-               description "Base identity for all tunnel-types";
-       }
-
-       identity tunnel-type-vxlan {
-               description "Tunnel type for vxlan tunnels";
-               base tunnel-type-base;
-       }
-
-       identity tunnel-type-gre {
-               description "Tunnel type for gre tunnels";
-               base tunnel-type-base;
-       }
-
-       /* base/common properties */
-       augment "/if:interfaces/if:interface" {
-               leaf of-port-id { 
-                       type string; 
-                       description "can be a physical switch port or virtual switch port e.g. neutron port";
-               } 
-               leaf tenant-id { 
-                       type string; 
-                       description "Tenant that owns particular interface";
-               } /* optional */
-               leaf base-interface { 
-                       type if:interface-ref; 
-                       description "some interfaces need a reference to parent interface ";
-               } 
-       }
-       
-       /* interface type specific properties */
-       
-       /* VLAN logical port */
-       augment "/if:interfaces/if:interface" {
-               when "if:type = 'ianaift:l2vlan'";
-               leaf vlan-id {
-                       type uint16 {
-                               range "1..4094";
-                       }
-                       must "../base-interface" {
-                               description
-                               "If a vlan-id is defined, a base-interface must
-                               be specified.";
-                       }
-               }
-       }
-       
-       /* Q-in-Q logical port */
-       augment "/if:interfaces/if:interface" {
-               when "if:type = 'stacked_vlan'";
-               leaf stacked_vlan-id {
-                       type uint16 {
-                               range "1..4094";
-                       }
-                       must "../base-interface" {
-                               description
-                               "If a vlan-id is defined, a base-interface must
-                               be specified.";
-                       }
-               }
-       }
-
-       augment "/if:interfaces/if:interface" {
-               when "if:type = 'ianaift:l3tunnel'";
-
-               leaf tunnel-type {
+    identity stacked-vlan {
+        base if:interface-type;
+        reference
+        "Q-in-Q interface";
+    }
+
+    identity l3tunnel {
+        base if:interface-type;
+        reference
+        "l3 tunnel interface";
+    }
+
+    identity mpls {
+        base if:interface-type;
+        reference
+        "MPLS interface";
+    }
+
+    /* l3Tunnel (GRE, VxLAN) logical port */
+    identity tunnel-type-base {
+        description "Base identity for all tunnel-types";
+    }
+
+    identity tunnel-type-vxlan {
+        description "Tunnel type for vxlan tunnels";
+        base tunnel-type-base;
+    }
+
+    identity tunnel-type-gre {
+        description "Tunnel type for gre tunnels";
+        base tunnel-type-base;
+    }
+
+    /* base/common properties */
+    augment "/if:interfaces/if:interface" {
+        ext:augment-identifier "base-ids";
+        leaf of-port-id {
+            type inv:node-connector-id;
+            description "can be a physical switch port or virtual switch port e.g. neutron port";
+        }
+        leaf tenant-id {
+            type string;
+            description "Tenant that owns particular interface";
+        } /* optional */
+        leaf base-interface {
+            type if:interface-ref;
+            description "some interfaces need a reference to parent interface ";
+        }
+    }
+
+    /* interface type specific properties */
+
+    /* VLAN logical port */
+    augment "/if:interfaces/if:interface" {
+        ext:augment-identifier "if-l2vlan";
+        when "if:type = 'ianaift:l2vlan'";
+        leaf vlan-id {
+            type uint16 {
+                range "1..4094";
+            }
+            must "../base-interface" {
+                description
+                "If a vlan-id is defined, a base-interface must
+                be specified.";
+            }
+        }
+    }
+
+    /* Q-in-Q logical port */
+    augment "/if:interfaces/if:interface" {
+        ext:augment-identifier "if-stacked-vlan";
+        when "if:type = 'stacked_vlan'";
+        leaf stacked_vlan-id {
+            type uint16 {
+                range "1..4094";
+            }
+            must "../base-interface" {
+                description
+                "If a vlan-id is defined, a base-interface must
+                be specified.";
+            }
+        }
+    }
+
+    augment "/if:interfaces/if:interface" {
+        ext:augment-identifier "if-l3tunnel";
+        when "if:type = 'ianaift:l3tunnel'";
+
+        leaf tunnel-type {
             type identityref {
                 base tunnel-type-base;
             }
         }
-               leaf local-ip {
-                       type inet:ip-address;
-                       description "Local Endpoint IP address";
-               }
-               
-               leaf remote-ip {
-                       type inet:ip-address;
-                       description "Remote Endpoint IP address";
-               }
-               
-               leaf gateway-ip {
-                       type inet:ip-address;
-                       description "gateway IP address";
-               }
-                               
-       }
-
-               
-       /* MPLS logical port */
-       augment "/if:interfaces/if:interface" {
-               when "if:type = 'mpls'";
-               leaf-list labelStack {
-                       type uint32 {
-                               range "15..1048575";
-                       }
-               }
-               leaf numLabels{
-                       type uint8 {
-                               range "1..7";
-                       }
-               }               
-       }
+        leaf local-ip {
+            type inet:ip-address;
+            description "Local Endpoint IP address";
+        }
+
+        leaf remote-ip {
+            type inet:ip-address;
+            description "Remote Endpoint IP address";
+        }
+
+        leaf gateway-ip {
+            type inet:ip-address;
+            description "gateway IP address";
+        }
+
+    }
+
+
+    /* MPLS logical port */
+    augment "/if:interfaces/if:interface" {
+        ext:augment-identifier "if-mpls";
+        when "if:type = 'mpls'";
+        leaf-list labelStack {
+            type uint32 {
+                range "15..1048575";
+            }
+        }
+        leaf numLabels{
+            type uint8 {
+                range "1..7";
+            }
+        }
+    }
 
 }
 
index 52ad8bfb221f3f0e90e994a7638916a96c3bdb2a..9c90c127004febacac5294c370534dc30a3034cb 100644 (file)
@@ -21,6 +21,24 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <version>0.0.1-SNAPSHOT</version>
   <packaging>bundle</packaging>
   <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>interfacemgr-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-interfaces</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.vpnservice</groupId>
+      <artifactId>vpnmanager-impl</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
     <!-- Testing Dependencies -->
     <dependency>
       <groupId>junit</groupId>
diff --git a/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfaceManager.java b/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfaceManager.java
new file mode 100644 (file)
index 0000000..b8920ba
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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.vpnservice.interfacemgr;
+
+import com.google.common.util.concurrent.FutureCallback;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.BaseIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.vpnservice.AbstractDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
+
+public class InterfaceManager extends AbstractDataChangeListener<Interface> implements AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(InterfaceManager.class);
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker broker;
+
+    private static final FutureCallback<Void> DEFAULT_CALLBACK =
+                    new FutureCallback<Void>() {
+                        public void onSuccess(Void result) {
+                            LOG.debug("Success in Datastore write operation");
+                        }
+
+                        public void onFailure(Throwable error) {
+                            LOG.error("Error in Datastore write operation", error);
+                        };
+                    };
+
+    public InterfaceManager(final DataBroker db) {
+        super(Interface.class);
+        broker = db;
+        registerListener(db);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("Interface Manager Closed");
+    }
+    
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    getWildCardPath(), InterfaceManager.this, DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("InterfaceManager DataChange listener registration fail!", e);
+            throw new IllegalStateException("InterfaceManager registration Listener failed.", e);
+        }
+    }
+
+    @Override
+    protected void add(final InstanceIdentifier<Interface> identifier,
+            final Interface imgrInterface) {
+        LOG.trace("key: " + identifier + ", value=" + imgrInterface );
+        addInterface(identifier, imgrInterface);
+    }
+
+    private InstanceIdentifier<Interface> buildId(final InstanceIdentifier<Interface> identifier) {
+        //TODO Make this generic and move to AbstractDataChangeListener or Utils.
+        final InterfaceKey key = identifier.firstKeyOf(Interface.class, InterfaceKey.class);
+        String interfaceName = key.getName();
+        InstanceIdentifierBuilder<Interface> idBuilder = 
+                InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
+        InstanceIdentifier<Interface> id = idBuilder.build();
+        return id;
+    }
+
+    private void addInterface(final InstanceIdentifier<Interface> identifier,
+                              final Interface imgrInterface) {
+        InstanceIdentifier<Interface> id = buildId(identifier);
+        Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
+        if(port.isPresent()) {
+            Interface interf = port.get();
+            NodeConnector nodeConn = getNodeConnectorFromInterface(interf);
+            updateInterfaceState(identifier, imgrInterface, interf);
+            /* TODO:
+             *  1. Get interface-id from id manager
+             *  2. Update interface-state with following:
+             *    admin-status = set to enable value
+             *    oper-status = Down [?]
+             *    if-index = interface-id
+             *    
+             * FIXME:
+             *  1. Get operational data from node-connector-id?
+             *
+             */
+        }
+    }
+
+    private void updateInterfaceState(InstanceIdentifier<Interface> identifier, Interface imgrInterface,
+                    Interface interf) {
+        // TODO Update InterfaceState
+        
+    }
+
+    private NodeConnector getNodeConnectorFromInterface(Interface interf) {
+        NodeConnectorId ncId = interf.getAugmentation(BaseIds.class).getOfPortId();
+        NodeId nodeId = new NodeId(ncId.getValue().substring(0,ncId.getValue().lastIndexOf(":")));
+        InstanceIdentifier<NodeConnector> ncIdentifier = InstanceIdentifier.builder(Nodes.class)
+                        .child(Node.class, new NodeKey(nodeId))
+                        .child(NodeConnector.class, new NodeConnectorKey(ncId)).build();
+
+        Optional<NodeConnector> nc = read(LogicalDatastoreType.OPERATIONAL, ncIdentifier);
+        if(nc.isPresent()) {
+            NodeConnector nodeConn = nc.get();
+            LOG.trace("nodeConnector: {}",nodeConn);
+            return nodeConn;
+        }
+        return null;
+    }
+
+    private void delInterface(final InstanceIdentifier<Interface> identifier,
+                              final Interface del) {
+        InstanceIdentifier<Interface> id = buildId(identifier);
+        Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
+        if(port.isPresent()) {
+            Interface interf = port.get();
+            // TODO: Update operational data
+        }
+    }
+
+    private void updateInterface(final InstanceIdentifier<Interface> identifier,
+                              final Interface original, final Interface udpate) {
+        InstanceIdentifier<Interface> id = buildId(identifier);
+        Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
+        if(port.isPresent()) {
+            Interface interf = port.get();
+            //TODO: Update operational data
+        }
+    }
+
+    private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
+            InstanceIdentifier<T> path) {
+
+        ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+
+        Optional<T> result = Optional.absent();
+        try {
+            result = tx.read(datastoreType, path).get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return result;
+    }
+
+    private InstanceIdentifier<Interface> getWildCardPath() {
+        return InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
+        LOG.trace("key: " + identifier + ", value=" + del );
+        delInterface(identifier, del);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
+        LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
+        updateInterface(identifier, original, update);
+        
+    }
+
+}
index a3d4e7324c880df0d2cd9af45303f30cb6eac75e..ad2a315de2cff89ae832d2ede3294f6c3955f176 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.vpnservice.interfacemgr;
 
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.slf4j.Logger;
@@ -15,15 +16,24 @@ import org.slf4j.LoggerFactory;
 public class InterfacemgrProvider implements BindingAwareProvider, AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(InterfacemgrProvider.class);
+    
+    private InterfaceManager interfaceManager;
 
     @Override
     public void onSessionInitiated(ProviderContext session) {
         LOG.info("InterfacemgrProvider Session Initiated");
+        try {
+            final  DataBroker dataBroker = session.getSALService(DataBroker.class);
+            interfaceManager = new InterfaceManager(dataBroker);
+        } catch (Exception e) {
+            LOG.error("Error initializing services", e);
+        }
     }
 
     @Override
     public void close() throws Exception {
         LOG.info("InterfacemgrProvider Closed");
+        interfaceManager.close();
     }
 
 }