Bug 4988: OF statistics & REST client 46/33646/33
authorKonstantin Blagov <kblagov@cisco.com>
Sun, 20 Dec 2015 20:53:17 +0000 (21:53 +0100)
committerMartin Sunal <msunal@cisco.com>
Thu, 11 Feb 2016 21:27:35 +0000 (22:27 +0100)
Change-Id: I48c8302196f997abf6c6180e36beae5886d7be48
Signed-off-by: Konstantin Blagov <kblagov@cisco.com>
Signed-off-by: Keith Burns (alagalah) <alagalah@gmail.com>
Signed-off-by: Martin Sunal <msunal@cisco.com>
54 files changed:
demos/gbpsfc-env/.gitignore [changed mode: 0644->0755]
demos/gbpsfc-env/cleandemo.sh
demos/gbpsfc-env/demo-asymmetric-chain/rest.py
demos/gbpsfc-env/demo-asymmetric-coexistence/rest.py
demos/gbpsfc-env/demo-gbp1/infrastructure_config.py
demos/gbpsfc-env/demo-gbp1/rest.py
demos/gbpsfc-env/demo-gbp2/get-nsps.py [new file with mode: 0755]
demos/gbpsfc-env/demo-gbp2/infrastructure_config.py [new file with mode: 0755]
demos/gbpsfc-env/demo-gbp2/rest.py [new file with mode: 0755]
demos/gbpsfc-env/demo-symmetric-chain/rest.py
demos/gbpsfc-env/demo-symmetric-coexistence/rest.py
demos/gbpsfc-env/infrastructure_launch.py
demos/gbpsfc-env/install_java.sh [new file with mode: 0755]
demos/gbpsfc-env/sflow/.gitignore [new file with mode: 0755]
demos/gbpsfc-env/sflow/README
demos/gbpsfc-env/sflow/install_sflow-rt.sh [new file with mode: 0755]
demos/gbpsfc-env/sflow/internal_settings.sh [moved from demos/gbpsfc-env/sflow/internal_settings with 80% similarity]
demos/gbpsfc-env/sflow/internal_start.sh [moved from demos/gbpsfc-env/sflow/internal_start with 81% similarity]
demos/gbpsfc-env/sflow/internal_stop.sh [moved from demos/gbpsfc-env/sflow/internal_stop with 58% similarity]
demos/gbpsfc-env/sflow/set_collector_ip.sh [new file with mode: 0755]
demos/gbpsfc-env/sflow/settings.sh [moved from demos/gbpsfc-env/sflow/settings with 65% similarity]
demos/gbpsfc-env/sflow/start
demos/gbpsfc-env/sflow/stop
demos/gbpsfc-env/sflow/stop_sflow-rt.sh [new file with mode: 0755]
features/src/main/features/features.xml
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/statistics/StatisticsManagerImpl.java [changed mode: 0644->0755]
groupbasedpolicy/src/test/java/org/opendaylight/groupbasedpolicy/statistics/StatisticManagerImplTest.java [changed mode: 0644->0755]
renderers/ofoverlay/pom.xml
renderers/ofoverlay/src/main/config/default-config.xml [changed mode: 0644->0755]
renderers/ofoverlay/src/main/java/org/opendaylight/controller/config/yang/config/ofoverlay_provider/impl/OFOverlayProviderModule.java [changed mode: 0644->0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/OFOverlayRenderer.java [changed mode: 0644->0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/PolicyManager.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/endpoint/EndpointManager.java [changed mode: 0644->0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/JsonRestClient.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/JsonRestClientResponse.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/OFStatisticsManager.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ProcessDataTask.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ReadGbpFlowCacheTask.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ResolvedPolicyClassifierListener.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/SFlowRTConnection.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/SflowClientSettingsListener.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCache.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheData.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheDefinition.java [new file with mode: 0755]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheFactory.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheFilter.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheKeys.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/util/FlowCacheCons.java [new file with mode: 0644]
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/util/IidSflowNameUtil.java [new file with mode: 0644]
renderers/ofoverlay/src/main/yang/ofoverlay-provider-impl.yang [changed mode: 0644->0755]
renderers/ofoverlay/src/main/yang/ofoverlay.yang [changed mode: 0644->0755]
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/OFOverlayRendererTest.java [changed mode: 0644->0755]
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/endpoint/EndpointManagerTest.java

old mode 100644 (file)
new mode 100755 (executable)
index 0c9bef2..439d707
@@ -1,6 +1,6 @@
 .vagrant
 *.pyc
-get-nsps.py
-infrastructure_config.py
+/get-nsps.py
+/infrastructure_config.py
 demo.lock
 
index 64b95ec1cd5529c8d44669d40e89fa8d91d27ae7..5e8b5762d5d3d12a8d7ec6be877f6b0d79c34c48 100755 (executable)
@@ -5,10 +5,10 @@ for i in `seq 1 $NUM_NODES`; do
   hostname="gbpsfc"$i
   switchname="sw"$i
   echo $hostname
-  vagrant ssh $hostname -c "sudo ovs-vsctl del-br $switchname; sudo ovs-vsctl del-manager; sudo /vagrant/vmclean.sh"
+  vagrant ssh $hostname -c "sudo ovs-vsctl del-br $switchname; sudo ovs-vsctl del-manager; sudo /vagrant/vmclean.sh; sudo /vagrant/sflow/stop_sflow-rt.sh  >/dev/null 2>&1"
 
 done
+
 ./rest-clean.py
 
 if [ -f "demo.lock" ] ; then
index e2438a1c788c8f51a27d5c8e5f5e3162f74e8f6c..baf88ba840d5b2b59a26637dfb5573fd932532d9 100755 (executable)
@@ -375,8 +375,14 @@ def get_tenant_data():
                           "order": 0,
                           "classifier-ref": [
                             {
-                              "name": "icmp",
-                              "instance-name": "icmp"
+                              "name": "icmp-in",
+                              "instance-name": "icmp",
+                              "direction": "in"
+                            },
+                            {
+                              "name": "icmp-out",
+                              "instance-name": "icmp",
+                              "direction": "out"
                             }
                           ],
                           "action-ref": [
index 722f6b589c9e07d69554510e95e36e1941ed1080..41264d665b54cc4a1149e7027c6548338659b10c 100755 (executable)
@@ -375,8 +375,14 @@ def get_tenant_data():
                           "order": 0,
                           "classifier-ref": [
                             {
-                              "name": "icmp",
-                              "instance-name": "icmp"
+                              "name": "icmp-in",
+                              "instance-name": "icmp",
+                              "direction": "in"
+                            },
+                            {
+                              "name": "icmp-out",
+                              "instance-name": "icmp",
+                              "direction": "out"
                             }
                           ],
                           "action-ref": [
index cc33d253e71af3d87e0ffba4729f18715fd13543..a05ecf610fe56816e99add3e645d04ef3dd917b0 100755 (executable)
@@ -10,7 +10,7 @@ switches = [
              'type': 'gbp',
              'dpid': '3'},
             {'name': 'sw4',
-             'type': 'none',
+             'type': 'sflow',
              'dpid': '4'},
             {'name': 'sw5',
              'type': 'none',
index 35fceb86581f65788556bdad4e62ddaf441bb48e..7c7f4993e9d11c3e64f5d891a24e1e14674d1546 100755 (executable)
@@ -53,7 +53,7 @@ def post(host, port, uri, data, debug=False):
     if debug == True:
         print r.text
     r.raise_for_status()
-    
+
 
 def get_tenant_data():
     return {
@@ -143,8 +143,14 @@ def get_tenant_data():
                       {
                         "classifier-ref": [
                           {
-                            "name": "icmp",
-                            "instance-name": "icmp"
+                            "name": "icmp-in",
+                            "instance-name": "icmp",
+                            "direction": "in"
+                          },
+                          {
+                            "name": "icmp-out",
+                            "instance-name": "icmp",
+                            "direction": "out"
                           }
                         ],
                         "action-ref": [
@@ -239,17 +245,17 @@ def get_tenant_data():
     }
 
 # Main definition - constants
+
 # =======================
 #     MENUS FUNCTIONS
 # =======================
+
 # Main menu
 
 # =======================
 #      MAIN PROGRAM
 # =======================
+
 # Main Program
 
 def get_tenant_uri():
@@ -311,11 +317,11 @@ def get_tunnel_data():
           }
         ]
       },
-             
+
     ]
   }
             }
-    
+
 def get_tunnel_uri():
     return "/restconf/config/opendaylight-inventory:nodes"
 
@@ -323,159 +329,159 @@ def get_endpoint_data():
     return [{
     "input": {
 
-        "endpoint-group": "clients", 
+        "endpoint-group": "clients",
 
         "network-containment" : "subnet-10.0.35.0/24",
 
-        "l2-context": "bridge-domain1", 
-        "mac-address": "00:00:00:00:35:02", 
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:35:02",
 
         "l3-address": [
             {
-                "ip-address": "10.0.35.2", 
+                "ip-address": "10.0.35.2",
                 "l3-context": "l3-context-vrf-red"
             }
-        ], 
-        "port-name": "vethl-h35_2", 
+        ],
+        "port-name": "vethl-h35_2",
         "tenant": "tenant-red"
     }
 },
             {
     "input": {
 
-        "endpoint-group": "clients", 
+        "endpoint-group": "clients",
 
         "network-containment" : "subnet-10.0.35.0/24",
 
-        "l2-context": "bridge-domain1", 
-        "mac-address": "00:00:00:00:35:03", 
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:35:03",
 
         "l3-address": [
             {
-                "ip-address": "10.0.35.3", 
+                "ip-address": "10.0.35.3",
                 "l3-context": "l3-context-vrf-red"
             }
-        ], 
-        "port-name": "vethl-h35_3", 
+        ],
+        "port-name": "vethl-h35_3",
         "tenant": "tenant-red"
     }
 },
             {
     "input": {
 
-        "endpoint-group": "clients", 
+        "endpoint-group": "clients",
 
         "network-containment" : "subnet-10.0.35.0/24",
 
-        "l2-context": "bridge-domain1", 
-        "mac-address": "00:00:00:00:35:04", 
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:35:04",
 
         "l3-address": [
             {
-                "ip-address": "10.0.35.4", 
+                "ip-address": "10.0.35.4",
                 "l3-context": "l3-context-vrf-red"
             }
-        ], 
-        "port-name": "vethl-h35_4", 
+        ],
+        "port-name": "vethl-h35_4",
         "tenant": "tenant-red"
     }
 },
             {
     "input": {
 
-        "endpoint-group": "clients", 
+        "endpoint-group": "clients",
 
         "network-containment" : "subnet-10.0.35.0/24",
 
-        "l2-context": "bridge-domain1", 
-        "mac-address": "00:00:00:00:35:05", 
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:35:05",
 
         "l3-address": [
             {
-                "ip-address": "10.0.35.5", 
+                "ip-address": "10.0.35.5",
                 "l3-context": "l3-context-vrf-red"
             }
-        ], 
-        "port-name": "vethl-h35_5", 
+        ],
+        "port-name": "vethl-h35_5",
         "tenant": "tenant-red"
     }
 },
             {
     "input": {
 
-        "endpoint-group": "webservers", 
+        "endpoint-group": "webservers",
 
         "network-containment" : "subnet-10.0.36.0/24",
 
-        "l2-context": "bridge-domain1", 
-        "mac-address": "00:00:00:00:36:02", 
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:36:02",
 
         "l3-address": [
             {
-                "ip-address": "10.0.36.2", 
+                "ip-address": "10.0.36.2",
                 "l3-context": "l3-context-vrf-red"
             }
-        ], 
-        "port-name": "vethl-h36_2", 
+        ],
+        "port-name": "vethl-h36_2",
         "tenant": "tenant-red"
     }
 },
             {
     "input": {
 
-        "endpoint-group": "webservers", 
+        "endpoint-group": "webservers",
 
         "network-containment" : "subnet-10.0.36.0/24",
 
-        "l2-context": "bridge-domain1", 
-        "mac-address": "00:00:00:00:36:03", 
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:36:03",
 
         "l3-address": [
             {
-                "ip-address": "10.0.36.3", 
+                "ip-address": "10.0.36.3",
                 "l3-context": "l3-context-vrf-red"
             }
-        ], 
-        "port-name": "vethl-h36_3", 
+        ],
+        "port-name": "vethl-h36_3",
         "tenant": "tenant-red"
     }
 },
             {
     "input": {
 
-        "endpoint-group": "webservers", 
+        "endpoint-group": "webservers",
 
         "network-containment" : "subnet-10.0.36.0/24",
 
-        "l2-context": "bridge-domain1", 
-        "mac-address": "00:00:00:00:36:04", 
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:36:04",
 
         "l3-address": [
             {
-                "ip-address": "10.0.36.4", 
+                "ip-address": "10.0.36.4",
                 "l3-context": "l3-context-vrf-red"
             }
-        ], 
-        "port-name": "vethl-h36_4", 
+        ],
+        "port-name": "vethl-h36_4",
         "tenant": "tenant-red"
     }
 },{
     "input": {
 
-        "endpoint-group": "webservers", 
+        "endpoint-group": "webservers",
 
         "network-containment" : "subnet-10.0.36.0/24",
 
-        "l2-context": "bridge-domain1", 
-        "mac-address": "00:00:00:00:36:05", 
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:36:05",
 
         "l3-address": [
             {
-                "ip-address": "10.0.36.5", 
+                "ip-address": "10.0.36.5",
                 "l3-context": "l3-context-vrf-red"
             }
-        ], 
-        "port-name": "vethl-h36_5", 
+        ],
+        "port-name": "vethl-h36_5",
         "tenant": "tenant-red"
     }
 }]
@@ -491,12 +497,12 @@ if __name__ == "__main__":
     controller=os.environ.get('ODL')
     if controller == None:
         sys.exit("No controller set.")
-    
+
 
     print "tenants"
     tenants=get(controller,DEFAULT_PORT,CONF_TENANT)
     print tenants
-    
+
     print "sending tenant"
     put(controller, DEFAULT_PORT, get_tenant_uri(), get_tenant_data(),True)
     print "sending tunnel"
@@ -504,7 +510,7 @@ if __name__ == "__main__":
     print "registering endpoints"
     for endpoint in get_endpoint_data():
         post(controller, DEFAULT_PORT, get_endpoint_uri(),endpoint,True)
-        
-        
-    
-    
+
+
+
+
diff --git a/demos/gbpsfc-env/demo-gbp2/get-nsps.py b/demos/gbpsfc-env/demo-gbp2/get-nsps.py
new file mode 100755 (executable)
index 0000000..c8ac97c
--- /dev/null
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+
+if __name__ == "__main__":
+    # Launch main menu
+
+
+    # Some sensible defaults
+    print "Nothing"
diff --git a/demos/gbpsfc-env/demo-gbp2/infrastructure_config.py b/demos/gbpsfc-env/demo-gbp2/infrastructure_config.py
new file mode 100755 (executable)
index 0000000..09eb1f9
--- /dev/null
@@ -0,0 +1,67 @@
+# Config for switches, tunnelIP is the local IP address.
+switches = [
+            {'name': 'sw1',
+             'type': 'gbp',
+             'dpid': '1'},
+            {'name': 'sw2',
+             'type': 'gbp',
+             'dpid': '2'},
+            {'name': 'sw3',
+             'type': 'sflow',
+             'dpid': '3'},
+            {'name': 'sw4',
+             'type': 'none',
+             'dpid': '4'},
+            {'name': 'sw5',
+             'type': 'none',
+             'dpid': '5'},
+            {'name': 'sw6',
+             'type': 'none',
+             'dpid': '6'},
+            {'name': 'sw7',
+             'type': 'none',
+             'dpid': '7'},
+            {'name': 'sw8',
+             'type': 'none',
+             'dpid': '8'}
+           ]
+
+defaultContainerImage='alagalah/odlpoc_ovs230'
+#defaultContainerImage='ubuntu:14.04'
+
+#Note that tenant name and endpointGroup name come from policy_config.py
+
+hosts = [{'name': 'h35_2',
+          'mac': '00:00:00:00:35:02',
+          'ip': '10.0.35.2/24',
+          'switch': 'sw1'},
+         {'name': 'h35_3',
+          'ip': '10.0.35.3/24',
+          'mac': '00:00:00:00:35:03',
+          'switch': 'sw1'},
+         {'name': 'h35_4',
+          'ip': '10.0.35.4/24',
+          'mac': '00:00:00:00:35:04',
+          'switch': 'sw1'},
+         {'name': 'h35_5',
+          'ip': '10.0.35.5/24',
+          'mac': '00:00:00:00:35:05',
+          'switch': 'sw1'},
+         {'name': 'h36_2',
+          'ip': '10.0.36.2/24',
+          'mac': '00:00:00:00:36:02',
+          'switch': 'sw2'},
+         {'name': 'h36_3',
+          'ip': '10.0.36.3/24',
+          'mac': '00:00:00:00:36:03',
+          'switch': 'sw2'},
+         {'name': 'h36_4',
+          'ip': '10.0.36.4/24',
+          'mac': '00:00:00:00:36:04',
+          'switch': 'sw2'},
+         {'name': 'h36_5',
+          'ip': '10.0.36.5/24',
+          'mac': '00:00:00:00:36:05',
+          'switch': 'sw2'}
+          ]
+
diff --git a/demos/gbpsfc-env/demo-gbp2/rest.py b/demos/gbpsfc-env/demo-gbp2/rest.py
new file mode 100755 (executable)
index 0000000..d08aa82
--- /dev/null
@@ -0,0 +1,528 @@
+#!/usr/bin/python
+import argparse
+import requests,json
+from requests.auth import HTTPBasicAuth
+from subprocess import call
+import time
+import sys
+import os
+
+
+DEFAULT_PORT='8181'
+
+
+USERNAME='admin'
+PASSWORD='admin'
+
+
+OPER_NODES='/restconf/operational/opendaylight-inventory:nodes/'
+CONF_TENANT='/restconf/config/policy:tenants'
+
+def get(host, port, uri):
+    url='http://'+host+":"+port+uri
+    #print url
+    r = requests.get(url, auth=HTTPBasicAuth(USERNAME, PASSWORD))
+    jsondata=json.loads(r.text)
+    return jsondata
+
+def put(host, port, uri, data, debug=False):
+    '''Perform a PUT rest operation, using the URL and data provided'''
+
+    url='http://'+host+":"+port+uri
+
+    headers = {'Content-type': 'application/yang.data+json',
+               'Accept': 'application/yang.data+json'}
+    if debug == True:
+        print "PUT %s" % url
+        print json.dumps(data, indent=4, sort_keys=True)
+    r = requests.put(url, data=json.dumps(data), headers=headers, auth=HTTPBasicAuth(USERNAME, PASSWORD))
+    if debug == True:
+        print r.text
+    r.raise_for_status()
+
+def post(host, port, uri, data, debug=False):
+    '''Perform a POST rest operation, using the URL and data provided'''
+
+    url='http://'+host+":"+port+uri
+    headers = {'Content-type': 'application/yang.data+json',
+               'Accept': 'application/yang.data+json'}
+    if debug == True:
+        print "POST %s" % url
+        print json.dumps(data, indent=4, sort_keys=True)
+    r = requests.post(url, data=json.dumps(data), headers=headers, auth=HTTPBasicAuth(USERNAME, PASSWORD))
+    if debug == True:
+        print r.text
+    r.raise_for_status()
+
+
+def get_tenant_data():
+    return {
+        "policy:tenant": {
+          "id": "tenant-red",
+          "name": "GBPPOC",
+          "forwarding-context": {
+            "l2-bridge-domain": [
+              {
+                "id": "bridge-domain1",
+                "parent": "l3-context-vrf-red"
+              }
+            ],
+            "l2-flood-domain": [
+              {
+                "id": "flood-domain-1",
+                "parent": "bridge-domain1"
+              },
+              {
+                "id": "flood-domain1",
+                "parent": "bridge-domain1"
+              }
+            ],
+            "l3-context": [
+              {
+                "id": "l3-context-vrf-red"
+              }
+            ],
+            "subnet": [
+              {
+                "id": "subnet-10.0.35.0/24",
+                "ip-prefix": "10.0.35.1/24",
+                "parent": "flood-domain-1",
+                "virtual-router-ip": "10.0.35.1"
+              },
+              {
+                "id": "subnet-10.0.36.0/24",
+                "ip-prefix": "10.0.36.1/24",
+                "parent": "flood-domain1",
+                "virtual-router-ip": "10.0.36.1"
+              }
+            ]
+          },
+          "policy": {
+            "contract": [
+              {
+                "clause": [
+                  {
+                    "name": "allow-http-clause",
+                    "subject-refs": [
+                      "allow-http-subject",
+                      "allow-icmp-subject"
+                    ]
+                  }
+                ],
+                "id": "icmp-http-contract",
+                "subject": [
+                  {
+                    "name": "allow-http-subject",
+                    "rule": [
+                      {
+                        "classifier-ref": [
+                          {
+                            "direction": "in",
+                            "name": "http-dest",
+                            "instance-name": "http-dest"
+                          },
+                          {
+                            "direction": "out",
+                            "name": "http-src",
+                            "instance-name": "http-src"
+                          }
+                        ],
+                        "action-ref": [
+                          {
+                            "name": "allow1",
+                            "order": 0
+                          }
+                        ],
+                        "name": "allow-http-rule"
+                      }
+                    ]
+                  },
+                  {
+                    "name": "allow-icmp-subject",
+                    "rule": [
+                      {
+                        "classifier-ref": [
+                          {
+                            "name": "icmp-in",
+                            "instance-name": "icmp",
+                            "direction": "in"
+                          },
+                          {
+                            "name": "icmp-out",
+                            "instance-name": "icmp",
+                            "direction": "out"
+                          }
+                        ],
+                        "action-ref": [
+                          {
+                            "name": "allow1",
+                            "order": 0
+                          }
+                        ],
+                        "name": "allow-icmp-rule"
+                      }
+                    ]
+                  }
+                ]
+              }
+            ],
+            "endpoint-group": [
+              {
+                "consumer-named-selector": [
+                  {
+                    "contract": [
+                      "icmp-http-contract"
+                    ],
+                    "name": "webservers-clients-icmp-http-contract"
+                  }
+                ],
+                "id": "clients",
+                "provider-named-selector": []
+              },
+              {
+                "consumer-named-selector": [],
+                "id": "webservers1",
+                "provider-named-selector": [
+                  {
+                    "contract": [
+                      "icmp-http-contract"
+                    ],
+                    "name": "webservers-clients-icmp-http-contract"
+                  }
+                ]
+              },
+              {
+                "consumer-named-selector": [],
+                "id": "webservers2",
+                "provider-named-selector": [
+                  {
+                    "contract": [
+                      "icmp-http-contract"
+                    ],
+                    "name": "webservers-clients-icmp-http-contract"
+                  }
+                ]
+              }
+            ],
+            "subject-feature-instances": {
+              "classifier-instance": [
+                {
+                  "classifier-definition-id": "Classifier-L4",
+                  "name": "http-dest",
+                  "parameter-value": [
+                    {
+                      "int-value": "6",
+                      "name": "proto"
+                    },
+                    {
+                      "int-value": "80",
+                      "name": "destport"
+                    }
+                  ]
+                },
+                {
+                  "classifier-definition-id": "Classifier-L4",
+                  "name": "http-src",
+                  "parameter-value": [
+                    {
+                      "int-value": "6",
+                      "name": "proto"
+                    },
+                    {
+                      "int-value": "80",
+                      "name": "sourceport"
+                    }
+                  ]
+                },
+                {
+                  "classifier-definition-id": "Classifier-IP-Protocol",
+                  "name": "icmp",
+                  "parameter-value": [
+                    {
+                      "int-value": "1",
+                      "name": "proto"
+                    }
+                  ]
+                }
+              ],
+              "action-instance": [
+                {
+                  "name": "allow1",
+                  "action-definition-id": "Action-Allow"
+                }
+              ]
+            }
+          }
+        }
+    }
+
+# Main definition - constants
+
+# =======================
+#     MENUS FUNCTIONS
+# =======================
+
+# Main menu
+
+# =======================
+#      MAIN PROGRAM
+# =======================
+
+# Main Program
+
+def get_tenant_uri():
+    return "/restconf/config/policy:tenants/policy:tenant/tenant-red"
+
+
+def get_tunnel_data():
+    return {
+  "opendaylight-inventory:nodes": {
+    "node": [
+      {
+        "id": "openflow:1",
+        "ofoverlay:tunnel": [
+          {
+            "tunnel-type": "overlay:tunnel-type-vxlan-gpe",
+            "node-connector-id": "openflow:1:1",
+            "ip": "192.168.50.70",
+            "port": 6633
+          },
+          {
+            "tunnel-type": "overlay:tunnel-type-vxlan",
+            "node-connector-id": "openflow:1:2",
+            "ip": "192.168.50.70",
+            "port": 4789
+          }
+        ]
+      },
+      {
+        "id": "openflow:2",
+        "ofoverlay:tunnel": [
+          {
+            "tunnel-type": "overlay:tunnel-type-vxlan-gpe",
+            "node-connector-id": "openflow:2:1",
+            "ip": "192.168.50.71",
+            "port": 6633
+          },
+          {
+            "tunnel-type": "overlay:tunnel-type-vxlan",
+            "node-connector-id": "openflow:2:2",
+            "ip": "192.168.50.71",
+            "port": 4789
+          }
+        ]
+      },
+                   {
+        "id": "openflow:3",
+        "ofoverlay:tunnel": [
+          {
+            "tunnel-type": "overlay:tunnel-type-vxlan-gpe",
+            "node-connector-id": "openflow:3:1",
+            "ip": "192.168.50.72",
+            "port": 6633
+          },
+          {
+            "tunnel-type": "overlay:tunnel-type-vxlan",
+            "node-connector-id": "openflow:3:2",
+            "ip": "192.168.50.72",
+            "port": 4789
+          }
+        ]
+      },
+
+    ]
+  }
+            }
+
+def get_tunnel_uri():
+    return "/restconf/config/opendaylight-inventory:nodes"
+
+def get_endpoint_data():
+    return [{
+    "input": {
+
+        "endpoint-group": "clients",
+
+        "network-containment" : "subnet-10.0.35.0/24",
+
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:35:02",
+
+        "l3-address": [
+            {
+                "ip-address": "10.0.35.2",
+                "l3-context": "l3-context-vrf-red"
+            }
+        ],
+        "port-name": "vethl-h35_2",
+        "tenant": "tenant-red"
+    }
+},
+            {
+    "input": {
+
+        "endpoint-group": "clients",
+
+        "network-containment" : "subnet-10.0.35.0/24",
+
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:35:03",
+
+        "l3-address": [
+            {
+                "ip-address": "10.0.35.3",
+                "l3-context": "l3-context-vrf-red"
+            }
+        ],
+        "port-name": "vethl-h35_3",
+        "tenant": "tenant-red"
+    }
+},
+            {
+    "input": {
+
+        "endpoint-group": "clients",
+
+        "network-containment" : "subnet-10.0.35.0/24",
+
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:35:04",
+
+        "l3-address": [
+            {
+                "ip-address": "10.0.35.4",
+                "l3-context": "l3-context-vrf-red"
+            }
+        ],
+        "port-name": "vethl-h35_4",
+        "tenant": "tenant-red"
+    }
+},
+            {
+    "input": {
+
+        "endpoint-group": "clients",
+
+        "network-containment" : "subnet-10.0.35.0/24",
+
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:35:05",
+
+        "l3-address": [
+            {
+                "ip-address": "10.0.35.5",
+                "l3-context": "l3-context-vrf-red"
+            }
+        ],
+        "port-name": "vethl-h35_5",
+        "tenant": "tenant-red"
+    }
+},
+            {
+    "input": {
+
+        "endpoint-group": "webservers1",
+
+        "network-containment" : "subnet-10.0.36.0/24",
+
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:36:02",
+
+        "l3-address": [
+            {
+                "ip-address": "10.0.36.2",
+                "l3-context": "l3-context-vrf-red"
+            }
+        ],
+        "port-name": "vethl-h36_2",
+        "tenant": "tenant-red"
+    }
+},
+            {
+    "input": {
+
+        "endpoint-group": "webservers2",
+
+        "network-containment" : "subnet-10.0.36.0/24",
+
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:36:03",
+
+        "l3-address": [
+            {
+                "ip-address": "10.0.36.3",
+                "l3-context": "l3-context-vrf-red"
+            }
+        ],
+        "port-name": "vethl-h36_3",
+        "tenant": "tenant-red"
+    }
+},
+            {
+    "input": {
+
+        "endpoint-group": "webservers1",
+
+        "network-containment" : "subnet-10.0.36.0/24",
+
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:36:04",
+
+        "l3-address": [
+            {
+                "ip-address": "10.0.36.4",
+                "l3-context": "l3-context-vrf-red"
+            }
+        ],
+        "port-name": "vethl-h36_4",
+        "tenant": "tenant-red"
+    }
+},{
+    "input": {
+
+        "endpoint-group": "webservers2",
+
+        "network-containment" : "subnet-10.0.36.0/24",
+
+        "l2-context": "bridge-domain1",
+        "mac-address": "00:00:00:00:36:05",
+
+        "l3-address": [
+            {
+                "ip-address": "10.0.36.5",
+                "l3-context": "l3-context-vrf-red"
+            }
+        ],
+        "port-name": "vethl-h36_5",
+        "tenant": "tenant-red"
+    }
+}]
+
+def get_endpoint_uri():
+    return "/restconf/operations/endpoint:register-endpoint"
+
+if __name__ == "__main__":
+    # Launch main menu
+
+
+    # Some sensible defaults
+    controller=os.environ.get('ODL')
+    if controller == None:
+        sys.exit("No controller set.")
+
+
+    print "tenants"
+    tenants=get(controller,DEFAULT_PORT,CONF_TENANT)
+    print tenants
+
+    print "sending tenant"
+    put(controller, DEFAULT_PORT, get_tenant_uri(), get_tenant_data(),True)
+    print "sending tunnel"
+    put(controller, DEFAULT_PORT, get_tunnel_uri(), get_tunnel_data(), True)
+    print "registering endpoints"
+    for endpoint in get_endpoint_data():
+        post(controller, DEFAULT_PORT, get_endpoint_uri(),endpoint,True)
+
+
+
+
index edc74553800c99dcffe1aaa4bb7ef201febaa7b8..c22c322d44cc19ff91796dfd1e1a30d63fa65c18 100755 (executable)
@@ -377,8 +377,14 @@ def get_tenant_data():
                           "order": 0,
                           "classifier-ref": [
                             {
-                              "name": "icmp",
-                              "instance-name": "icmp"
+                              "name": "icmp-in",
+                              "instance-name": "icmp",
+                              "direction": "in"
+                            },
+                            {
+                              "name": "icmp-out",
+                              "instance-name": "icmp",
+                              "direction": "out"
                             }
                           ],
                           "action-ref": [
index c8caa10096e8e4bb7ddcd5dd2a5dfef623acf07a..2884d76a0e900d9a52638f44215347220c9c3e99 100755 (executable)
@@ -375,8 +375,14 @@ def get_tenant_data():
                           "order": 0,
                           "classifier-ref": [
                             {
-                              "name": "icmp",
-                              "instance-name": "icmp"
+                              "name": "icmp-in",
+                              "instance-name": "icmp",
+                              "direction": "in"
+                            },
+                            {
+                              "name": "icmp-out",
+                              "instance-name": "icmp",
+                              "direction": "out"
                             }
                           ],
                           "action-ref": [
index 713aaef6c58334c614510cebc281aa7b966270d2..5653063c93bfe0f2623afb4a610eb65bcccef117 100755 (executable)
@@ -147,4 +147,15 @@ if __name__ == "__main__" :
            print "*****************************"
            doCmd('sudo /vagrant/sf-config.sh')
            #addGpeTunnel(switches[sw_index]['name'])
+       elif sw_type == 'sflow':
+           print "*****************************"
+           print "Configuring %s as an sFlow-RT collector." % sw_name
+           print "*****************************"
+           doCmd('sudo /vagrant/install_java.sh')
+           doCmd('sudo /vagrant/sflow/install_sflow-rt.sh')
+           call('sudo /home/vagrant/sflow-rt/gbp_start.sh &'.split())
+           doCmd('sudo /vagrant/sflow/set_collector_ip.sh')
+           doCmd('sudo /vagrant/sflow/curl_put_collector.sh')
+           print "Configuring finished."
+
 
diff --git a/demos/gbpsfc-env/install_java.sh b/demos/gbpsfc-env/install_java.sh
new file mode 100755 (executable)
index 0000000..6420b2d
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+if ! java -version 2>/dev/null; then
+  sudo apt-get update
+  sudo apt-get install openjdk-7-jre-headless -y
+fi
diff --git a/demos/gbpsfc-env/sflow/.gitignore b/demos/gbpsfc-env/sflow/.gitignore
new file mode 100755 (executable)
index 0000000..3604b91
--- /dev/null
@@ -0,0 +1 @@
+/curl_put_collector.sh
index 6a15973cd94580cb2c95b392c39072b388b937f7..552ce6fbe46e93847919d3ec9ae12f33a2bcaebf 100755 (executable)
@@ -4,11 +4,11 @@ contains a list of numbers to append to "gbpsfc" to get the VMs' names
 start [<name>]
 stop [<name>]
 list [<name>]
-No parameters: machines' names are generated from settings file.
-One parameter: operation will take place on than machine only
+No parameters: machines' names are generated from settings.sh file (SFLOW_LIST should contain numbers used for vagrant's names of VMs).
+One parameter: operation will take place on than machine only (ex., `start gbpsfc2')
 
 start
-Start sending sFlow data from OVS (all parameters are set in internal_settings)
+Start sending sFlow data from OVS (all parameters are set in internal_settings.sh)
 
 stop
 Stop sending sFlow data
@@ -16,10 +16,10 @@ Stop sending sFlow data
 list
 Show actual state of sFlow, or will not show anything if sFlow is stopped.
 
-internal_settings
+internal_settings.sh
 Settings used to start sFlow sending on a machine
 
-internal_start, internal_stop
+internal_start.sh, internal_stop.sh
 Not to be run manually. Starting/stopping sFlow sending on individual machine
 
 
diff --git a/demos/gbpsfc-env/sflow/install_sflow-rt.sh b/demos/gbpsfc-env/sflow/install_sflow-rt.sh
new file mode 100755 (executable)
index 0000000..6e1e614
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+if [ ! -d /home/vagrant/sflow-rt ]; then
+  echo "/home/vagrant/sflow-rt not found; installing sFlow-RT..."
+  wget http://www.inmon.com/products/sFlow-RT/sflow-rt.tar.gz
+  tar -xvzf sflow-rt.tar.gz
+  sudo chown -R vagrant:vagrant /home/vagrant/sflow-rt
+fi
+
+if [ ! -f /home/vagrant/sflow-rt/gbp_start.sh ]; then
+  sed '/exec java/c sudo nohup java ${JVM_OPTS} ${RT_OPTS} ${SCRIPTS} -jar ${JAR} 1>rt.out 2>&1 &' ~/sflow-rt/start.sh >/home/vagrant/sflow-rt/gbp_start.sh
+  sudo chmod +x /home/vagrant/sflow-rt/gbp_start.sh
+fi
similarity index 80%
rename from demos/gbpsfc-env/sflow/internal_settings
rename to demos/gbpsfc-env/sflow/internal_settings.sh
index 5398af747d69a08efa96d31096374308fe2045cd..030d218ac38b8c56b15eac44062ddb921e5baaa6 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-export COLLECTOR_IP=192.168.53.2
+export COLLECTOR_IP=192.168.53.73
 export COLLECTOR_PORT=6343
 export AGENT_IP=eth2
 export HEADER_BYTES=128
similarity index 81%
rename from demos/gbpsfc-env/sflow/internal_start
rename to demos/gbpsfc-env/sflow/internal_start.sh
index 0e3218c131c73419fe06acd214a947f785779355..46797cd280e17f8136df5c563ebc6e7291313de0 100755 (executable)
@@ -1,12 +1,12 @@
 #!/usr/bin/env bash
 
-. /vagrant/sflow/internal_settings
+. /vagrant/sflow/internal_settings.sh
 hostnum=${HOSTNAME#"gbpsfc"}
 sw="sw$hostnum"
 
 if [ -f ~/sflow_uuid ]; then
   echo "sflow_uuid already present; cleaning..."
-  sudo ovs-vsctl remove bridge $sw sflow `cat ~/sflow_uuid` 
+  sudo ovs-vsctl remove bridge $sw sflow `cat ~/sflow_uuid`
   rm ~/sflow_uuid
 fi
 
similarity index 58%
rename from demos/gbpsfc-env/sflow/internal_stop
rename to demos/gbpsfc-env/sflow/internal_stop.sh
index 005be483abbe83edf41f308fde6103b22774fc09..b21192b6417b07a6611536667d6af1b666d8420c 100755 (executable)
@@ -1,12 +1,12 @@
 #!/usr/bin/env bash
 
 if [ ! -f ~/sflow_uuid ]; then
-  echo "No sflow_uuid found!"
+  echo "No sflow_uuid found."
   exit 1
 fi
 
 hostnum=${HOSTNAME#"gbpsfc"}
 sw="sw$hostnum"
 
-sudo ovs-vsctl remove bridge $sw sflow `cat ~/sflow_uuid` 
+sudo ovs-vsctl remove bridge $sw sflow `cat ~/sflow_uuid`
 rm ~/sflow_uuid
diff --git a/demos/gbpsfc-env/sflow/set_collector_ip.sh b/demos/gbpsfc-env/sflow/set_collector_ip.sh
new file mode 100755 (executable)
index 0000000..092c631
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+source /vagrant/env.sh
+source /vagrant/sflow/settings.sh
+export THIS_IP=$(ifconfig | grep -A 1 'eth2' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)
+
+echo "#!/usr/bin/env bash" >/vagrant/sflow/curl_put_collector.sh
+echo "curl -H \"Content-Type:application/yang.data+json\" -X PUT --data \"{'ofoverlay:of-overlay-config': {'sflow-client-settings': {'gbp-ofoverlay-sflow-retrieve-interval': $SFLOW_INTERVAL, 'gbp-ofoverlay-sflow-collector-uri': 'http://$THIS_IP:8008'}}}\" http://admin:admin@$ODL:8181/restconf/config/ofoverlay:of-overlay-config" >>/vagrant/sflow/curl_put_collector.sh
+
+sed -i "/export COLLECTOR_IP=/c export COLLECTOR_IP=$THIS_IP" /vagrant/sflow/internal_settings.sh
similarity index 65%
rename from demos/gbpsfc-env/sflow/settings
rename to demos/gbpsfc-env/sflow/settings.sh
index 27e2f4d0712bb463a559d1e8fa0560617db94f88..02d3f961cb189bb54282643cc6d05a0adf93f615 100755 (executable)
@@ -1,4 +1,5 @@
 #!/usr/bin/env bash
 
 export SFLOW_LIST="1 2 3"
+export SFLOW_INTERVAL=30
 
index b78316da576b4594ad02b71e83cc482a675c6228..3c5cab633a6ae762441709ab2efb9efddbf4c138 100755 (executable)
@@ -1,13 +1,13 @@
 #!/usr/bin/env bash
 
 if [ $1 ]; then
-  vagrant ssh $1 -c "bash -E /vagrant/sflow/internal_start"
+  vagrant ssh $1 -c "bash -E /vagrant/sflow/internal_start.sh"
 else
-  . sflow/settings
+  . sflow/settings.sh
   for i in $SFLOW_LIST
   do
     echo; echo "gbpsfc$i"
-    vagrant ssh gbpsfc$i -c "bash -E /vagrant/sflow/internal_start"
+    vagrant ssh gbpsfc$i -c "bash -E /vagrant/sflow/internal_start.sh"
   done
 fi
 
index b0514aea632f1ce5b7bd7a0e78c4789b90a219e5..f66330e6e834173d88dd47e1d69220ddfef7e13b 100755 (executable)
@@ -1,12 +1,12 @@
 #!/usr/bin/env bash
 
 if [ $1 ]; then
-  vagrant ssh $1 -c "bash -E /vagrant/sflow/internal_stop"
+  vagrant ssh $1 -c "bash -E /vagrant/sflow/internal_stop.sh"
 else
-  . sflow/settings
+  . sflow/settings.sh
   for i in $SFLOW_LIST
   do
     echo; echo "gbpsfc$i"
-    vagrant ssh gbpsfc$i -c "bash -E /vagrant/sflow/internal_stop"
+    vagrant ssh gbpsfc$i -c "bash -E /vagrant/sflow/internal_stop.sh"
   done
 fi
diff --git a/demos/gbpsfc-env/sflow/stop_sflow-rt.sh b/demos/gbpsfc-env/sflow/stop_sflow-rt.sh
new file mode 100755 (executable)
index 0000000..238ec3b
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+sudo kill $(ps -fe | grep port=6343 | grep -v grep | awk 'NR==1 {print $2}')
+sudo rm /home/vagrant/sflow-rt/rt.out.old
+sudo mv /home/vagrant/sflow-rt/rt.out /home/vagrant/sflow-rt/rt.out.old
index 5f0bc9ad8ab66329a9b5b33738effe64b962e590..bcd48f8dbfbf74630f6748553c9f398173781584 100755 (executable)
@@ -56,6 +56,9 @@
         <feature version='${sfc.version}'>odl-sfc-ui</feature>
         <bundle>mvn:commons-net/commons-net/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.groupbasedpolicy/ofoverlay-renderer/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-core/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-client/{{VERSION}}</bundle>
+        <bundle>mvn:com.google.code.gson/gson/{{VERSION}}</bundle>
         <configfile finalname="${config.configfile.directory}/15-groupbasedpolicy-ofoverlay.xml">mvn:org.opendaylight.groupbasedpolicy/ofoverlay-renderer/{{VERSION}}/xml/config</configfile>
     </feature>
 
index 255e90a5e002f948c0169ad51aad11f9fb62e544..370f82bc7d52ce81a199c7fc8de425ecae6264ff 100755 (executable)
@@ -38,11 +38,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Policy;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.SubjectFeatureInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.ResolvedPolicies;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.ResolvedPoliciesBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -316,6 +318,21 @@ public class PolicyResolver implements PolicyValidatorRegistry, AutoCloseable {
             synchronized (subscribersPerTenant) {
                 if (subscribersPerTenant.contains(tenantAfter.getId())) {
                     updateTenant(tenantAfter.getId(), tenantAfter);
+                    tenantAfter.getPolicy().getContract().get(0).getId();
+                    tenantAfter.getPolicy().getContract().get(0).getSubject().get(0).getName();
+                    tenantAfter.getPolicy().getContract().get(0).getSubject().get(0).getRule().get(0).getName();
+                    List<ClassifierRef> cref = tenantAfter.getPolicy()
+                            .getContract()
+                            .get(0)
+                            .getSubject()
+                            .get(0)
+                            .getRule()
+                            .get(0)
+                            .getClassifierRef();
+                    cref.get(0).getInstanceName();
+                    tenantAfter.getPolicy().getSubjectFeatureInstances().getClassifierInstance().get(0).getName();
+                    tenantAfter.getPolicy().getSubjectFeatureInstances().getClassifierInstance().get(0).getParameterValue()
+                            .get(0);
                 }
             }
         }
old mode 100644 (file)
new mode 100755 (executable)
index 0ac0899..eebbfe5
@@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.api.StatisticsManager;
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
@@ -72,15 +73,16 @@ public class StatisticsManagerImpl implements StatisticsManager, AutoCloseable {
 
     @Override
     public boolean writeStat(StatRecords record) {
+        WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
         for (EpToEpStatistic epStats : record.getEpToEpStatistic()) {
             SrcEndpointBuilder srcBuilder = new SrcEndpointBuilder();
             DstEndpointBuilder dstBuilder = new DstEndpointBuilder();
             srcBuilder.setMacAddress(epStats.getSrcMacAddress())
-                .setL2Context(epStats.getSrcL2c())
-                .setTenant(epStats.getSrcTenant());
+                    .setL2Context(epStats.getSrcL2c())
+                    .setTenant(epStats.getSrcTenant());
             dstBuilder.setMacAddress(epStats.getDstMacAddress())
-                .setL2Context(epStats.getDstL2c())
-                .setTenant(epStats.getDstTenant());
+                    .setL2Context(epStats.getDstL2c())
+                    .setTenant(epStats.getDstTenant());
             for (EpEpgToEpEpgStatistic epgStats : epStats.getEpEpgToEpEpgStatistic()) {
                 StatisticRecordKey key = new StatisticRecordKey(new RecordId(recordKey++));
                 StatisticRecord statRecord;
@@ -89,35 +91,33 @@ public class StatisticsManagerImpl implements StatisticsManager, AutoCloseable {
                 List<Statistic> statisticList = new ArrayList<>();
                 for (MatchedRuleStatistic ruleStats : epgStats.getMatchedRuleStatistic()) {
                     Statistic statistic = new StatisticBuilder()
-                        .setKey(new StatisticKey(ruleStats.getContract(), ruleStats.getMatchedRule(),
-                                ruleStats.getSubject()))
-                        .setContract(ruleStats.getContract())
-                        .setSubject(ruleStats.getSubject())
-                        .setRule(ruleStats.getMatchedRule())
-                        .setAction(ruleStats.getAction())
-                        .setClassifier(ruleStats.getClassifier())
-                        .setByteCount(ruleStats.getByteCount())
-                        .setPacketCount(ruleStats.getPacketCount())
-                        .build();
+                            .setKey(new StatisticKey(ruleStats.getContract(),
+                                    ruleStats.getMatchedRule(), ruleStats.getSubject()))
+                            .setContract(ruleStats.getContract())
+                            .setSubject(ruleStats.getSubject())
+                            .setRule(ruleStats.getMatchedRule())
+                            .setAction(ruleStats.getAction())
+                            .setClassifier(ruleStats.getClassifier())
+                            .setByteCount(ruleStats.getByteCount())
+                            .setPacketCount(ruleStats.getPacketCount())
+                            .build();
                     statisticList.add(statistic);
 
                 }
                 statRecord = new StatisticRecordBuilder().setKey(key)
-                    .setRecordId(new RecordId(recordKey))
-                    .setTimestamp(epStats.getTimestamp())
-                    .setSrcEndpoint(srcBuilder.build())
-                    .setDstEndpoint(dstBuilder.build())
-                    .setStatistic(statisticList)
-                    .build();
+                        .setRecordId(new RecordId(recordKey))
+                        .setTimestamp(epStats.getTimestamp())
+                        .setSrcEndpoint(srcBuilder.build())
+                        .setDstEndpoint(dstBuilder.build())
+                        .setStatistic(statisticList)
+                        .build();
 
                 InstanceIdentifier<StatisticRecord> statIID = IidFactory.statisticRecordIid(key);
-                WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
-                LOG.debug("Writing statistics to datastore");
-                wtx.put(LogicalDatastoreType.OPERATIONAL, statIID, statRecord);
-                wtx.submit();
+                LOG.debug("Writing statistics to datastore: {}", statRecord);
+                wtx.put(LogicalDatastoreType.OPERATIONAL, statIID, statRecord, true);
             }
         }
-        return true;
+        return DataStoreHelper.submitToDs(wtx);
     }
 
     @Override
old mode 100644 (file)
new mode 100755 (executable)
index 1330fc0..4d2f694
@@ -20,6 +20,7 @@ import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
@@ -132,10 +133,18 @@ public class StatisticManagerImplTest {
             .setSrcEndpoint(srcBuilder.build())
             .setDstEndpoint(dstBuilder.build());
 
+//        manager.writeStat(recordsBuilder.build());
+//        Mockito.verify(wtx).put(LogicalDatastoreType.OPERATIONAL,
+//                IidFactory.statisticRecordIid(key),
+//                statRecord.build());
+        CheckedFuture<Void,TransactionCommitFailedException> future = Mockito.mock(CheckedFuture.class);
+        Mockito.when(wtx.submit()).thenReturn(future);
+        Mockito.when(dataBroker.newWriteOnlyTransaction()).thenReturn(wtx);
+
         manager.writeStat(recordsBuilder.build());
         Mockito.verify(wtx).put(LogicalDatastoreType.OPERATIONAL,
                 IidFactory.statisticRecordIid(key),
-                statRecord.build());
+                statRecord.build(), true);
     }
 
     @Test
index 0ddabf385adc243cf71fd25a78ef466118517f95..5fa95470a565aee4ba00ca143f5b2c89ebe20a5f 100755 (executable)
       <groupId>commons-net</groupId>
       <artifactId>commons-net</artifactId>
     </dependency>
+    <!-- REST client-->
+    <dependency>
+       <groupId>com.sun.jersey</groupId>
+       <artifactId>jersey-client</artifactId>
+    </dependency>
+    <dependency>
+       <groupId>com.google.code.gson</groupId>
+       <artifactId>gson</artifactId>
+    </dependency>
     <!-- SFC -->
     <dependency>
       <groupId>org.opendaylight.sfc</groupId>
old mode 100644 (file)
new mode 100755 (executable)
index a572908..8388627
                         <name>policy-validator-registry</name>
                     </policy-validator-registry>
 
+                    <statistics-manager>
+                        <type xmlns:gbp="urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy">gbp:statistics-manager</type>
+                        <name>statistics-manager</name>
+                    </statistics-manager>
+
                     <gbp-ofoverlay-table-offset>0</gbp-ofoverlay-table-offset>
+
+                    <!--<gbp-ofoverlay-sflow-start>false</gbp-ofoverlay-sflow-start>-->
+                    <!--<gbp-ofoverlay-sflow-collector-uri>http://192.168.53.2:8008</gbp-ofoverlay-sflow-collector-uri>-->
                 </module>
             </modules>
         </data>
old mode 100644 (file)
new mode 100755 (executable)
index 20b69ab..a6cb224
@@ -38,6 +38,7 @@ public class OFOverlayProviderModule extends org.opendaylight.controller.config.
                                      getNotificationAdapterDependency(),
                                      getEpRendererAugmentationRegistryDependency(),
                                      getPolicyValidatorRegistryDependency(),
+                                     getStatisticsManagerDependency(),
                                      getGbpOfoverlayTableOffset().shortValue());
     }
 
old mode 100644 (file)
new mode 100755 (executable)
index 6ca185f..53b7c07
@@ -28,6 +28,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentationRegistry;
 import org.opendaylight.groupbasedpolicy.api.PolicyValidatorRegistry;
+import org.opendaylight.groupbasedpolicy.api.StatisticsManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.OfOverlayAug;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.OfOverlayL3NatAug;
@@ -36,6 +37,7 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Action;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ActionDefinitionListener;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ClassifierDefinitionListener;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.SflowClientSettingsListener;
 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
@@ -56,6 +58,7 @@ import com.google.common.util.concurrent.ListenableFuture;
  * using Open vSwitch.
  */
 public class OFOverlayRenderer implements AutoCloseable, DataChangeListener {
+
     private static final Logger LOG =
             LoggerFactory.getLogger(OFOverlayRenderer.class);
     public static final RendererName RENDERER_NAME = new RendererName("OFOverlay");
@@ -65,6 +68,7 @@ public class OFOverlayRenderer implements AutoCloseable, DataChangeListener {
     private final EndpointManager endpointManager;
     private final PolicyManager policyManager;
     private final ClassifierDefinitionListener classifierDefinitionListener;
+    private final SflowClientSettingsListener sflowClientSettingsListener;
     private ActionDefinitionListener actionDefinitionListener;
     private final OfOverlayAug ofOverlayAug;
     private final OfOverlayL3NatAug ofOverlayL3NatAug;
@@ -77,11 +81,12 @@ public class OFOverlayRenderer implements AutoCloseable, DataChangeListener {
     ListenerRegistration<DataChangeListener> configReg;
 
     public OFOverlayRenderer(final DataBroker dataProvider,
-                             RpcProviderRegistry rpcRegistry,
-                             NotificationService notificationService,
-                             EpRendererAugmentationRegistry epRendererAugmentationRegistry,
-                             PolicyValidatorRegistry policyValidatorRegistry,
-                             final short tableOffset) {
+            RpcProviderRegistry rpcRegistry,
+            NotificationService notificationService,
+            EpRendererAugmentationRegistry epRendererAugmentationRegistry,
+            PolicyValidatorRegistry policyValidatorRegistry,
+            StatisticsManager statisticsManager,
+            final short tableOffset) {
         super();
         this.dataBroker = dataProvider;
         int numCPU = Runtime.getRuntime().availableProcessors();
@@ -99,6 +104,8 @@ public class OFOverlayRenderer implements AutoCloseable, DataChangeListener {
             policyValidatorRegistry.register(entry.getKey(), entry.getValue());
         }
 
+        sflowClientSettingsListener = new SflowClientSettingsListener(dataProvider, executor, statisticsManager);
+
         policyManager = new PolicyManager(dataProvider,
                 switchManager,
                 endpointManager,
@@ -116,6 +123,11 @@ public class OFOverlayRenderer implements AutoCloseable, DataChangeListener {
             configBuilder.setGbpOfoverlayTableOffset(tableOffset).build();
             writeTableOffset(configBuilder.build());
         }
+
+    }
+
+    public ScheduledExecutorService getExecutor() {
+        return executor;
     }
 
     // *************
@@ -133,6 +145,7 @@ public class OFOverlayRenderer implements AutoCloseable, DataChangeListener {
         if (ofOverlayAug != null) ofOverlayAug.close();
         if (ofOverlayL3NatAug != null) ofOverlayL3NatAug.close();
         if (policyManager != null) policyManager.close();
+        if (sflowClientSettingsListener != null) sflowClientSettingsListener.close();
     }
 
     // ******************
index 02fba5e9d6cbc91a8a65a47063d17e2fe9443283..20b66c6857f6d0f105524cec487d1b293cf01db0 100755 (executable)
@@ -11,10 +11,12 @@ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
 import java.io.Closeable;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CompletionService;
 import java.util.concurrent.ExecutionException;
@@ -23,6 +25,7 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
@@ -45,6 +48,7 @@ import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchListener;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcIidFactory;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.OFStatisticsManager;
 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
 import org.opendaylight.groupbasedpolicy.util.SingletonTask;
@@ -56,11 +60,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.followed.tenant.FollowedEndpointGroup;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.followed.tenant.FollowedEndpointGroupBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.ResolvedPolicies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRule;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.PolicyRuleGroupWithEndpointConstraints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.PolicyRuleGroup;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
 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.Item;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
old mode 100644 (file)
new mode 100755 (executable)
index 6162c54..65ba240
@@ -37,6 +37,7 @@ import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.EndpointListener;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.arp.ArpTasker;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.OFStatisticsManager;
 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
 import org.opendaylight.groupbasedpolicy.util.SetUtils;
@@ -281,6 +282,7 @@ public class EndpointManager implements AutoCloseable {
         // create L3 endpoint
         if (oldL3Ep == null && newL3Ep != null) {
             createL3Endpoint(newL3Ep);
+            OFStatisticsManager.addL3Endpoint(newL3Ep);
         }
 
         // update L3 endpoint
@@ -290,6 +292,7 @@ public class EndpointManager implements AutoCloseable {
 
         // remove L3 endpoint
         if (oldL3Ep != null && newL3Ep == null) {
+            OFStatisticsManager.removeL3Endpoint(oldL3Ep);
             removeL3Endpoint(oldL3Ep);
         }
     }
@@ -531,7 +534,7 @@ public class EndpointManager implements AutoCloseable {
 
     /**
      * An endpoint is external if its endpoint-group is external implicit group.
-     * 
+     *
      * @param ep an endpoint
      * @param eigs external implicit groups
      * @return {@code true} if the given endpoint has EPG representing external implicit group;
@@ -545,7 +548,7 @@ public class EndpointManager implements AutoCloseable {
 
     /**
      * An endpoint is internal if none of its endpoint-groups is external implicit group.
-     * 
+     *
      * @param ep an endpoint
      * @param eigs external implicit groups
      * @return {@code true} if the given endpoint does not have EPG representing external implicit
@@ -606,7 +609,8 @@ public class EndpointManager implements AutoCloseable {
         }
         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
         Optional<Endpoints> endpoints =
-                DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.endpointsIidWildcard(), rTx);
+                DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
+                        IidFactory.endpointsIidWildcard(), rTx);
         if (!endpoints.isPresent()) {
             LOG.warn("No Endpoints present in data store.");
             return null;
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/JsonRestClient.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/JsonRestClient.java
new file mode 100755 (executable)
index 0000000..40dbc18
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import com.google.common.base.Preconditions;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JsonRestClient {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JsonRestClient.class);
+
+    private String uri;
+    private ClientConfig clientConfig;
+    private Client client;
+    private WebResource webResource;
+
+    public JsonRestClient(String uri, Integer connectTimeout, Integer readTimeout) {
+        Preconditions.checkNotNull(uri);
+
+        this.uri = uri;
+        clientConfig = new DefaultClientConfig();
+        clientConfig.getProperties()
+                .put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, connectTimeout);
+        clientConfig.getProperties().put(ClientConfig.PROPERTY_READ_TIMEOUT, readTimeout);
+
+        client = Client.create(clientConfig);
+        webResource = client.resource(this.uri);
+    }
+
+    public String getHost() {
+        return webResource.getURI().getHost();
+    }
+
+    public JsonRestClientResponse get(String path) throws ClientHandlerException {
+        return get(path, null);
+    }
+
+    public JsonRestClientResponse get(String path, MultivaluedMap<String, String> params)
+            throws ClientHandlerException {
+        ClientResponse response;
+        WebResource r = this.webResource.path(path);
+        if (params == null) {
+            response = r.accept(MediaType.APPLICATION_JSON_TYPE).get(ClientResponse.class);
+        } else {
+            response = r.queryParams(params)
+                    .accept(MediaType.APPLICATION_JSON_TYPE)
+                    .get(ClientResponse.class);
+        }
+        return new JsonRestClientResponse(response);
+    }
+
+    public JsonRestClientResponse post(String path, String someJson) throws ClientHandlerException {
+        ClientResponse response;
+        response = webResource.path(path)
+                .accept(MediaType.APPLICATION_JSON_TYPE)
+                .type(MediaType.APPLICATION_JSON_TYPE)
+                .post(ClientResponse.class, someJson);
+        return new JsonRestClientResponse(response);
+    }
+
+    public JsonRestClientResponse put(String path, String someJson) throws ClientHandlerException {
+        ClientResponse response;
+        response = webResource.path(path)
+                .accept(MediaType.APPLICATION_JSON_TYPE)
+                .type(MediaType.APPLICATION_JSON_TYPE)
+                .put(ClientResponse.class, someJson);
+        return new JsonRestClientResponse(response);
+    }
+
+    public JsonRestClientResponse delete(String path) throws ClientHandlerException {
+        ClientResponse response;
+        response = webResource.path(path)
+                .accept(MediaType.APPLICATION_JSON_TYPE)
+                .delete(ClientResponse.class);
+        return new JsonRestClientResponse(response);
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/JsonRestClientResponse.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/JsonRestClientResponse.java
new file mode 100644 (file)
index 0000000..055baf5
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.ofoverlay.statistics;
+
+import javax.annotation.Nullable;
+
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+
+public class JsonRestClientResponse {
+
+    private ClientResponse clientResponse;
+    private String entity;
+    private int statusCode;
+    private ClientHandlerException clientHandlerException;
+
+    public JsonRestClientResponse(ClientResponse clientResponse) {
+        this.clientResponse = clientResponse;
+        try {
+            entity = clientResponse.getEntity(String.class);
+        } catch (UniformInterfaceException e) {
+            // in case of 204 No Content
+            entity = null;
+        } catch (ClientHandlerException ex) {
+            clientHandlerException = ex;
+            // LOG.warn("Error getting response entity while status code is: {}",
+            // clientResponse.getClientResponseStatus(), ex);
+            entity = null;
+        }
+        this.statusCode = clientResponse.getStatus();
+    }
+
+    public ClientResponse getClientResponse() {
+        return clientResponse;
+    }
+
+    public int getStatusCode() {
+        return statusCode;
+    }
+
+    @Nullable
+    public String getJsonResponse() {
+        return entity;
+    }
+
+    @Nullable
+    public ClientHandlerException getClientHandlerException() {
+        return clientHandlerException;
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/OFStatisticsManager.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/OFStatisticsManager.java
new file mode 100755 (executable)
index 0000000..a17c315
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nullable;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.groupbasedpolicy.api.StatisticsManager;
+import org.opendaylight.groupbasedpolicy.dto.ConsEpgKey;
+import org.opendaylight.groupbasedpolicy.dto.EpgKeyDto;
+import org.opendaylight.groupbasedpolicy.dto.ProvEpgKey;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCache;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCacheFactory;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.util.FlowCacheCons;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.util.IidSflowNameUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicyKey;
+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.HashMultimap;
+import com.google.common.collect.SetMultimap;
+
+public class OFStatisticsManager implements AutoCloseable {
+
+    // key is String (not a full IpAddress) because
+    // we will get String from REST query to sFlow
+    private static ConcurrentMap<String, EndpointL3> endpointL3ByIpMap = new ConcurrentHashMap<>();
+
+    private static final Logger LOG = LoggerFactory.getLogger(OFStatisticsManager.class);
+
+    private final ScheduledExecutorService executor;
+    private final StatisticsManager statisticsManager;
+    private final Set<String> flowCacheNames = new HashSet<>();
+    private static final SetMultimap<ContractId, Pair<ConsEpgKey, ProvEpgKey>> epgsByContractId = HashMultimap.create();
+    private List<ScheduledFuture<?>> collectStatsTasks = new ArrayList<>();
+
+    private static int MAX_FLOWS = 100;
+    private static double MIN_VALUE_IN_FLOW = 0.1;
+    private static final String AGG_MODE = "sum";
+    private Long delay;
+    private String sflowCollectorUri;
+
+    public OFStatisticsManager(ScheduledExecutorService executor, StatisticsManager statisticsManager) {
+        this.executor = executor;
+        this.statisticsManager = statisticsManager;
+    }
+
+    public synchronized void pullStatsForClassifier(InstanceIdentifier<Classifier> classifierIid,
+            Classifier classifier) {
+        Preconditions.checkNotNull(sflowCollectorUri);
+        Preconditions.checkNotNull(delay);
+        FlowCache flowCache = FlowCacheFactory.createFlowCache(classifierIid, classifier, FlowCacheCons.Value.BYTES);
+        setStatsPulling(flowCache, classifierIid);
+        flowCache = FlowCacheFactory.createFlowCache(classifierIid, classifier, FlowCacheCons.Value.FRAMES);
+        setStatsPulling(flowCache, classifierIid);
+    }
+
+    private void setStatsPulling(FlowCache flowCache, InstanceIdentifier<Classifier> classifierIid) {
+        if (flowCache == null) {
+            LOG.trace("Flow cache is null for classifier {}", classifierIid);
+            return;
+        }
+        ResolvedPolicyKey resolvedPolicyKey = classifierIid.firstKeyOf(ResolvedPolicy.class);
+        ConsEpgKey consEpgKey =
+                new EpgKeyDto(resolvedPolicyKey.getConsumerEpgId(), resolvedPolicyKey.getConsumerTenantId());
+        ProvEpgKey provEpgKey =
+                new EpgKeyDto(resolvedPolicyKey.getProviderEpgId(), resolvedPolicyKey.getProviderTenantId());
+        String flowCacheName = flowCache.getName();
+        ContractId contractId = IidSflowNameUtil.resolveContractIdFromFlowCacheName(flowCacheName);
+        epgsByContractId.put(contractId, Pair.of(consEpgKey, provEpgKey));
+        boolean isFlowCacheNew = flowCacheNames.add(flowCacheName);
+        if (isFlowCacheNew) {
+            SFlowRTConnection sFlowRTConnection = new SFlowRTConnection(executor, sflowCollectorUri, flowCache);
+            ScheduledFuture<?> collectStatsTask = this.executor.scheduleWithFixedDelay(new ReadGbpFlowCacheTask(flowCacheName, sFlowRTConnection,
+                    statisticsManager, MAX_FLOWS, MIN_VALUE_IN_FLOW, AGG_MODE), 0, delay, TimeUnit.SECONDS);
+            collectStatsTasks.add(collectStatsTask);
+        }
+    }
+
+    public synchronized static Set<Pair<ConsEpgKey, ProvEpgKey>> getEpgsForContract(ContractId contractId) {
+        return epgsByContractId.get(contractId);
+    }
+
+    public synchronized void setSflowCollectorUri(String sflowCollectorUri) {
+        this.sflowCollectorUri = sflowCollectorUri;
+    }
+
+    public synchronized void setDelay(Long delay) {
+        this.delay = delay;
+    }
+
+    public static EndpointL3 getEndpointL3ForIp(@Nullable String ipAddress) {
+        if (ipAddress == null) {
+            return null;
+        }
+        return endpointL3ByIpMap.get(ipAddress);
+    }
+
+    public static void addL3Endpoint(EndpointL3 endpointL3) {
+        endpointL3ByIpMap.put(getStringIpAddress(endpointL3.getIpAddress()), endpointL3);
+    }
+
+    public static void removeL3Endpoint(EndpointL3 endpointL3) {
+        endpointL3ByIpMap.remove(getStringIpAddress(endpointL3.getIpAddress()));
+    }
+
+    private static String getStringIpAddress(IpAddress ipAddress) {
+        if (ipAddress.getIpv4Address() != null) {
+            return ipAddress.getIpv4Address().getValue();
+        }
+        return ipAddress.getIpv6Address().getValue();
+    }
+
+    @Override
+    public synchronized void close() throws Exception {
+        Iterator<ScheduledFuture<?>> tasksIterator = collectStatsTasks.iterator();
+        while (tasksIterator.hasNext()) {
+            ScheduledFuture<?> scheduledFuture = tasksIterator.next();
+            scheduledFuture.cancel(false);
+            tasksIterator.remove();
+        }
+        epgsByContractId.clear();
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ProcessDataTask.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ProcessDataTask.java
new file mode 100755 (executable)
index 0000000..1126150
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.ofoverlay.statistics;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.groupbasedpolicy.api.StatisticsManager;
+import org.opendaylight.groupbasedpolicy.dto.ConsEpgKey;
+import org.opendaylight.groupbasedpolicy.dto.EpgKey;
+import org.opendaylight.groupbasedpolicy.dto.EpgKeyDto;
+import org.opendaylight.groupbasedpolicy.dto.ProvEpgKey;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCache;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCacheData;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.util.FlowCacheCons;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.util.IidSflowNameUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.StatRecords;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.StatRecordsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.EpToEpStatistic;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.EpToEpStatisticBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.ep.to.ep.statistic.EpEpgToEpEpgStatistic;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.ep.to.ep.statistic.EpEpgToEpEpgStatisticBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.ep.to.ep.statistic.ep.epg.to.ep.epg.statistic.MatchedRuleStatisticBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+public class ProcessDataTask implements Runnable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ProcessDataTask.class);
+
+    private FlowCache flowCache;
+    private BigInteger timestamp;
+    private StatisticsManager statisticsManager;
+    List<FlowCacheData> dataList;
+
+    public ProcessDataTask(FlowCache flowCache, List<FlowCacheData> dataList, BigInteger timestamp,
+            StatisticsManager statisticsManager) {
+        this.flowCache = flowCache;
+        this.dataList = dataList;
+        this.timestamp = timestamp;
+        this.statisticsManager = statisticsManager;
+    }
+
+    @Override
+    public void run() {
+        for (FlowCacheData flowCacheData : dataList) {
+            Map<String, String> flowCacheDataMap = createFlowCacheDataMap(flowCacheData);
+            if (flowCacheDataMap == null) {
+                LOG.info("Stats are skipped for {}", flowCacheData);
+                continue;
+            }
+            String srcIp = flowCacheDataMap.get(FlowCacheCons.Key.IP_SOURCE.get());
+            String dstIp = flowCacheDataMap.get(FlowCacheCons.Key.IP_DESTINATION.get());
+            EndpointL3 srcEpL3 = OFStatisticsManager.getEndpointL3ForIp(srcIp);
+            EndpointL3 dstEpL3 = OFStatisticsManager.getEndpointL3ForIp(dstIp);
+            if (srcEpL3 != null && dstEpL3 != null) {
+                ContractId contractId = IidSflowNameUtil.resolveContractIdFromFlowCacheName(flowCache.getName());
+                MatchedRuleStatisticBuilder matchedRuleStatisticBuilder = new MatchedRuleStatisticBuilder()
+                .setContract(contractId)
+                .setSubject(IidSflowNameUtil.resolveSubjectNameFromFlowCacheName(flowCache.getName()))
+                .setMatchedRule(IidSflowNameUtil.resolveRuleNameFromFlowCacheName(flowCache.getName()))
+                .setClassifier(ImmutableList
+                    .of(IidSflowNameUtil.resolveClassifierNameFromFlowCacheName(flowCache.getName())));
+                if (FlowCacheCons.Value.BYTES.get().equals(IidSflowNameUtil.resolveFlowCacheValue(flowCache.getName()))) {
+                    matchedRuleStatisticBuilder.setByteCount(Math.round(flowCacheData.getValue()));
+                } else if (FlowCacheCons.Value.FRAMES.get().equals(IidSflowNameUtil.resolveFlowCacheValue(flowCache.getName()))) {
+                    matchedRuleStatisticBuilder.setPacketCount(Math.round(flowCacheData.getValue()));
+                }
+
+                Set<Pair<ConsEpgKey, ProvEpgKey>> epgsForContract = OFStatisticsManager.getEpgsForContract(contractId);
+                Set<EpgKey> epgsFromSrcEp = getEpgsFromEndpoint(srcEpL3);
+                Set<EpgKey> epgsFromDstEp = getEpgsFromEndpoint(dstEpL3);
+                Pair<? extends EpgKey, ? extends EpgKey> leftSrcEpgRightDstEpg = getMatchingEpgs(epgsForContract, epgsFromSrcEp, epgsFromDstEp, flowCache.getDirection());
+                if (leftSrcEpgRightDstEpg == null) {
+                    LOG.info("Stats are skipped for {}", flowCacheData);
+                    continue;
+                }
+
+                EpEpgToEpEpgStatistic epEpgToEpEpgStats = new EpEpgToEpEpgStatisticBuilder()
+                    .setSrcEpg(leftSrcEpgRightDstEpg.getLeft().getEpgId())
+                    .setDstEpg(leftSrcEpgRightDstEpg.getRight().getEpgId())
+                    .setMatchedRuleStatistic(ImmutableList.of(matchedRuleStatisticBuilder.build()))
+                    .build();
+
+                EpToEpStatistic e2e = new EpToEpStatisticBuilder().setSrcL2c(srcEpL3.getL2Context())
+                    .setSrcMacAddress(srcEpL3.getMacAddress())
+                    .setSrcTenant(srcEpL3.getTenant())
+                    .setDstL2c(dstEpL3.getL2Context())
+                    .setDstMacAddress(dstEpL3.getMacAddress())
+                    .setDstTenant(dstEpL3.getTenant())
+                    .setEpEpgToEpEpgStatistic(ImmutableList.of(epEpgToEpEpgStats))
+                    .setTimestamp(timestamp)
+                    .build();
+
+                StatRecords statRecords = new StatRecordsBuilder().setEpToEpStatistic(ImmutableList.of(e2e)).build();
+
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("[sflow] writing StatRecords: {}", statRecords);
+                }
+                statisticsManager.writeStat(statRecords);
+            }
+        }
+    }
+
+    private Set<EpgKey> getEpgsFromEndpoint(EndpointL3 epL3) {
+        Set<EpgKey> result = new HashSet<>();
+        TenantId tenantId = epL3.getTenant();
+        if (epL3.getEndpointGroup() != null) {
+            result.add(new EpgKeyDto(epL3.getEndpointGroup(), tenantId));
+        }
+        List<EndpointGroupId> epgs = epL3.getEndpointGroups();
+        if (epgs != null) {
+            for (EndpointGroupId epg : epgs) {
+                result.add(new EpgKeyDto(epg, tenantId));
+            }
+        }
+        return result;
+    }
+
+    private Pair<? extends EpgKey, ? extends EpgKey> getMatchingEpgs(Set<Pair<ConsEpgKey, ProvEpgKey>> epgsForContract,
+            Set<EpgKey> epgsFromSrcEp, Set<EpgKey> epgsFromDstEp, Direction direction) {
+        if (direction == null || Direction.Bidirectional == direction) {
+            LOG.info("The bidirectional direction is not supported.");
+            return null;
+        }
+        for (Pair<ConsEpgKey, ProvEpgKey> epgForContract : epgsForContract) {
+            ConsEpgKey consEpg = epgForContract.getLeft();
+            ProvEpgKey provEpg = epgForContract.getRight();
+            if (epgsFromSrcEp.contains(consEpg) && epgsFromDstEp.contains(provEpg)) {
+                if (Direction.In.equals(direction)) {
+                    return Pair.of(consEpg, provEpg);
+                } else if (Direction.Out.equals(direction)) {
+                    return Pair.of(provEpg, consEpg);
+                }
+            }
+            if (epgsFromSrcEp.contains(provEpg) && epgsFromDstEp.contains(consEpg)) {
+                if (Direction.In.equals(direction)) {
+                    return Pair.of(consEpg, provEpg);
+                } else if (Direction.Out.equals(direction)) {
+                    return Pair.of(provEpg, consEpg);
+                }
+            }
+        }
+        LOG.info(
+                "EPGs of srcEP and dstEp does not match against EPGs for contract:"
+                        + "\nsrcEP EPGs: {}\ndstEP EPGs: {}\nEPGs for contract: {}",
+                epgsFromSrcEp, epgsFromDstEp, epgsForContract);
+        return null;
+    }
+
+    private Map<String, String> createFlowCacheDataMap(FlowCacheData flowCacheData) {
+        String[] splitValues = flowCacheData.getKey().split(",");
+        if (splitValues.length != flowCache.getKeyNum()) {
+            LOG.error(
+                    "Key names and key values lists length do not match: {} != {}. Not processing.",
+                    flowCache.getKeyNum(), splitValues.length);
+            return null;
+        }
+        Map<String, String> flowCacheDataMap = new HashMap<>();
+        for (int i = 0; i < flowCache.getKeyNum(); i++) {
+            flowCacheDataMap.put(flowCache.getKeyNames()[i], splitValues[i]);
+        }
+        return flowCacheDataMap;
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ReadGbpFlowCacheTask.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ReadGbpFlowCacheTask.java
new file mode 100755 (executable)
index 0000000..bd476cf
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.lang.reflect.Type;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.opendaylight.groupbasedpolicy.api.StatisticsManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCacheData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+
+public class ReadGbpFlowCacheTask implements Runnable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ReadGbpFlowCacheTask.class);
+
+    private static final Type LIST_OF_FLOW_CACHE_DATA = new TypeToken<List<FlowCacheData>>() {}.getType();
+    private static final Gson GSON = new Gson();
+    private static final String MAX_FLOWS_PARAM = "maxFlows";
+    private static final String MIN_VALUE_PARAM = "minValue";
+    private static final String AGG_MODE_PARAM = "aggMode";
+
+    private final SFlowRTConnection sFlowRTConnection;
+    private final StatisticsManager statisticsManager;
+    private final String maxFlows;
+    private final String minValue;
+    private final String aggMode;
+    private final String path;
+
+    public ReadGbpFlowCacheTask(String flowCacheName, SFlowRTConnection sFlowRTConnection,
+            StatisticsManager statisticsManager, Integer maxFlows, Double minValue, String aggMode) {
+        this.path = "/activeflows/ALL/" + checkNotNull(flowCacheName) + "/json";
+        this.sFlowRTConnection = checkNotNull(sFlowRTConnection);
+        this.statisticsManager = checkNotNull(statisticsManager);
+        this.maxFlows = String.valueOf(checkNotNull(maxFlows));
+        this.minValue = String.valueOf(checkNotNull(minValue));
+        this.aggMode = checkNotNull(aggMode);
+    }
+
+    @Override
+    public void run() {
+        MultivaluedMap<String, String> params = new MultivaluedMapImpl();
+        params.add(MAX_FLOWS_PARAM, maxFlows);
+        params.add(MIN_VALUE_PARAM, minValue);
+        params.add(AGG_MODE_PARAM, aggMode);
+        JsonRestClientResponse result = sFlowRTConnection.get(path, params);
+
+        if (result != null && result.getJsonResponse() != null) {
+            List<FlowCacheData> dataList = GSON.fromJson(result.getJsonResponse(), LIST_OF_FLOW_CACHE_DATA);
+            if (dataList == null) {
+                LOG.trace("Empty reply, not processing");
+                return;
+            }
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("Got sFlow reply: {}", result.getJsonResponse());
+            }
+
+            if (result.getStatusCode() < 300) {
+                sFlowRTConnection.getExecutor().execute((new ProcessDataTask(sFlowRTConnection.getFlowCache(), dataList,
+                        BigInteger.valueOf(new Date().getTime()), statisticsManager)));
+            } else if (result.getStatusCode() < 400) {
+                LOG.warn("Status code {}, not processing data. Response: {}", result.getStatusCode(),
+                        result.getClientResponse().toString());
+            } else {
+                LOG.error("Status code {}, not processing data. Response: {}", result.getStatusCode(),
+                        result.getClientResponse().toString());
+            }
+        }
+    }
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ResolvedPolicyClassifierListener.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/ResolvedPolicyClassifierListener.java
new file mode 100644 (file)
index 0000000..e7faaac
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.ofoverlay.statistics;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.ResolvedPolicies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.PolicyRuleGroupWithEndpointConstraints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.PolicyRuleGroup;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.MapDifference;
+import com.google.common.collect.Maps;
+
+public class ResolvedPolicyClassifierListener extends DataTreeChangeHandler<ResolvedPolicy> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ResolvedPolicyClassifierListener.class);
+    private final OFStatisticsManager ofStatsManager;
+
+    public ResolvedPolicyClassifierListener(DataBroker dataProvider, OFStatisticsManager ofStatsManager) {
+        super(dataProvider, new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.builder(ResolvedPolicies.class).child(ResolvedPolicy.class).build()));
+        this.ofStatsManager = checkNotNull(ofStatsManager);
+    }
+
+    @Override
+    protected void onWrite(DataObjectModification<ResolvedPolicy> rootNode,
+            InstanceIdentifier<ResolvedPolicy> rootIdentifier) {
+        ResolvedPolicy resolvedPolicy = rootNode.getDataAfter();
+        Map<InstanceIdentifier<Classifier>, Classifier> classifierByIid =
+                resolveClassifiers(resolvedPolicy, rootIdentifier);
+        for (Entry<InstanceIdentifier<Classifier>, Classifier> classfierEntry : classifierByIid.entrySet()) {
+            LOG.trace("New classifier created: {}\n{}", classfierEntry.getKey(), classfierEntry.getValue());
+            ofStatsManager.pullStatsForClassifier(classfierEntry.getKey(), classfierEntry.getValue());
+        }
+    }
+
+    @Override
+    protected void onDelete(DataObjectModification<ResolvedPolicy> rootNode,
+            InstanceIdentifier<ResolvedPolicy> rootIdentifier) {
+        LOG.debug("Delete is not supported yet.");
+    }
+
+    @Override
+    protected void onSubtreeModified(DataObjectModification<ResolvedPolicy> rootNode,
+            InstanceIdentifier<ResolvedPolicy> rootIdentifier) {
+        ResolvedPolicy resolvedPolicyAfter = rootNode.getDataAfter();
+        ResolvedPolicy resolvedPolicyBefore = rootNode.getDataBefore();
+        Map<InstanceIdentifier<Classifier>, Classifier> classifierByIidAfter =
+                resolveClassifiers(resolvedPolicyAfter, rootIdentifier);
+        Map<InstanceIdentifier<Classifier>, Classifier> classifierByIidBefore =
+                resolveClassifiers(resolvedPolicyBefore, rootIdentifier);
+        MapDifference<InstanceIdentifier<Classifier>, Classifier> difference =
+                Maps.difference(classifierByIidBefore, classifierByIidAfter);
+        Map<InstanceIdentifier<Classifier>, Classifier> createdClassifierByIid = difference.entriesOnlyOnRight();
+        for (Entry<InstanceIdentifier<Classifier>, Classifier> createdClassfierEntry : createdClassifierByIid
+            .entrySet()) {
+            LOG.trace("New classifier created: {}\n{}", createdClassfierEntry.getKey(),
+                    createdClassfierEntry.getValue());
+            ofStatsManager.pullStatsForClassifier(createdClassfierEntry.getKey(), createdClassfierEntry.getValue());
+        }
+        // TODO missing impl for case when classifier is changed or removed
+    }
+
+    private Map<InstanceIdentifier<Classifier>, Classifier> resolveClassifiers(ResolvedPolicy resolvedPolicy,
+            InstanceIdentifier<ResolvedPolicy> resolvedPolicyIid) {
+        List<PolicyRuleGroupWithEndpointConstraints> policyRgWithEcs =
+                resolvedPolicy.getPolicyRuleGroupWithEndpointConstraints();
+        if (policyRgWithEcs == null) {
+            return Collections.emptyMap();
+        }
+        Map<InstanceIdentifier<Classifier>, Classifier> result = new HashMap<>();
+        for (PolicyRuleGroupWithEndpointConstraints policyRgWithEc : policyRgWithEcs) {
+            List<PolicyRuleGroup> policyRuleGroups = policyRgWithEc.getPolicyRuleGroup();
+            if (policyRuleGroups == null) {
+                continue;
+            }
+            for (PolicyRuleGroup policyRuleGroup : policyRuleGroups) {
+                List<ResolvedRule> resolvedRules = policyRuleGroup.getResolvedRule();
+                if (resolvedRules == null) {
+                    continue;
+                }
+                for (ResolvedRule resolvedRule : resolvedRules) {
+                    List<Classifier> classifiers = resolvedRule.getClassifier();
+                    if (classifiers == null) {
+                        continue;
+                    }
+                    for (Classifier classifier : classifiers) {
+                        InstanceIdentifier<Classifier> classifierIid = resolvedPolicyIid.builder()
+                            .child(PolicyRuleGroupWithEndpointConstraints.class)
+                            .child(PolicyRuleGroup.class, policyRuleGroup.getKey())
+                            .child(ResolvedRule.class, resolvedRule.getKey())
+                            .child(Classifier.class, classifier.getKey())
+                            .build();
+                        result.put(classifierIid, classifier);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/SFlowRTConnection.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/SFlowRTConnection.java
new file mode 100755 (executable)
index 0000000..9a390fe
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics;
+
+import javax.annotation.Nullable;
+import javax.ws.rs.core.MultivaluedMap;
+import java.util.concurrent.ScheduledExecutorService;
+
+import com.google.common.base.Preconditions;
+import com.sun.jersey.api.client.ClientHandlerException;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SFlowRTConnection {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SFlowRTConnection.class);
+
+    private static final int CONNECT_TIMEOUT_MILLISEC = 20000;
+    private static final int READ_TIMEOUT_MILLISEC = 30000;
+    private static final String GET = "GET";
+    private static final String PUT = "PUT";
+    private static final String DELETE = "DELETE";
+
+    private final FlowCache flowCache;
+    private JsonRestClient client;
+    private boolean isInitialized = false;
+    private final ScheduledExecutorService executor;
+    private final String collectorUri;
+
+    public SFlowRTConnection(ScheduledExecutorService executor, String collectorUri, FlowCache flowCache) {
+        this.executor = Preconditions.checkNotNull(executor);
+        this.collectorUri = Preconditions.checkNotNull(collectorUri);
+        this.flowCache = Preconditions.checkNotNull(flowCache);
+
+        this.client = new JsonRestClient(collectorUri, CONNECT_TIMEOUT_MILLISEC,
+                READ_TIMEOUT_MILLISEC);
+        initialize();
+    }
+
+    @Nullable
+    public String getJsonResponse(String path, MultivaluedMap<String, String> params) {
+        try {
+            JsonRestClientResponse responce = client.get(path, params);
+            Preconditions.checkNotNull(responce);
+            logStatusCode(GET, responce.getStatusCode(), path, params);
+            return responce.getJsonResponse();
+        } catch (ClientHandlerException e) {
+            processClientHandlerException(e);
+        }
+        return null;
+    }
+
+    @Nullable
+    public JsonRestClientResponse get(String path,
+            MultivaluedMap<String, String> params) {
+        if (!isInitialized()) {
+            throw new IllegalStateException("SFlowRTConnection is not initialized.");
+        }
+        try {
+            JsonRestClientResponse responce = client.get(path, params);
+            Preconditions.checkNotNull(responce);
+            return responce;
+        } catch (ClientHandlerException e) {
+            processClientHandlerException(e);
+        }
+        return null;
+    }
+
+    @Nullable
+    public JsonRestClientResponse put(String path, String someJson) {
+        if (!isInitialized()) {
+            throw new IllegalStateException("SFlowRTConnection is not initialized.");
+        }
+        return putWithoutInitCheck(path, someJson);
+    }
+
+    private JsonRestClientResponse putWithoutInitCheck(String path,
+            String someJson) {
+        try {
+            JsonRestClientResponse responce = client.put(path, someJson);
+            Preconditions.checkNotNull(responce);
+            logStatusCode(PUT, responce.getStatusCode(), path, null);
+            return responce;
+        } catch (ClientHandlerException e) {
+            processClientHandlerException(e);
+        }
+        return null;
+    }
+
+    public JsonRestClientResponse delete(String path) {
+        if (!isInitialized()) {
+            throw new IllegalStateException("SFlowRTConnection is not initialized.");
+        }
+        try {
+            JsonRestClientResponse responce = client.delete(path);
+            Preconditions.checkNotNull(responce);
+            logStatusCode(DELETE, responce.getStatusCode(), path, null);
+            return responce;
+        } catch (ClientHandlerException e) {
+            processClientHandlerException(e);
+        }
+        return null;
+    }
+
+    public boolean isInitialized() {
+        return isInitialized;
+    }
+
+    public FlowCache getFlowCache() {
+        return flowCache;
+    }
+
+    public ScheduledExecutorService getExecutor() {
+        return executor;
+    }
+
+    public String getCollectorUri() {
+        return collectorUri;
+    }
+
+    public void initialize() {
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Initializing flow {}", flowCache);
+        }
+        JsonRestClientResponse initResp =
+                putWithoutInitCheck(flowCache.getPath(), flowCache.getJsonDefinition());
+        Preconditions.checkNotNull(initResp);
+        if (initResp.getStatusCode() < 300) {
+            LOG.info("sFlow connection {} initialization status code {}", getCollectorUri(), initResp.getStatusCode());
+        } else if (initResp.getStatusCode() < 400) {
+            LOG.warn("sFlow connection {} initialization status code {}", getCollectorUri(), initResp.getStatusCode());
+        } else {
+            LOG.error("sFlow connection {} initialization status code {}", getCollectorUri(), initResp.getStatusCode());
+        }
+        this.isInitialized = true;
+    }
+
+    private void processClientHandlerException(ClientHandlerException e) {
+        if (e.getCause() instanceof java.net.SocketTimeoutException || e.getCause() instanceof java.net.ConnectException) {
+            LOG.error("Connection to {} failed: {}", client.getHost(), e.getMessage());
+            this.isInitialized = false;
+            throw e;
+        } else {
+            throw e;
+        }
+    }
+
+    private void logStatusCode(String verb, int status, String path,
+            MultivaluedMap<String, String> params) {
+        if (params != null) {
+            if (status <= 204) {
+                LOG.trace("Query {} {} with params {} returned status {}", verb, path, params,
+                        status);
+            } else if (status < 400) {
+                LOG.warn("Query {} {} with params {} returned status {}", verb, path, params,
+                        status);
+            } else {
+                LOG.error("Query {} {} with params {} returned status {}", verb, path, params,
+                        status);
+            }
+        } else {
+            if (status <= 204) {
+                LOG.trace("Query {} {} returned status {}", verb, path, status);
+            } else if (status < 400) {
+                LOG.warn("Query {} {} returned status {}", verb, path, status);
+            } else {
+                LOG.error("Query {} {} returned status {}", verb, path, status);
+            }
+        }
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/SflowClientSettingsListener.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/SflowClientSettingsListener.java
new file mode 100755 (executable)
index 0000000..ec0a0bf
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.ofoverlay.statistics;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.api.StatisticsManager;
+import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.sflow.values.SflowClientSettings;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class SflowClientSettingsListener extends DataTreeChangeHandler<SflowClientSettings> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SflowClientSettingsListener.class);
+    private static InstanceIdentifier<SflowClientSettings> IID =
+            InstanceIdentifier.builder(OfOverlayConfig.class)
+                    .child(SflowClientSettings.class)
+                    .build();
+    private OFStatisticsManager ofStatisticsManager;
+    private final ScheduledExecutorService executor;
+    private final StatisticsManager statisticsManager;
+    private ResolvedPolicyClassifierListener classifierListener;
+
+    public SflowClientSettingsListener(DataBroker dataprovider, ScheduledExecutorService executor, StatisticsManager statisticsManager) {
+        super(dataprovider, new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, IID));
+        this.statisticsManager = Preconditions.checkNotNull(statisticsManager);
+        this.executor = Preconditions.checkNotNull(executor);
+    }
+
+    @Override
+    protected void onWrite(DataObjectModification<SflowClientSettings> rootNode,
+            InstanceIdentifier<SflowClientSettings> rootIdentifier) {
+        onSubtreeModified(rootNode, rootIdentifier);
+    }
+
+    @Override
+    protected void onDelete(DataObjectModification<SflowClientSettings> rootNode,
+            InstanceIdentifier<SflowClientSettings> rootIdentifier) {
+        try {
+            classifierListener.close();
+            ofStatisticsManager.close();
+        } catch (Exception e) {
+            LOG.error(
+                    "Error during closing OFStatisticsManager and ResolvedPolicyClassifierListener. "
+                    + "Statistics do not have to be correct because of illegal state.", e);
+        }
+    }
+
+    @Override
+    protected void onSubtreeModified(DataObjectModification<SflowClientSettings> rootNode,
+            InstanceIdentifier<SflowClientSettings> rootIdentifier) {
+        SflowClientSettings sflowClientSettings =
+                Preconditions.checkNotNull(rootNode.getDataAfter());
+        if (classifierListener != null && ofStatisticsManager != null) {
+            try {
+                classifierListener.close();
+                ofStatisticsManager.close();
+            } catch (Exception e) {
+                LOG.error(
+                        "Error during closing OFStatisticsManager and ResolvedPolicyClassifierListener. "
+                        + "Statistics do not have to be correct because of illegal state.", e);
+            }
+        }
+        ofStatisticsManager = new OFStatisticsManager(executor, statisticsManager);
+        ofStatisticsManager.setSflowCollectorUri(sflowClientSettings.getGbpOfoverlaySflowCollectorUri());
+        ofStatisticsManager.setDelay(sflowClientSettings.getGbpOfoverlaySflowRetrieveInterval());
+        classifierListener = new ResolvedPolicyClassifierListener(dataProvider, ofStatisticsManager);
+    }
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCache.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCache.java
new file mode 100755 (executable)
index 0000000..6aca699
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache;
+
+import java.util.Arrays;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
+
+import com.google.common.base.Preconditions;
+import com.google.gson.Gson;
+
+public class FlowCache {
+
+    static final String API_FLOW = "/flow/";
+    static final String SUFFIX_JSON = "/json";
+
+    private transient Direction direction;
+    private String name;
+    private FlowCacheDefinition definition;
+
+    /** Array containing key names from FlowCacheDefinition */
+    private String[] keyNames;
+    private int keyNum;
+
+    private FlowCache() {
+    }
+
+    private FlowCache(FlowCacheBuilder builder) {
+        this.name = builder.getName();
+        this.definition = builder.getDefinition();
+        this.direction = builder.getDirection();
+
+        this.keyNames = this.definition.getKeys().split(",");
+        this.keyNum = this.keyNames.length;
+        for (int i = 0; i < this.keyNum; i++) {
+            keyNames[i] = parseNullableKeyName(keyNames[i]);
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public FlowCacheDefinition getDefinition() {
+        return definition;
+    }
+
+    public Direction getDirection() {
+        return direction;
+    }
+
+    public String[] getKeyNames() {
+        return keyNames;
+    }
+
+    public int getKeyNum() {
+        return keyNum;
+    }
+
+    public String getPath() {
+        return API_FLOW + name + SUFFIX_JSON;
+    }
+
+    public String getJsonDefinition() {
+        Gson gson = new Gson();
+        return gson.toJson(definition);
+    }
+
+    public static FlowCacheBuilder builder() {
+        return new FlowCacheBuilder();
+    }
+
+    private String parseNullableKeyName(String nullableKeyName) {
+        String res = nullableKeyName.replaceAll("^\\w+:(\\w+):.*", "$1");
+        return "".equals(res) ? nullableKeyName : res;
+    }
+
+    @Override
+    public String toString() {
+        return "FlowCache [name=" + name + ", definition=" + definition + ", keyNames=" + Arrays.toString(keyNames)
+                + ", keyNum=" + keyNum + "]";
+    }
+
+    public static class FlowCacheBuilder {
+
+        private String name;
+        private FlowCacheDefinition definition;
+        private Direction direction;
+
+        public String getName() {
+            return name;
+        }
+
+        public FlowCacheBuilder setName(String name) {
+            Preconditions.checkNotNull(name);
+            this.name = name;
+            return this;
+        }
+
+        public FlowCacheDefinition getDefinition() {
+            return definition;
+        }
+
+        public FlowCacheBuilder setDefinition(FlowCacheDefinition definition) {
+            Preconditions.checkNotNull(definition);
+            this.definition = definition;
+            return this;
+        }
+
+        public Direction getDirection() {
+            return direction;
+        }
+
+        public FlowCacheBuilder setDirection(Direction direction) {
+            this.direction = direction;
+            return this;
+        }
+
+        public FlowCache build() {
+            return new FlowCache(this);
+        }
+    }
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheData.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheData.java
new file mode 100755 (executable)
index 0000000..77e4ce4
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache;
+
+public class FlowCacheData {
+
+    private String key;
+    private double value;
+
+    private FlowCacheData() {
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public double getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return "FlowCacheData [key=" + key + ", value=" + value + "]";
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheDefinition.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheDefinition.java
new file mode 100755 (executable)
index 0000000..f060e49
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache;
+
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCacheFilter.FlowCacheFilterBuilder;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCacheKeys.FlowCacheKeysBuilder;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * An object to handle flow-cache parameters for JSON conversion
+ */
+public final class FlowCacheDefinition {
+
+    private String keys;
+    private String value;
+    private String filter;
+    private boolean log;
+
+    private FlowCacheDefinition() {
+    }
+
+    private FlowCacheDefinition(FlowCacheDefinitionBuilder builder) {
+        this.keys = builder.getKeysBuilder().build().getValue();
+        this.value = builder.getValue();
+        this.filter = builder.getFilterBuilder().build().getValue();
+        this.log = builder.isLog();
+    }
+
+    public String getKeys() {
+        return keys;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public String getFilter() {
+        return filter;
+    }
+
+    public boolean getLog() {
+        return log;
+    }
+
+    public static FlowCacheDefinitionBuilder builder(){
+        return new FlowCacheDefinitionBuilder();
+    }
+
+    @Override
+    public String toString() {
+        return "FlowCacheDefinition [keys=" + keys + ", value=" + value + ", filter=" + filter + ", log=" + log + "]";
+    }
+
+    public static class FlowCacheDefinitionBuilder {
+
+        private String value;
+        private boolean log = false;
+        private final FlowCacheKeysBuilder keysBuilder = new FlowCacheKeysBuilder();
+        private final FlowCacheFilterBuilder filterBuilder = new FlowCacheFilterBuilder();
+
+        public FlowCacheKeysBuilder getKeysBuilder() {
+            return keysBuilder;
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        public FlowCacheDefinitionBuilder setValue(String value) {
+            Preconditions.checkNotNull(value);
+            this.value = value;
+            return this;
+        }
+
+        public FlowCacheFilterBuilder getFilterBuilder() {
+            return filterBuilder;
+        }
+
+        public boolean isLog() {
+            return log;
+        }
+
+        public FlowCacheDefinitionBuilder setLog(boolean log) {
+            this.log = log;
+            return this;
+        }
+
+        public FlowCacheDefinition build() {
+            return new FlowCacheDefinition(this);
+        }
+    }
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheFactory.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheFactory.java
new file mode 100644 (file)
index 0000000..d40465e
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache;
+
+import java.util.List;
+
+import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
+import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
+import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCache.FlowCacheBuilder;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCacheDefinition.FlowCacheDefinitionBuilder;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.util.FlowCacheCons;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.util.IidSflowNameUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowCacheFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FlowCacheFactory.class);
+
+    public static FlowCache createFlowCache(InstanceIdentifier<Classifier> classifierIid, Classifier classifier,
+            FlowCacheCons.Value value) {
+        FlowCacheDefinition flowCacheDefinition = creteFlowCacheDefinition(classifier, value);
+        if (flowCacheDefinition == null) {
+            LOG.info("Cannot create flow cache for statistics of classifier {}\n{}", classifierIid, classifier);
+            return null;
+        }
+        return new FlowCacheBuilder().setDefinition(flowCacheDefinition)
+            .setName(IidSflowNameUtil.createFlowCacheName(classifierIid, value))
+            .setDirection(classifier.getDirection())
+            .build();
+    }
+
+    public static FlowCacheDefinition creteFlowCacheDefinition(Classifier classifier, FlowCacheCons.Value value) {
+        FlowCacheDefinitionBuilder fcdBuilder = new FlowCacheDefinitionBuilder();
+        if (L4ClassifierDefinition.ID.equals(classifier.getClassifierDefinitionId())) {
+            addEthTypeInfoToFlowCache(classifier, fcdBuilder);
+            if (!addIpProtoInfoToFlowCache(classifier, fcdBuilder)) {
+                return null;
+            }
+            if (!addL4InfoToFlowCache(classifier, fcdBuilder)) {
+                return null;
+            }
+        } else if (IpProtoClassifierDefinition.ID.equals(classifier.getClassifierDefinitionId())) {
+            addEthTypeInfoToFlowCache(classifier, fcdBuilder);
+            if (!addIpProtoInfoToFlowCache(classifier, fcdBuilder)) {
+                return null;
+            }
+        } else if (EtherTypeClassifierDefinition.ID.equals(classifier.getClassifierDefinitionId())) {
+            addEthTypeInfoToFlowCache(classifier, fcdBuilder);
+        } else {
+            LOG.warn("Sflow stats will not be pulled because of unknown classifier: {}", classifier);
+            return null;
+        }
+        fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.IP_SOURCE.get()).addValue(FlowCacheCons.Key.IP_DESTINATION.get());
+        fcdBuilder.setValue(value.get());
+        return fcdBuilder.build();
+    }
+
+    private static void addEthTypeInfoToFlowCache(Classifier classifier, FlowCacheDefinitionBuilder fcdBuilder) {
+        List<ParameterValue> parametersAndValues = classifier.getParameterValue();
+        ParameterValue ethTypeParam = getParamVal(parametersAndValues, EtherTypeClassifierDefinition.ETHERTYPE_PARAM);
+        if (ethTypeParam != null) {
+            fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.ETH_PROTOCOL.get());
+            fcdBuilder.getFilterBuilder()
+                .addValue(FlowCacheCons.Key.ETH_PROTOCOL.get() + FlowCacheCons.EQ + ethTypeParam.getIntValue());
+        } else {
+            fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.ETH_PROTOCOL.get());
+            fcdBuilder.getFilterBuilder()
+                .addValue(FlowCacheCons.Key.ETH_PROTOCOL.get() + FlowCacheCons.EQ + FlowUtils.IPv4 + FlowCacheCons.OR
+                        + FlowCacheCons.Key.ETH_PROTOCOL.get() + FlowCacheCons.EQ + FlowUtils.IPv6);
+        }
+    }
+
+    private static boolean addIpProtoInfoToFlowCache(Classifier classifier, FlowCacheDefinitionBuilder fcdBuilder) {
+        List<ParameterValue> parametersAndValues = classifier.getParameterValue();
+        ParameterValue ipProtoParam = getParamVal(parametersAndValues, IpProtoClassifierDefinition.PROTO_PARAM);
+        if (ipProtoParam != null) {
+            fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.IP_PROTOCOL.get());
+            fcdBuilder.getFilterBuilder()
+                .addValue(FlowCacheCons.Key.IP_PROTOCOL.get() + FlowCacheCons.EQ + ipProtoParam.getIntValue());
+            return true;
+        } else {
+            LOG.trace("Cannot add ip-proto information to flow cache for Sflow-RT.");
+            return false;
+        }
+    }
+
+    private static boolean addL4InfoToFlowCache(Classifier classifier, FlowCacheDefinitionBuilder fcdBuilder) {
+        List<ParameterValue> parametersAndValues = classifier.getParameterValue();
+        ParameterValue ipProtoParam = getParamVal(parametersAndValues, IpProtoClassifierDefinition.PROTO_PARAM);
+        ParameterValue dstPortParam = getParamVal(parametersAndValues, L4ClassifierDefinition.DST_PORT_PARAM);
+        ParameterValue srcPortParam = getParamVal(parametersAndValues, L4ClassifierDefinition.SRC_PORT_PARAM);
+        if (ipProtoParam == null || (dstPortParam == null && srcPortParam == null)) {
+            LOG.trace(
+                    "Cannot add L4 information to flow cache for Sflow-RT."
+                            + "\nipProtoParam:{} dstPortParam:{} srcPortParam:{}",
+                    ipProtoParam, dstPortParam, srcPortParam);
+            return false;
+        }
+        if (dstPortParam != null) {
+            if (!addTcpUdpPortKeys(ipProtoParam.getIntValue(), dstPortParam.getIntValue(), true, fcdBuilder)) {
+                return false;
+            }
+        }
+        if (srcPortParam != null) {
+            if (!addTcpUdpPortKeys(ipProtoParam.getIntValue(), srcPortParam.getIntValue(), false, fcdBuilder)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static ParameterValue getParamVal(List<ParameterValue> parametersAndValues, String paramName) {
+        for (ParameterValue paramVal : parametersAndValues) {
+            if (paramName.equals(paramVal.getName().getValue())) {
+                return paramVal;
+            }
+        }
+        return null;
+    }
+
+    private static boolean addTcpUdpPortKeys(Long ipProto, Long port, boolean isDstPort,
+            FlowCacheDefinitionBuilder fcdBuilder) {
+        if (isDstPort) {
+            if (ipProto == IpProtoClassifierDefinition.TCP_VALUE) {
+                fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.TCP_DST_PORT.get());
+                fcdBuilder.getFilterBuilder().addValue(FlowCacheCons.Key.TCP_DST_PORT.get() + FlowCacheCons.EQ + port);
+            } else if (ipProto == IpProtoClassifierDefinition.UDP_VALUE) {
+                fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.UDP_DST_PORT.get());
+                fcdBuilder.getFilterBuilder().addValue(FlowCacheCons.Key.UDP_DST_PORT.get() + FlowCacheCons.EQ + port);
+            } else {
+                LOG.info("Statistics cannot be collected for ip-proto {} and port {}", ipProto, port);
+                return false;
+            }
+        } else {
+            if (ipProto == IpProtoClassifierDefinition.TCP_VALUE) {
+                fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.TCP_SRC_PORT.get());
+                fcdBuilder.getFilterBuilder().addValue(FlowCacheCons.Key.TCP_SRC_PORT.get() + FlowCacheCons.EQ + port);
+            } else if (ipProto == IpProtoClassifierDefinition.UDP_VALUE) {
+                fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.UDP_SRC_PORT.get());
+                fcdBuilder.getFilterBuilder().addValue(FlowCacheCons.Key.UDP_SRC_PORT.get() + FlowCacheCons.EQ + port);
+            } else {
+                LOG.info("Statistics cannot be collected for ip-proto {} and port {}", ipProto, port);
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheFilter.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheFilter.java
new file mode 100644 (file)
index 0000000..ffaa766
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+
+public final class FlowCacheFilter {
+
+    private static final String AND = "&";
+    private static final String LB = "(";
+    private static final String RB = ")";
+
+    private String value;
+
+    private FlowCacheFilter(FlowCacheFilterBuilder builder) {
+        this.value = Joiner.on(AND).join(builder.getValues());
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public static FlowCacheFilterBuilder builder(){
+        return new FlowCacheFilterBuilder();
+    }
+
+    public static class FlowCacheFilterBuilder {
+
+        private List<String> values = new ArrayList<>();
+
+        public List<String> getValues() {
+            return values;
+        }
+
+        public FlowCacheFilterBuilder setValues(List<String> values) {
+            this.values = Preconditions.checkNotNull(values);
+            return this;
+        }
+
+        public FlowCacheFilterBuilder addValue(String value) {
+            values.add(LB + Preconditions.checkNotNull(value)  + RB);
+            return this;
+        }
+
+        public FlowCacheFilter build() {
+            return new FlowCacheFilter(this);
+        }
+    }
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheKeys.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/flowcache/FlowCacheKeys.java
new file mode 100644 (file)
index 0000000..3761b25
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 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.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+
+public final class FlowCacheKeys {
+
+    private static final String SEPARATOR = ",";
+
+    private String value;
+
+    private FlowCacheKeys(FlowCacheKeysBuilder builder) {
+        this.value = Joiner.on(SEPARATOR).join(builder.getValues());
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public static FlowCacheKeysBuilder builder(){
+        return new FlowCacheKeysBuilder();
+    }
+
+    public static class FlowCacheKeysBuilder {
+
+        private List<String> values = new ArrayList<>();
+
+        public List<String> getValues() {
+            return values;
+        }
+
+        public FlowCacheKeysBuilder setValues(List<String> values) {
+            this.values = Preconditions.checkNotNull(values);
+            return this;
+        }
+
+        public FlowCacheKeysBuilder addValue(String value) {
+            values.add(Preconditions.checkNotNull(value));
+            return this;
+        }
+
+        public FlowCacheKeys build() {
+            return new FlowCacheKeys(this);
+        }
+    }
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/util/FlowCacheCons.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/util/FlowCacheCons.java
new file mode 100644 (file)
index 0000000..4bf7cce
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.ofoverlay.statistics.util;
+
+public class FlowCacheCons {
+
+    public static final String EQ = "=";
+    public static final String OR = "|";
+
+    public static enum Key {
+        TCP_DST_PORT("tcpdestinationport"),
+        TCP_SRC_PORT("tcpsourceport"),
+        UDP_DST_PORT("udpdestinationport"),
+        UDP_SRC_PORT("udpsourceport"),
+        IP_PROTOCOL("ipprotocol"),
+        ETH_PROTOCOL("ethernetprotocol"),
+        IP_SOURCE("ipsource"),
+        IP_DESTINATION("ipdestination");
+
+        private String val;
+
+        private Key(String val) {
+            this.val = val;
+        }
+
+        public String get() {
+            return val;
+        }
+    }
+
+    public static enum Value {
+        BYTES("bytes"),
+        FRAMES("frames");
+
+        private String val;
+
+        private Value(String val) {
+            this.val = val;
+        }
+
+        public String get() {
+            return val;
+        }
+    }
+
+}
diff --git a/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/util/IidSflowNameUtil.java b/renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/statistics/util/IidSflowNameUtil.java
new file mode 100644 (file)
index 0000000..57df0bc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.ofoverlay.statistics.util;
+
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.RuleName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.ClassifierKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRuleKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.PolicyRuleGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.PolicyRuleGroupKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+
+public class IidSflowNameUtil {
+
+    public static final String DELIMETER = "_-_";
+    public static final String KEY_DELIMETER = "-_-";
+
+    public static String createFlowCacheName(InstanceIdentifier<Classifier> classifierIid, FlowCacheCons.Value value) {
+        PolicyRuleGroupKey policyRuleGroup = classifierIid.firstKeyOf(PolicyRuleGroup.class);
+        ResolvedRuleKey resolvedRule = classifierIid.firstKeyOf(ResolvedRule.class);
+        ClassifierKey classifier = classifierIid.firstKeyOf(Classifier.class);
+        StringBuilder sb = new StringBuilder();
+        sb.append(createStringFromCompositeKey(policyRuleGroup.getTenantId().getValue(),
+                policyRuleGroup.getContractId().getValue(), policyRuleGroup.getSubjectName().getValue()))
+            .append(DELIMETER)
+            .append(resolvedRule.getName().getValue())
+            .append(DELIMETER)
+            .append(classifier.getName().getValue())
+            .append(DELIMETER)
+            .append(value.get());
+        return sb.toString();
+    }
+
+    private static String createStringFromCompositeKey(String... keys) {
+        return Joiner.on(KEY_DELIMETER).join(keys);
+    }
+
+    public static ContractId resolveContractIdFromFlowCacheName(String flowCacheName) {
+        List<String> keys = Splitter.on(DELIMETER).splitToList(flowCacheName);
+        String policyRuleGroupKey = keys.get(0);
+        String contractId = Splitter.on(KEY_DELIMETER).splitToList(policyRuleGroupKey).get(1);
+        return new ContractId(contractId);
+    }
+
+    public static SubjectName resolveSubjectNameFromFlowCacheName(String flowCacheName) {
+        List<String> keys = Splitter.on(DELIMETER).splitToList(flowCacheName);
+        String policyRuleGroupKey = keys.get(0);
+        String subjectName = Splitter.on(KEY_DELIMETER).splitToList(policyRuleGroupKey).get(2);
+        return new SubjectName(subjectName);
+    }
+
+    public static RuleName resolveRuleNameFromFlowCacheName(String flowCacheName) {
+        List<String> keys = Splitter.on(DELIMETER).splitToList(flowCacheName);
+        String ruleName = keys.get(1);
+        return new RuleName(ruleName);
+    }
+
+    public static ClassifierName resolveClassifierNameFromFlowCacheName(String flowCacheName) {
+        List<String> keys = Splitter.on(DELIMETER).splitToList(flowCacheName);
+        String classifierName = keys.get(2);
+        return new ClassifierName(classifierName);
+    }
+
+    public static String resolveFlowCacheValue(String flowCacheName) {
+        List<String> keys = Splitter.on(DELIMETER).splitToList(flowCacheName);
+        return keys.get(3);
+    }
+}
old mode 100644 (file)
new mode 100755 (executable)
index 2c1835e..c3d95c8
@@ -33,7 +33,7 @@ module ofoverlay-provider-impl {
         config:java-name-prefix OFOverlayProvider;
     }
 
-    // Augments the 'configuration' choice node under modules/module.  
+    // Augments the 'configuration' choice node under modules/module.
     augment "/config:modules/config:module/config:configuration" {
         case ofoverlay-provider-impl {
             when "/config:modules/config:module/config:type = 'ofoverlay-provider-impl'";
@@ -83,8 +83,18 @@ module ofoverlay-provider-impl {
                     }
                 }
             }
+            // StatisticsManager service
+            container statistics-manager {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity gbpcfg:statistics-manager;
+                    }
+                }
+            }
 
             uses ofoverlay:initial-values;
+            //uses ofoverlay:sflow-values;
         }
     }
 }
old mode 100644 (file)
new mode 100755 (executable)
index ae4aeb1..b013b63
@@ -62,6 +62,7 @@ module ofoverlay {
         }
 
         uses initial-values;
+        uses sflow-values;
     }
 
     grouping initial-values {
@@ -75,6 +76,25 @@ module ofoverlay {
         }
     }
 
+    grouping sflow-values {
+        description
+            "Values for sFlow-RT collector setup";
+        container sflow-client-settings {
+            leaf gbp-ofoverlay-sflow-retrieve-interval {
+                description
+                    "Interval (seconds) for periodical flowcache data retrieve.";
+                type uint32;
+                default 20;
+            }
+            leaf gbp-ofoverlay-sflow-collector-uri {
+                description
+                    "URI of sFlow-RT collector, including schema, IP/domain, port. No trailing slash.";
+                mandatory true;
+                type string;
+            }
+        }
+    }
+
     grouping endpoint-location {
         description
             "The location for this endpoint in the overlay network";
old mode 100644 (file)
new mode 100755 (executable)
index a1fd3b8..ea5b03b
@@ -31,6 +31,7 @@ import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.groupbasedpolicy.api.PolicyValidatorRegistry;
+import org.opendaylight.groupbasedpolicy.api.StatisticsManager;
 import org.opendaylight.groupbasedpolicy.endpoint.EndpointRpcRegistry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -49,6 +50,7 @@ public class OFOverlayRendererTest {
     private EndpointRpcRegistry endpointRpcRegistry;
     private NotificationService notificationService;
     private PolicyValidatorRegistry policyValidatorRegistry;
+    private StatisticsManager statisticsManager;
     private short tableOffset;
     private CheckedFuture<Optional<OfOverlayConfig>, ReadFailedException> future;
     private ListenerRegistration<DataChangeListener> configReg;
@@ -62,6 +64,7 @@ public class OFOverlayRendererTest {
         endpointRpcRegistry = mock(EndpointRpcRegistry.class);
         notificationService = mock(NotificationService.class);
         policyValidatorRegistry = mock(PolicyValidatorRegistry.class);
+        statisticsManager = mock(StatisticsManager.class);
         tableOffset = 5;
         configReg = mock(ListenerRegistration.class);
         when(dataProvider.registerDataChangeListener(any(LogicalDatastoreType.class), any(InstanceIdentifier.class),
@@ -79,13 +82,13 @@ public class OFOverlayRendererTest {
         future = Futures.immediateCheckedFuture(Optional.<OfOverlayConfig> absent());
         when(readTransaction.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(future);
         renderer = new OFOverlayRenderer(dataProvider, rpcRegistry, notificationService, endpointRpcRegistry,
-                policyValidatorRegistry, tableOffset);
+                policyValidatorRegistry, statisticsManager, tableOffset);
     }
 
     @Test
     public void constructorTest() throws Exception {
         renderer.close();
-        verify(configReg, times(10)).close();
+        verify(configReg, times(11)).close();
     }
 
     @Test
index 724a813cd358ce88566c415652d582f8af04980d..cc267d2c9b8959accc7583364d86a51aed0cede6 100644 (file)
@@ -49,6 +49,7 @@ import org.opendaylight.groupbasedpolicy.dto.EpKey;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.EndpointListener;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
@@ -131,7 +132,7 @@ public class EndpointManagerTest {
         tenantId = mock(TenantId.class);
         endpointGroupId = mock(EndpointGroupId.class);
         l2BridgeDomainId = mock(L2BridgeDomainId.class);
-        MacAddress macAddress = mock(MacAddress.class);
+        MacAddress macAddress = new MacAddress("12:34:56:78:9a:bc");
         when(endpoint1.getTenant()).thenReturn(tenantId);
         when(endpoint1.getEndpointGroup()).thenReturn(endpointGroupId);
         when(endpoint1.getL2Context()).thenReturn(l2BridgeDomainId);
@@ -383,7 +384,7 @@ public class EndpointManagerTest {
         when(newL3Ep.getKey()).thenReturn(endpointL3Key);
         IpAddress ipAddress = mock(IpAddress.class);
         when(endpointL3Key.getIpAddress()).thenReturn(ipAddress);
-
+        when(newL3Ep.getIpAddress()).thenReturn(new IpAddress(new Ipv4Address("1.1.1.1")));
         manager.processL3Endpoint(null, newL3Ep);
         verify(endpointListener,never()).endpointUpdated(any(EpKey.class));
     }
@@ -404,7 +405,7 @@ public class EndpointManagerTest {
         when(newL3Ep.getKey()).thenReturn(endpointL3Key);
         IpAddress ipAddress = mock(IpAddress.class);
         when(endpointL3Key.getIpAddress()).thenReturn(ipAddress);
-
+        when(newL3Ep.getIpAddress()).thenReturn(new IpAddress(new Ipv4Address("1.1.1.1")));
         manager.processL3Endpoint(null, newL3Ep);
         verify(endpointListener,never()).endpointUpdated(any(EpKey.class));
     }
@@ -423,7 +424,7 @@ public class EndpointManagerTest {
 
         when(newL3Ep.getL2Context()).thenReturn(mock(L2BridgeDomainId.class));
         when(newL3Ep.getMacAddress()).thenReturn(mock(MacAddress.class));
-
+        when(newL3Ep.getIpAddress()).thenReturn(new IpAddress(new Ipv4Address("1.1.1.1")));
         manager.processL3Endpoint(null, newL3Ep);
         verify(endpointListener).endpointUpdated(any(EpKey.class));
     }
@@ -434,13 +435,14 @@ public class EndpointManagerTest {
         when(newL3Ep.getEndpointGroup()).thenReturn(mock(EndpointGroupId.class));
         when(newL3Ep.getL3Context()).thenReturn(mock(L3ContextId.class));
         when(newL3Ep.getIpAddress()).thenReturn(null);
-
+        when(newL3Ep.getIpAddress()).thenReturn(new IpAddress(new Ipv4Address("1.1.1.1")));
         manager.processL3Endpoint(null, newL3Ep);
         verify(endpointListener,never()).endpointUpdated(any(EpKey.class));
     }
 
     @Test
     public void updateEndpointL3TestDelete() throws Exception {
+        when(oldL3Ep.getIpAddress()).thenReturn(new IpAddress(new Ipv4Address("1.1.1.1")));
         manager.processL3Endpoint(oldL3Ep, null);
         verify(endpointListener).endpointUpdated(any(EpKey.class));
     }