Rate limits on uni port 74/49974/1
authorKonsta Pozdeev <konsta.pozdeev@hpe.com>
Wed, 14 Dec 2016 10:30:39 +0000 (12:30 +0200)
committerDavid Goldberg <gdavid@hpe.com>
Tue, 3 Jan 2017 15:10:06 +0000 (17:10 +0200)
Change-Id: I83e84008906d3b1ad6e670bf3b6545b37e072dcb
Signed-off-by: Konsta Pozdeev <konsta.pozdeev@hpe.com>
14 files changed:
dlux/cpeui/cpeui-module/src/main/resources/cpeui/admin.controller.js
dlux/cpeui/cpeui-module/src/main/resources/cpeui/admin.tpl.html
dlux/cpeui/cpeui-module/src/main/resources/cpeui/cpeui.controller.js
dlux/cpeui/cpeui-module/src/main/resources/cpeui/dialogs/AddProfile.tpl.html [new file with mode: 0644]
dlux/cpeui/cpeui-module/src/main/resources/cpeui/dialogs/LinkEvcUni.tpl.html
dlux/cpeui/cpeui-module/src/main/resources/cpeui/dialogs/LinkIpvcUni.tpl.html
dlux/cpeui/cpeui-module/src/main/resources/cpeui/services/cpeui.services.js
dlux/cpeui/cpeui-module/src/main/resources/cpeui/tenant.controller.js
dlux/cpeui/cpeui-module/src/main/resources/cpeui/tenant.tpl.html
legato-api/src/main/yang/mef-services.yang
netvirt/src/main/java/org/opendaylight/unimgr/mef/netvirt/EvcListener.java
netvirt/src/main/java/org/opendaylight/unimgr/mef/netvirt/IpvcListener.java
netvirt/src/main/java/org/opendaylight/unimgr/mef/netvirt/UniQosManager.java [new file with mode: 0644]
netvirt/src/main/resources/org/opendaylight/blueprint/netvirt-driver.xml

index 113eb176b097ebfddca4fae2543543045ba216fd..4d1426353fcf1d58e3065da622f78dfb599f6766 100644 (file)
@@ -39,6 +39,28 @@ define([ 'app/cpeui/cpeui.module' ], function(cpeui) {
           });
         };
 
+        // Profiles
+        $scope.profiles = [];
+        $scope.updateProfilesView = function() {
+          CpeuiSvc.getProfiles(function(profiles) {
+            $scope.profiles = profiles;
+          });
+        };
+
+        $scope.addProfile = new CpeuiDialogs.Dialog('AddProfile', {}, function(obj) {
+          CpeuiSvc.addProfile(obj['bw-profile'], obj.cir, obj.cbs, function() {
+            $scope.updateProfilesView();
+          });
+        });
+
+        $scope.deleteProfile = function(profileName) {
+          CpeuiDialogs.confirm(function() {
+            CpeuiSvc.deleteProfile(profileName, function() {
+              $scope.updateProfilesView();
+            });
+          });
+        };
+
         // CEs
         $scope.updateCesView = function() {
           CpeuiSvc.getCes(function(ces) {
@@ -195,6 +217,7 @@ define([ 'app/cpeui/cpeui.module' ], function(cpeui) {
           $scope.updateTenantView();
           $scope.updateCesView();
           $scope.updateUniView();
+          $scope.updateProfilesView()
         };
 
         $scope.updateView();
index 2903ebaeb07aa32d2e6f93be275eb18fb90ac715..c53b818ae491da7f4a4a13a7e0ed73274ee0b79c 100644 (file)
@@ -9,13 +9,16 @@
                                ng-click="setTab('admin',2)"><a id="evcs-configure-tab" href="#/cpeui/admin/cpes">
                                        <i class="icon-tasks"></i> CPEs (Devices)</a></li>
                        <li ng-class="{ active: isTabSet('admin',3)}"
-                               ng-click="setTab('admin',3);updateView()"><a id="dashboard-tab"  href="#/cpeui/admin/unis">
+                               ng-click="setTab('admin',3);updateView()"><a href="#/cpeui/admin/unis">
                                 <i class="icon-exchange"></i> UNIs</a>
                         </li>
                         <li ng-class="{ active: isTabSet('admin',4)}"
-                               ng-click="setTab('admin',4);updateNetworksView()"><a id="dashboard-tab"  href="#/cpeui/admin/networks">
+                               ng-click="setTab('admin',4);updateNetworksView()"><a href="#/cpeui/admin/networks">
                                <i class="icon-signal"></i> Networks</a>
                         </li>
+                        <li ng-class="{ active: isTabSet('admin',5)}" ng-click="setTab('admin',5);updateProfilesView()">
+                               <a href="#/cpeui/admin/profiles"><i class="icon-signal"></i> Profiles</a>
+                        </li>
                        <li id="refresh_btn" class="active refresh-btn"
                                ng-click="updateView()"><button class="btn add-row"> <i class="icon-refresh"></i> Refresh</button>
                                </li>
@@ -73,7 +76,7 @@
                                        <th colspan="2">Tenant</th>
                                </tr>
                        </thead>
-                       <tbody id="ces_table">
+                       <tbody>
                                <tr ng-repeat="item in unis | orderBy: '[\'uni-id\']'">
                                        <td ng-init="device = ces.filterByField('dev-id',item.device)[0]">{{ device["device-name"] ? device["device-name"] : item.device}}</td>
                                        <td>{{ item.prettyID }}</td>
                                        <th>Tenant</th>
                                </tr>
                        </thead>
-                       <tbody id="ces_table">
+                       <tbody>
                                <tr ng-repeat="svc in services ">                                       
                                        <td class="minimal-width">{{ svc['svc-id'] }}</td>
                                        <td class="minimal-width">{{ networkNames[svc['svc-id']] }}</td>                                        
                        </tbody>
                </table>                
        </div>
+       <div ng-show="isTabSet('admin',5)">
+               <div class="table-header">Profiles</div>
+               <table class="footable table table-striped">
+                       <thead>
+                               <tr>
+                                       <th>Profile Name</th>
+                                       <th>Committed Information Rate (Kb/s)</th>
+                                       <th>Committed Burst Size (bytes)</th>
+                                       <th></th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                               <tr ng-repeat="profile in profiles | orderBy: '[\'bw-profile\']'">
+                                       <td class="minimal-width">{{ profile['bw-profile'] }}</td>
+                                       <td class="minimal-width">{{ profile.cir }}</td>
+                                       <td class="minimal-width">{{ profile.cbs }}</td>
+                                       <td class="delete-tr">
+                                               <button class="btn btn-md btn-danger" ng-click="deleteProfile(profile['bw-profile'])">
+                                               <i class="icon-trash"></i>
+                                               <md-tooltip>Delete Profile</md-tooltip>
+                                               </button>
+                                       </td>
+                               </tr>
+                       </tbody>
+               </table>
+               <div>
+                       <a class="btn add-row" ng-click="addProfile.show($event)">Add Profile</a>
+               </div>
+       </div>
 </div>
index b4a92f0070b0e8e1640f8bda5863a6d0b03acc49..a381bcc9260b7368d32b18df88bdb6106a8b32c4 100644 (file)
@@ -21,7 +21,8 @@ define([].concat(modules).concat(services).concat(directives).concat(controllers
       "tenants" : 1,
       "cpes" : 2,
       "unis" : 3,
-      "networks" : 4
+      "networks" : 4,
+      "profiles" : 5
     }
 
     $scope.tab = {
diff --git a/dlux/cpeui/cpeui-module/src/main/resources/cpeui/dialogs/AddProfile.tpl.html b/dlux/cpeui/cpeui-module/src/main/resources/cpeui/dialogs/AddProfile.tpl.html
new file mode 100644 (file)
index 0000000..59b8a51
--- /dev/null
@@ -0,0 +1,46 @@
+<md-dialog class="cpe-dialog" aria-label="Create Profile" ng-cloak>
+       <md-toolbar>
+               <div class="md-toolbar-tools">
+                       <h2>Create Profile</h2>
+                       <span flex></span>
+                       <md-button class="md-icon-button" aria-label="Close dialog"
+                               ng-click="cancel()"> <i class="icon-remove-sign"></i> </md-button>
+               </div>
+       </md-toolbar>
+       <form name="projectForm" novalidate>
+               <md-dialog-content>
+                       <div layout="column" ng-cloak>
+                               <md-content layout-padding>
+                                       <md-input-container class="md-block">
+                                               <label>Profile Name</label>
+                                               <input name="profilename" ng-model="obj['bw-profile']">
+                                               <div ng-messages="projectForm.profilename.$error">
+                                                       <div ng-message="required">This is required!</div>
+                                               </div>
+                                       </md-input-container>
+                                       <md-input-container class="md-block">
+                                               <label>Committed Information Rate (Kb/s)</label>
+                                               <input type="number" required name="cir" ng-model="obj.cir" min="0">
+                                               <div ng-messages="projectForm.cir.$error">
+                                                       <div ng-message="required">Number is required!</div>
+                                                       <div ng-message="min">Number must be positive!</div>
+                                               </div>
+                                       </md-input-container>
+                                       <md-input-container class="md-block">
+                                               <label>Committed Burst Size (bytes)</label>
+                                               <input type="number" required name="cbs" ng-model="obj.cbs" min="0">
+                                               <div ng-messages="projectForm.cbs.$error">
+                                                       <div ng-message="required">Number is required!</div>
+                                                       <div ng-message="min">Number must be positive!</div>
+                                               </div>
+                                       </md-input-container>
+                               </md-content>
+                       </div>
+               </md-dialog-content>
+               <md-dialog-actions layout="row">
+                       <span flex></span>
+                       <md-button ng-click="cancel()"> Cancel </md-button>
+                       <md-button type="submit" ng-click="done(obj)"> Create </md-button>
+               </md-dialog-actions>
+       </form>
+</md-dialog>
\ No newline at end of file
index 240b2a4e4a0288a84d6271dc289afc7015109f42..0112793630bd33249239fc9f10892b74f502ca9e 100644 (file)
                        <md-option value="leaf" default>Leaf</md-option>
         </md-select>
       </md-input-container>
+      <md-input-container class="md-block">
+        <label>Profile</label>
+        <md-select ng-model="obj.profile_name" name="profile_name">
+               <md-option ng-value="undefined" > - None - </md-option>
+                       <md-option ng-repeat="profile in params.profiles | orderBy: '[\'bw-profile\']'" value="{{ profile['bw-profile'] }}" >{{ profile['bw-profile'] }} <span class="small">(CIR: {{profile.cir}}, CBS: {{profile.cbs}})</span></md-option>
+        </md-select>
+      </md-input-container>
     <input type="hidden" name="vlans" ng-model="obj.vlans">
     <div ng-if="params.svc.evc['preserve-ce-vlan-id']">
        Preserved VLAN: {{params.svc.evc['preserved-vlan']}}
index d86ed4c338bf80d55e84ee82f92ba4473d232a71..96360a7070f4685150500fde5b8f7bc55b0c6e4d 100644 (file)
         <md-select ng-model="obj.ip_uni" name="ip_uni" ng-disabled="!obj.uni">
                        <md-option ng-repeat="ipuni in obj.uni['ip-unis']['ip-uni'] " value="{{ ipuni['ip-uni-id'] }}" >{{ ipuni['ip-uni-id'] }} : {{ipuni['ip-address']}}{{ipuni.vlan ? (' (vlan: ' + ipuni.vlan+')') : ''}}</md-option>
         </md-select>
+      </md-input-container>
+      <md-input-container class="md-block">
+        <label>Profile</label>
+        <md-select ng-model="obj.profile_name" name="profile_name">
+               <md-option ng-value="undefined" > - None - </md-option>
+                       <md-option ng-repeat="profile in params.profiles | orderBy: '[\'bw-profile\']'" value="{{ profile['bw-profile'] }}" >{{ profile['bw-profile'] }} <span class="small">(CIR: {{profile.cir}}, CBS: {{profile.cbs}})</span></md-option>
+        </md-select>
       </md-input-container>      
   </md-content>
 </div>
index 44eaae9f166185e4d5a52853c80616d8dfcfba6f..5fd5744851f5e61096612064da7c2c6fb442952a 100644 (file)
@@ -46,6 +46,52 @@ define(['app/cpeui/cpeui.module'],function(cpeui) {
                 }
             });
         };
+
+        // Profiles
+        svc.getProfiles = function(callback) {
+          $http({
+              method:'GET',
+              url:"/restconf/config/mef-global:mef-global/profiles/ingress-bwp-flows/"
+          }).then(function successCallback(response) {
+              if (callback != undefined) {
+                  callback(response.data["ingress-bwp-flows"]["bwp-flow"]);
+              }
+          }, function errorCallback(response) {
+              if (response.status == 404) {
+                  callback([]);
+              }
+              console.log(response);
+          });
+      };
+
+      svc.addProfile = function(name, cir, cbs, callback){
+          $http({
+              method:'POST',
+              url:"/restconf/config/mef-global:mef-global/profiles/ingress-bwp-flows/",
+              data: {"bwp-flow":{
+                        "bw-profile" : name,
+                         "cir" : cir,
+                         "cbs" : cbs
+                    }}
+          }).then(function successCallback(response) {
+              if (callback != undefined) {
+                  callback();
+              }
+          });
+      };
+
+      svc.deleteProfile = function(name, callback) {
+          $http({
+              method:'DELETE',
+              url:"/restconf/config/mef-global:mef-global/profiles/ingress-bwp-flows/bwp-flow/"+name,
+          }).then(function successCallback(response) {
+              if (callback != undefined) {
+                  callback();
+              }
+          });
+      };
+
+        // CEs
         svc.addCe = function(id, name, callback) {
             $http({
                 method:'POST',
@@ -90,27 +136,41 @@ define(['app/cpeui/cpeui.module'],function(cpeui) {
 
         svc.getCes = function(callback) {
             var ces;
+            var operMap = {};
+
             $http({
                 method:'GET',
-                url:"/restconf/config/mef-topology:mef-topology/devices/"
+                url:"/restconf/operational/mef-topology:mef-topology/devices/"
             }).then(function successCallback(response) {
                 ces = response.data["devices"]["device"];
-                ces.forEach(function(c){
-                  c.displayName = c['device-name'] ? c['device-name'] : c['dev-id'];
+                ces.forEach(function(c) {
+                  c.displayName = c['dev-id'];
+                  operMap[c['dev-id']] = c;
+                });
+            }).finally(function() {
+                $http({
+                  method:'GET',
+                  url:"/restconf/config/mef-topology:mef-topology/devices/"
+                }).then(function(response){
+                  var confCes = response.data["devices"]["device"];
+                  confCes.forEach(function(c) {
+                    c.displayName = c['device-name'] ? c['device-name'] : c['dev-id'];
+                    if (operMap[c['dev-id']]) {
+                      for (var attrname in c) {
+                        operMap[c['dev-id']][attrname] = c[attrname];
+                      }
+                    } else {
+                      operMap[c['dev-id']] = c;
+                    }
+                  });
+                }).finally(function() {
+                  if (callback != undefined) {
+                    callback(Object.values(operMap));
+                  }
                 });
-                if (callback != undefined) {
-                    callback(ces);
-                }
-            }, function errorCallback(response) {
-              if (response.status == 404) {
-                  callback([]);
-                }
-                console.log(response);
             });
-
-            return ces;
-
         };
+
         svc.removeCe = function(ceid, callback) {
              $http({
                 method:'DELETE',
@@ -235,8 +295,6 @@ define(['app/cpeui/cpeui.module'],function(cpeui) {
 
         // IPVCs
         svc.addIpvc = function(ipvc, tenant, callback) {
-//          var uni_json = getJsonUnis(evc.unis);
-//          preserved-vlan
           var data = {
             "mef-service" :  {
               "svc-id" : ipvc.id,
@@ -245,9 +303,6 @@ define(['app/cpeui/cpeui.module'],function(cpeui) {
               "ipvc" : {
                 "ipvc-id" : ipvc.id,
                 "ipvc-type" : 'multipoint',
-//                "unis" : {
-//                  "uni" : uni_json
-//                },
               }
             }
           };
@@ -485,12 +540,15 @@ define(['app/cpeui/cpeui.module'],function(cpeui) {
             });
         };
 
-        svc.addIpvcUni = function(svcid, uni_id, ipuni_id, callback) {
+        svc.addIpvcUni = function(svcid, uni_id, ipuni_id, profile_name, callback) {
           var data = {"uni":{
                           "uni-id":uni_id,
                           "ip-uni-id":ipuni_id
                           }
-                      };          
+                      };
+          if (profile_name) {
+            data.uni["ingress-bw-profile"] = profile_name;
+          }
            $http({
               method:'PUT',
               url:"/restconf/config/mef-services:mef-services/mef-service/" + svcid + "/ipvc/unis/uni/"+uni_id+"/"+ipuni_id,
@@ -519,13 +577,16 @@ define(['app/cpeui/cpeui.module'],function(cpeui) {
       
       
       
-        svc.addEvcUni = function(svcid, uni_id, role, vlans, callback) {
+        svc.addEvcUni = function(svcid, uni_id, role, vlans, profile_name, callback) {
             var data = {"uni":{
                             "uni-id":uni_id,
                             "role":role,
                             "admin-state-enabled":true
                             }
                         };
+            if (profile_name) {
+              data.uni["ingress-bw-profile"] = profile_name;
+            }
             if (vlans != undefined) {
                 data.uni['evc-uni-ce-vlans'] = {"evc-uni-ce-vlan":[]}
                 for (var i=0; i< vlans.length; ++i) {
index 41698b4ec3fc35575b6ca0494717b759668f3b68..6ad9df21759d03807ee67170f2929f36b3740afe 100644 (file)
@@ -7,6 +7,7 @@ define([ 'app/cpeui/cpeui.module' ], function(cpeui) {
     $scope.ces = [];
     $scope.ipvcs = [];
     $scope.subnets = {};
+    $scope.profiles =[];
     $scope.cesDisplayNames = {};
     $scope.unisMap = {};
     $scope.networkNames = {};
@@ -47,6 +48,10 @@ define([ 'app/cpeui/cpeui.module' ], function(cpeui) {
           $scope.networkNames[net.uuid] = net.name;
         });
       });
+
+      CpeuiSvc.getProfiles(function(profiles) {
+        $scope.profiles = profiles;
+      });
     }
 
     $scope.updateUnis = function(callback) {
@@ -138,7 +143,7 @@ define([ 'app/cpeui/cpeui.module' ], function(cpeui) {
 
     $scope.linkIpvcUniDialog = new CpeuiDialogs.Dialog('LinkIpvcUni', {},
         function(obj) {
-          CpeuiSvc.addIpvcUni(obj.svc_id, obj.uni['uni-id'], obj.ip_uni,
+          CpeuiSvc.addIpvcUni(obj.svc_id, obj.uni['uni-id'], obj.ip_uni, obj.profile_name,
               function() {
                 $scope.updateEvcView();
               });
@@ -279,7 +284,7 @@ define([ 'app/cpeui/cpeui.module' ], function(cpeui) {
           if (!obj.role) {
             obj.role = "root";
           }
-          CpeuiSvc.addEvcUni(obj.svc_id, obj.uni_id, obj.role, obj.vlans,
+          CpeuiSvc.addEvcUni(obj.svc_id, obj.uni_id, obj.role, obj.vlans, obj.profile_name,
               function() {
                 $scope.updateEvcView();
               });
index 73626638f346c3800f1c9162e8272a5119577d61..0140a6ad778ceda09c2a445f5efd364d4e94eb25 100644 (file)
                                                                                                <i class="icon-minus"></i>
                                                                                        </button>
                                                                                </th>
-                                                                               <th>Device</th>
-                                                                               <th>UNI</th>
-                                                                               <th ng-if="item.isTree" >Role</th>
+                                                                               <th class="minimal-width">Device</th>
+                                                                               <th class="minimal-width">UNI</th>
+                                                                               <th class="minimal-width" ng-if="item.isTree" >Role</th>
                                                                                <th class="minimal-width">VLANs <span style="font-size:small;color:inherit;"> (click to edit)</span></th>
-                                                                               <th class="delete-tr"><button class="btn btn-md btn-info" ng-click="linkEvcUniDialog.show($event, {'svc':item,'unis':unis,'ces':ces})"> <i class="icon-plus"></i> </button></th>                                                                                
+                                                                               <th class="minimal-width">Profile</th>
+                                                                               <th class="delete-tr">
+                                                                                       <button class="btn btn-md btn-info" ng-click="linkEvcUniDialog.show($event, {svc:item, unis:unis, ces:ces, profiles:profiles})">
+                                                                                       <i class="icon-plus"></i>
+                                                                                       </button>
+                                                                               </th>
                                                                        </tr>
                                                                </thead>
                                                                <tbody>
                                                                        <tr ng-repeat-start="(ce, unis) in item.device2unis | orderBy : ce ">
-                                                                               <td colspan="2" rowspan="{{unis.length}}">{{ cesDisplayNames[ce] }}</td>
-                                                                               <td ng-repeat-start="uni in unis | orderBy: sortUni | limitTo :1">{{ uni.prettyID }}</td>
-                                                                               <td ng-if="item.isTree">{{ uni['role'] }}</td>
+                                                                               <td class="minimal-width" colspan="2" rowspan="{{unis.length}}">{{ cesDisplayNames[ce] }}</td>
+                                                                               <td class="minimal-width" ng-repeat-start="uni in unis | orderBy: sortUni | limitTo :1">{{ uni.prettyID }}</td>
+                                                                               <td class="minimal-width" ng-if="item.isTree">{{ uni['role'] }}</td>
                                                                                <td class="clickable" ng-click="!item.evc['preserve-ce-vlan-id'] ? editVlanDialog.show($event, {svcid:item['svc-id'], uniid:uni['uni-id'], vlans:uni.vlans}) : 0">
                                                                                {{ uni.vlans.join(', ') }} {{item.evc['preserve-ce-vlan-id'] ? '(Preserved)' : ''}}
                                                                                </td>
+                                                                               <td class="minimal-width">{{ uni['ingress-bw-profile'] }}</td>
                                                                                <td ng-repeat-end class="delete-tr" style="white-space: nowrap;">
                                                                                <button class="btn btn-md btn-danger" ng-click="deleteEvcUni(item['svc-id'], uni['uni-id'])"> <i class="icon-trash"></i> </button>
                                                                                </td>
@@ -75,6 +81,7 @@
                                                                                <td class="clickable" ng-click="!item.evc['preserve-ce-vlan-id'] ? editVlanDialog.show($event, {svcid:item['svc-id'], uniid:uni['uni-id'], vlans:uni.vlans}) : 0">
                                                                                {{ uni.vlans.join(', ') }} {{item.evc['preserve-ce-vlan-id'] ? '(Preserved)' : ''}}
                                                                                </td>
+                                                                               <td class="minimal-width">{{ uni['ingress-bw-profile'] }}</td>
                                                                                <td class="delete-tr" style="white-space: nowrap;">
                                                                                <button class="btn btn-md btn-danger" ng-click="deleteEvcUni(item['svc-id'], uni['uni-id'])"> <i class="icon-trash"></i> </button>
                                                                                </td>
                                                                                <th>Device</th>
                                                                                <th>UNI</th>
                                                                                <th>IP Address</th>
-                                                                               <th>vlan</th>
-                                                                               <th class="delete-tr"><button class="btn btn-md btn-info" ng-click="linkIpvcUniDialog.show($event, {'svc':ipvc,'unis':unis,'ces':ces})"> <i class="icon-plus"></i> </button></th>
+                                                                               <th>Vlan</th>
+                                                                               <th>Profile</th>
+                                                                               <th class="delete-tr"><button class="btn btn-md btn-info" ng-click="linkIpvcUniDialog.show($event, {svc:ipvc, unis:unis, ces:ces, profiles:profiles})"> <i class="icon-plus"></i> </button></th>
                                                                        </tr>
                                                                </thead>
                                                                <tbody>
-                                                                       <tr ng-repeat="ipuni in ipvc.ipvc.unis.uni">
+                                                                       <tr ng-repeat="ipuni in ipvc.ipvc.unis.uni | orderBy: 'prettyID'">
                                                                                <td colspan="2" ng-init="serviceIpuni = getMefInterfaceIpvc(ipuni['uni-id'],ipuni['ip-uni-id'])">{{ cesDisplayNames[ipuni.device] }}</td>
                                                                                <td>{{ ipuni.prettyID }}</td>
                                                                                <td>{{serviceIpuni['ip-address']}}</td>
                                                                                <td>{{serviceIpuni.vlan}}</td>
+                                                                               <td class="minimal-width">{{ ipuni['ingress-bw-profile'] }}</td>
                                                                                <td class="delete-tr"><button class="btn btn-md btn-danger" ng-click="deleteIpvcUni(ipvc['svc-id'], ipuni['uni-id'], ipuni['ip-uni-id'])"> <i class="icon-trash"></i> </button></td>
                                                                        </tr>                                                                                                                                           
                                                                </tbody>
index 13b27c50628a97220ddcaade1f17012c32b13cf3..cba6a56041ef8dfd5d2ae29282d9c8bccfab9214 100644 (file)
@@ -89,6 +89,9 @@ module mef-services {
                 leaf ip-uni-id {
                   type mef-types:identifier45;
                 }
+                leaf ingress-bw-profile {
+                    type mef-types:identifier45;
+                }
 
                 container evc-uni-ce-vlans {
                   description
@@ -680,6 +683,9 @@ module mef-services {
                     }
                   }
                 }
+                leaf ingress-bw-profile {
+                    type mef-types:identifier45;
+                }
                 container ingress-bwp-flows-per-cos {
                   presence "Use Ingress Bandwidth Profiles Per CoS";
                   description
index 68ea369d431e5974ac3f4da18f752910ec54d958..852c184cee801c53a4de55cd391a0d1c4bce008c 100644 (file)
@@ -45,10 +45,13 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
     private static final Logger log = LoggerFactory.getLogger(EvcListener.class);
     private ListenerRegistration<EvcListener> evcListenerRegistration;
     private final IUniPortManager uniPortManager;
+    private final UniQosManager uniQosManager;
 
-    public EvcListener(final DataBroker dataBroker, final UniPortManager uniPortManager) {
+    public EvcListener(final DataBroker dataBroker, final UniPortManager uniPortManager,
+            final UniQosManager uniQosManager) {
         super(dataBroker);
         this.uniPortManager = uniPortManager;
+        this.uniQosManager = uniQosManager;
         registerListener();
     }
 
@@ -111,6 +114,7 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
                 for (Uni uni : data.getUnis().getUni()) {
                     createUniElanInterfaces(evcId, instanceName, uni, isEtree);
                 }
+                updateQos(data.getUnis().getUni());
             }
         } catch (final Exception e) {
             log.error("Add evc failed !", e);
@@ -121,9 +125,8 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
         try {
             Evc data = removedDataObject.getRootNode().getDataBefore();
             InstanceIdentifier<Evc> evcId = removedDataObject.getRootPath().getRootIdentifier();
-            List<Uni> uniToRemove = data.getUnis() != null && data.getUnis().getUni() != null
-                    ? data.getUnis().getUni() : Collections.emptyList();
-
+            List<Uni> uniToRemove = data.getUnis() != null && data.getUnis().getUni() != null ? data.getUnis().getUni()
+                    : Collections.emptyList();
 
             synchronized (data.getEvcId().getValue().intern()) {
                 EvcElan evcElan = getOperEvcElan(evcId);
@@ -136,6 +139,7 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
                 for (Uni uni : uniToRemove) {
                     removeUniElanInterfaces(evcId, instanceName, uni);
                 }
+                updateQos(uniToRemove);
 
                 log.info("Removing elan instance: " + instanceName);
                 NetvirtUtils.deleteElanInstance(dataBroker, instanceName);
@@ -170,12 +174,14 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
                 for (Uni uni : uniToRemove) {
                     removeUniElanInterfaces(evcId, instanceName, uni);
                 }
+                updateQos(uniToRemove);
 
                 List<Uni> uniToCreate = new ArrayList<>(updateUni);
                 uniToCreate.removeAll(originalUni);
                 for (Uni uni : uniToCreate) {
                     createUniElanInterfaces(evcId, instanceName, uni, isEtree);
                 }
+                updateQos(uniToCreate);
             }
         } catch (final Exception e) {
             log.error("Update evc failed !", e);
@@ -205,6 +211,8 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
             log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
             NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
                     isEtree);
+            uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
+                    uni.getIngressBwProfile());
             setOperEvcElanPort(evcId, instanceName, interfaceName);
         } else {
             for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
@@ -218,6 +226,8 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
                 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
                 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
                         isEtree);
+                uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
+                        uni.getIngressBwProfile());
                 setOperEvcElanPort(evcId, instanceName, interfaceName);
             }
         }
@@ -242,7 +252,7 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
                         interfaceName);
                 return;
             }
-            removeElanInterface(evcId, interfaceName);
+            removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
         } else {
             for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
                 Long vlan = safeCastVlan(ceVlan.getVid());
@@ -252,19 +262,21 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
                             vlan, interfaceName);
                     return;
                 }
-                removeElanInterface(evcId, interfaceName);
+                removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
             }
         }
     }
 
-    private void removeElanInterface(InstanceIdentifier<Evc> identifier, String interfaceName) {
+    private void removeElanInterface(InstanceIdentifier<Evc> identifier, String uniId, String interfaceName) {
         log.info("Removing elan interface: " + interfaceName);
+        uniQosManager.unMapUniPortBandwidthLimits(uniId, interfaceName);
         NetvirtUtils.deleteElanInterface(dataBroker, interfaceName);
 
         EvcElan evcElan = getOperEvcElan(identifier);
         if (evcElan == null) {
             log.error("Removing non-operational Elan interface {}", interfaceName);
         }
+
         deleteOperEvcElanPort(identifier, interfaceName);
     }
 
@@ -314,7 +326,8 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
         InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
         EvcElan evcElan = getOperEvcElan(identifier);
         EvcElanBuilder evcElanBuilder = evcElan != null ? new EvcElanBuilder(evcElan) : new EvcElanBuilder();
-        List<ElanPorts> exPorts =  evcElan != null && evcElan.getElanPorts() != null ? evcElan.getElanPorts() : new ArrayList<>();
+        List<ElanPorts> exPorts = evcElan != null && evcElan.getElanPorts() != null ? evcElan.getElanPorts()
+                : new ArrayList<>();
 
         ElanPortsBuilder portB = new ElanPortsBuilder();
         portB.setPortId(elanPort);
@@ -342,4 +355,8 @@ public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
         MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
     }
 
+    private void updateQos(List<Uni> uniToUpdate) {
+        uniToUpdate.forEach(u -> uniQosManager.setUniBandwidthLimits(u.getUniId()));
+    }
+
 }
index 4fdba752d74b70ac030b2b96e95b80b5145091d4..4626a53a046ced3ad9069a2c97c0e7a9938c7eff 100644 (file)
@@ -40,14 +40,15 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
     private static final Logger Log = LoggerFactory.getLogger(IpvcListener.class);
     private final IUniPortManager uniPortManager;
     private final ISubnetManager subnetManager;
+    private final UniQosManager uniQosManager;
     private ListenerRegistration<IpvcListener> ipvcListenerRegistration;
 
     public IpvcListener(final DataBroker dataBroker, final IUniPortManager uniPortManager,
-            final ISubnetManager subnetManager) {
+            final ISubnetManager subnetManager, final UniQosManager uniQosManager) {
         super(dataBroker);
         this.uniPortManager = uniPortManager;
         this.subnetManager = subnetManager;
-
+        this.uniQosManager = uniQosManager;
         registerListener();
     }
 
@@ -115,12 +116,7 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
                 }
                 MdsalUtils.commitTransaction(tx);
             }
-            for (Uni uni : unis) {
-                IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uni.getUniId(), uni.getIpUniId(),
-                        LogicalDatastoreType.CONFIGURATION);
-                createDirectSubnet(uni, ipUni);
-                subnetManager.assignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
-            }
+            createUnis(ipvcId, unis);
         } catch (final Exception e) {
             Log.error("Add ipvc failed !", e);
         }
@@ -141,7 +137,7 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
                 // remove elan/vpn interfaces
                 // must be in different transactios
                 WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
-                removeUni(ipvcId, operIpvcVpn, ipvc.getUnis().getUni(), tx);
+                removeUnis(ipvcId, operIpvcVpn, ipvc.getUnis().getUni(), tx);
                 MdsalUtils.commitTransaction(tx);
                 // Let to work for listeners
                 // TODO : change to listener
@@ -157,7 +153,7 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
         }
     }
 
-    private void removeUni(InstanceIdentifier<Ipvc> ipvcId, IpvcVpn operIpvcVpn, List<Uni> uniToRemove,
+    private void removeUnis(InstanceIdentifier<Ipvc> ipvcId, IpvcVpn operIpvcVpn, List<Uni> uniToRemove,
             WriteTransaction tx) {
         if (uniToRemove == null) {
             Log.trace("No UNI's to remove");
@@ -176,6 +172,17 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
             subnetManager.unAssignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
             removeInterfaces(ipvcId, operIpvcVpn, uni, ipUni, tx);
         }
+        updateQos(uniToRemove);
+    }
+
+    private void createUnis(InstanceIdentifier<Ipvc> ipvcId, List<Uni> uniToCreate) {
+        for (Uni uni : uniToCreate) {
+            IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uni.getUniId(), uni.getIpUniId(),
+                    LogicalDatastoreType.CONFIGURATION);
+            createDirectSubnet(uni, ipUni);
+            subnetManager.assignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
+        }
+        updateQos(uniToCreate);
     }
 
     private void updateIpvc(DataTreeModification<Ipvc> modifiedDataObject) {
@@ -199,7 +206,7 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
                 WriteTransaction txRemove = MdsalUtils.createTransaction(dataBroker);
                 List<Uni> uniToRemove = new ArrayList<>(originalUni);
                 uniToRemove.removeAll(updateUni);
-                removeUni(ipvcId, operIpvcVpn, uniToRemove, txRemove);
+                removeUnis(ipvcId, operIpvcVpn, uniToRemove, txRemove);
                 MdsalUtils.commitTransaction(txRemove);
 
                 WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
@@ -210,12 +217,7 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
                 }
                 MdsalUtils.commitTransaction(tx);
 
-                for (Uni uni : uniToCreate) {
-                    IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uni.getUniId(), uni.getIpUniId(),
-                            LogicalDatastoreType.CONFIGURATION);
-                    createDirectSubnet(uni, ipUni);
-                    subnetManager.assignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
-                }
+                createUnis(ipvcId, uniToCreate);
             }
 
         } catch (final Exception e) {
@@ -250,6 +252,9 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
         IpAddress ipAddress = new IpAddress(srcIpAddressStr.toCharArray());
 
         String interfaceName = createElanInterface(vpnName, ipvcId, uniId, elanName, vlan, ipAddress, tx);
+
+        uniQosManager.mapUniPortBandwidthLimits(uniId, interfaceName, uniInService.getIngressBwProfile());
+
         createVpnInterface(vpnName, uni, ipUni, interfaceName, elanName, tx);
         MefServicesUtils.addOperIpvcVpnElan(ipvcId, vpnName, uniInService.getUniId(), uniInService.getIpUniId(),
                 elanName, interfaceName, null, tx);
@@ -322,7 +327,9 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
         NetvirtVpnUtils.removeVpnInterfaceAdjacencies(dataBroker, vpnName, vpnElans.getElanPort());
         // TODO : change to listener
         NetvirtUtils.safeSleep();
+        uniQosManager.unMapUniPortBandwidthLimits(uniId, vpnElans.getElanPort());
         removeElan(vpnElans, uniId, ipUni, tx);
+        // record Uni bw limits
         removeVpnInterface(vpnName, vpnElans, uniId, ipUni, tx);
         MefServicesUtils.removeOperIpvcElan(dataBroker, ipvcId, ipvcVpn.getVpnId(), uniInService.getUniId(),
                 uniInService.getIpUniId(), vpnElans.getElanId(), vpnElans.getElanPort());
@@ -358,4 +365,8 @@ public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
                 ipUni.getIpUniId(), subnetPrefix);
         MdsalUtils.delete(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
     }
+
+    private void updateQos(List<Uni> uniToUpdate) {
+        uniToUpdate.forEach(u -> uniQosManager.setUniBandwidthLimits(u.getUniId()));
+    }
 }
diff --git a/netvirt/src/main/java/org/opendaylight/unimgr/mef/netvirt/UniQosManager.java b/netvirt/src/main/java/org/opendaylight/unimgr/mef/netvirt/UniQosManager.java
new file mode 100644 (file)
index 0000000..8520004
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2016 Hewlett Packard Enterprise, Co. 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.unimgr.mef.netvirt;
+
+import com.google.common.base.Optional;
+
+import jline.internal.Log;
+
+import java.math.BigInteger;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.MefGlobal;
+import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.mef.global.Profiles;
+import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.mef.global.bwp.flows.group.BwpFlow;
+import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.mef.global.bwp.flows.group.BwpFlowKey;
+import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.mef.global.profiles.IngressBwpFlows;
+import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.physical.layers.links.Link;
+import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.Identifier45;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UniQosManager {
+    private static final Logger LOG = LoggerFactory.getLogger(UniQosManager.class);
+    private OdlInterfaceRpcService odlInterfaceRpcService;
+    private DataBroker dataBroker;
+    private final Long noLimit = 0l;
+
+    // key in first map is uniId, key in second map is logical portId
+    private ConcurrentHashMap<String, ConcurrentHashMap<String, BandwidthLimits>> uniPortBandwidthLimits;
+
+    // map of current values per uni
+    private ConcurrentHashMap<String, BandwidthLimits> uniBandwidthLimits;
+    
+    private ConcurrentHashMap<String, BigInteger> uniToDpn;
+
+    public UniQosManager(final DataBroker dataBroker, OdlInterfaceRpcService odlInterfaceRpcService) {
+        this.dataBroker = dataBroker;
+        this.odlInterfaceRpcService = odlInterfaceRpcService;
+        this.uniPortBandwidthLimits = new ConcurrentHashMap<>();
+        this.uniBandwidthLimits = new ConcurrentHashMap<>();
+        this.uniToDpn = new ConcurrentHashMap<>();
+    }
+
+    public void mapUniPortBandwidthLimits(String uniId, String portId, Long maxKbps, Long maxBurstKb) {
+        Log.info("Record rate limits for Uni {} port {} maxKbps {} maxBurstKb {}", uniId, portId, maxKbps, maxBurstKb);
+        uniPortBandwidthLimits.putIfAbsent(uniId, new ConcurrentHashMap<>());
+        ConcurrentHashMap<String, BandwidthLimits> uniMap = uniPortBandwidthLimits.get(uniId);
+        uniMap.put(portId, new BandwidthLimits(maxKbps, maxBurstKb));
+    }
+
+    public void mapUniPortBandwidthLimits(String uniId, String portId, Identifier45 bwProfile) {
+        Long maxKbps = noLimit;
+        Long maxBurstKb = noLimit;
+        if (bwProfile != null) {
+
+            Optional<BwpFlow> bwFlowOp = MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                    getBwFlowInstanceIdentifier(bwProfile));
+            if (!bwFlowOp.isPresent()) {
+                Log.trace("Can't read bw profile {} for Uni {}", bwProfile, uniId);
+                return;
+            }
+            // Kbytes per second
+            maxKbps = bwFlowOp.get().getCir().getValue();
+            // burst in bytes, ovs requires in Kb
+            maxBurstKb = bwFlowOp.get().getCbs().getValue() / 1000;
+            Log.info("Record rate limits for Uni {} Profile {}", uniId, bwProfile);
+        }
+        mapUniPortBandwidthLimits(uniId, portId, maxKbps, maxBurstKb);
+    }
+
+    public void unMapUniPortBandwidthLimits(String uniId, String portId) {
+        Log.debug("Delete rate limits for Uni {} port {}", uniId, portId);
+        ConcurrentHashMap<String, BandwidthLimits> uniMap = uniPortBandwidthLimits.get(uniId);
+        if (uniMap == null) {
+            Log.error("Trying to delete limits for non-exsting uni {}", uniId);
+            return;
+        }
+        uniMap.remove(portId);
+        if (uniMap.isEmpty()) {
+            uniMap.put(portId, new BandwidthLimits(noLimit, noLimit));
+        }
+    }
+
+    public void setUniBandwidthLimits(Identifier45 uniIden) {
+        String uniId = uniIden.getValue();
+        if (!uniPortBandwidthLimits.containsKey(uniId)) {
+            Log.debug("Uni {} doesn't have rate limits configured", uniId);
+            return;
+        }
+        Iterator<String> uniPorts = uniPortBandwidthLimits.get(uniId).keySet().iterator();
+        if (uniPorts == null || !uniPorts.hasNext()) {
+            Log.debug("Uni {} doesn't have rate limits configured", uniId);
+            return;
+        }
+        String logicalPort = uniPorts.next();
+
+        BandwidthLimits newLimits = recalculateLimitsForUni(uniId, uniPortBandwidthLimits.get(uniId));
+        if (newLimits.equals(uniBandwidthLimits.get(uniId))) {
+            Log.debug("Uni {} rate limits has not changed", uniId);
+            return;
+        }
+
+        setPortBandwidthLimits(uniId, logicalPort, newLimits.getMaxKbps(), newLimits.getMaxBurstKb());
+        uniBandwidthLimits.put(uniId, newLimits);
+    }
+
+    private BandwidthLimits recalculateLimitsForUni(String uniId,
+            ConcurrentHashMap<String, BandwidthLimits> uniLimits) {
+        Long sumOfRate = noLimit;
+        Long sumOfBurst = noLimit;
+        Boolean hasNullRate = false;
+        Boolean hasNullBurst = false;
+
+        if (uniLimits == null || uniLimits.keySet() == null) {
+            return new BandwidthLimits(sumOfRate, sumOfBurst);
+        }
+
+        for (BandwidthLimits v : uniLimits.values()) {
+            if (v.maxKbps == null) {
+                hasNullRate = true;
+                break;
+            }
+            if (v.maxBurstKb == null) {
+                hasNullBurst = true;
+            }
+            sumOfRate = sumOfRate + v.maxKbps;
+            sumOfBurst = sumOfBurst + v.maxBurstKb;
+
+        }
+        if (hasNullRate) {
+            sumOfRate = noLimit;
+            sumOfBurst = noLimit;
+        } else if (hasNullBurst) {
+            sumOfBurst = noLimit;
+        }
+        return new BandwidthLimits(sumOfRate, sumOfBurst);
+    }
+
+    private void setPortBandwidthLimits(String uniId, String logicalPortId, Long maxKbps, Long maxBurstKb) {
+        LOG.trace("Setting bandwidth limits {} {} on Port {}", maxKbps, maxBurstKb, logicalPortId);
+
+        BigInteger dpId = BigInteger.ZERO;
+        if(uniToDpn.containsKey(uniId)) {
+            dpId = uniToDpn.get(uniId);
+        } else {        
+            dpId = getDpnForInterface(odlInterfaceRpcService, logicalPortId);
+            uniToDpn.put(uniId, dpId);
+        }
+        if (dpId.equals(BigInteger.ZERO)) {
+            LOG.error("DPN ID for interface {} not found", logicalPortId);
+            return;
+        }
+
+        OvsdbBridgeRef bridgeRefEntry = getBridgeRefEntryFromOperDS(dpId, dataBroker);
+        Optional<Node> bridgeNode = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL,
+                bridgeRefEntry.getValue().firstIdentifierOf(Node.class), dataBroker);
+        if (bridgeNode == null) {
+            LOG.error("Bridge ref for interface {} not found", logicalPortId);
+            return;
+        }
+
+        String physicalPort = getPhysicalPortForUni(dataBroker, uniId);
+        if (physicalPort == null) {
+            LOG.error("Physical port for interface {} not found", logicalPortId);
+            return;
+        }
+
+        TerminationPoint tp = getTerminationPoint(bridgeNode.get(), physicalPort);
+        if (tp == null) {
+            LOG.error("Termination point for port {} not found", physicalPort);
+            return;
+        }
+
+        OvsdbTerminationPointAugmentation ovsdbTp = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+        OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
+        tpAugmentationBuilder.setName(ovsdbTp.getName());
+        tpAugmentationBuilder.setIngressPolicingRate(maxKbps);
+        tpAugmentationBuilder.setIngressPolicingBurst(maxBurstKb);
+
+        TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
+        tpBuilder.setKey(tp.getKey());
+        tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
+        MdsalUtils.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.create(NetworkTopology.class)
+                        .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
+                        .child(Node.class, bridgeNode.get().getKey())
+                        .child(TerminationPoint.class, new TerminationPointKey(tp.getKey())),
+                tpBuilder.build());
+    }
+
+    private static TerminationPoint getTerminationPoint(Node bridgeNode, String portName) {
+        for (TerminationPoint tp : bridgeNode.getTerminationPoint()) {
+            String tpIdStr = tp.getTpId().getValue();
+            if (tpIdStr != null && tpIdStr.equals(portName))
+                return tp;
+        }
+        return null;
+    }
+
+    private static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
+        BigInteger nodeId = BigInteger.ZERO;
+        try {
+            GetDpidFromInterfaceInput dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
+            Future<RpcResult<GetDpidFromInterfaceOutput>> dpIdOutput = interfaceManagerRpcService
+                    .getDpidFromInterface(dpIdInput);
+            RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
+            if (dpIdResult.isSuccessful()) {
+                nodeId = dpIdResult.getResult().getDpid();
+            } else {
+                LOG.error("Could not retrieve DPN Id for interface {}", ifName);
+            }
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            LOG.error("Exception when getting dpn for interface {}", ifName, e);
+        }
+        return nodeId;
+    }
+
+    private static String getPhysicalPortForUni(DataBroker dataBroker, String uniId) {
+        String nodeId = null;
+        try {
+            Link link = MefInterfaceUtils.getLink(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
+            String parentInterfaceName = MefInterfaceUtils.getTrunkParentName(link);
+            return parentInterfaceName.split(":")[1];
+        } catch (Exception e) {
+            LOG.error("Exception when getting physical port for Uni {}", uniId, e);
+        }
+        return nodeId;
+    }
+
+    private static BridgeRefEntry getBridgeRefEntryFromOperDS(InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid,
+            DataBroker dataBroker) {
+        Optional<BridgeRefEntry> bridgeRefEntryOptional = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                dpnBridgeEntryIid);
+        if (!bridgeRefEntryOptional.isPresent()) {
+            return null;
+        }
+        return bridgeRefEntryOptional.get();
+    }
+
+    private static OvsdbBridgeRef getBridgeRefEntryFromOperDS(BigInteger dpId, DataBroker dataBroker) {
+        BridgeRefEntryKey bridgeRefEntryKey = new BridgeRefEntryKey(dpId);
+        InstanceIdentifier<BridgeRefEntry> bridgeRefEntryIid = getBridgeRefEntryIdentifier(bridgeRefEntryKey);
+        BridgeRefEntry bridgeRefEntry = getBridgeRefEntryFromOperDS(bridgeRefEntryIid, dataBroker);
+        return (bridgeRefEntry != null) ? bridgeRefEntry.getBridgeReference() : null;
+    }
+
+    private static InstanceIdentifier<BridgeRefEntry> getBridgeRefEntryIdentifier(BridgeRefEntryKey bridgeRefEntryKey) {
+        InstanceIdentifier.InstanceIdentifierBuilder<BridgeRefEntry> bridgeRefEntryInstanceIdentifierBuilder = InstanceIdentifier
+                .builder(BridgeRefInfo.class).child(BridgeRefEntry.class, bridgeRefEntryKey);
+        return bridgeRefEntryInstanceIdentifierBuilder.build();
+    }
+
+    private static InstanceIdentifier<BwpFlow> getBwFlowInstanceIdentifier(Identifier45 bwProfile) {
+        InstanceIdentifier.InstanceIdentifierBuilder<BwpFlow> bwProfileInstanceIdentifierBuilder = InstanceIdentifier
+                .builder(MefGlobal.class).child(Profiles.class).child(IngressBwpFlows.class)
+                .child(BwpFlow.class, new BwpFlowKey(bwProfile));
+        return bwProfileInstanceIdentifierBuilder.build();
+    }
+
+    private class BandwidthLimits {
+        private final Long maxKbps;
+        private final Long maxBurstKb;
+
+        public BandwidthLimits(Long maxKbps, Long maxBurstKb) {
+            this.maxKbps = replaceNull(maxKbps);
+            this.maxBurstKb = replaceNull(maxBurstKb);
+        }
+
+        public Long getMaxKbps() {
+            return maxKbps;
+        }
+
+        public Long getMaxBurstKb() {
+            return maxBurstKb;
+        }
+
+        private Long replaceNull(Long value) {
+            return (value == null) ? Long.valueOf(0) : value;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            BandwidthLimits other = (BandwidthLimits) obj;
+            if (!getOuterType().equals(other.getOuterType()))
+                return false;
+            if (maxBurstKb == null) {
+                if (other.maxBurstKb != null)
+                    return false;
+            } else if (!maxBurstKb.equals(other.maxBurstKb))
+                return false;
+            if (maxKbps == null) {
+                if (other.maxKbps != null)
+                    return false;
+            } else if (!maxKbps.equals(other.maxKbps))
+                return false;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "BandwidthLimitsBandwidthLimitsalues [maxKbps=" + maxKbps + ", maxBurstKb=" + maxBurstKb + "]";
+        }
+
+        private UniQosManager getOuterType() {
+            return UniQosManager.this;
+        }
+    }
+}
index 281b315737931b3243ce5c0d1f10cd7775b776d8..1cd2c52f5e9856ffc9f94ec0a5e7734e51c4da7c 100644 (file)
@@ -1,52 +1,60 @@
-<!-- Copyright (c) 2016 Hewlett Packard Enterprise, Co. 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 -->
+<!-- Copyright (c) 2016 Hewlett Packard Enterprise, Co. 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 -->
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-    xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
-    odl:use-default-for-reference-types="true">
-
-    <reference id="dataBroker"
-        interface="org.opendaylight.controller.md.sal.binding.api.DataBroker" />
-    <reference id="notificationPublishService"
-        interface="org.opendaylight.controller.md.sal.binding.api.NotificationPublishService" />
-    <odl:rpc-service id="odlArputilService"
-        interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService" />
-
-
-    <bean id="uniPortManager" class="org.opendaylight.unimgr.mef.netvirt.UniPortManager">
-        <argument ref="dataBroker" />
-    </bean>
-
-    <bean id="nodeConnectorListener"
-        class="org.opendaylight.unimgr.mef.netvirt.NodeConnectorListener">
-        <argument ref="dataBroker" />
-        <argument ref="uniPortManager" />
-        <argument value="false" />
-    </bean>
-
-    <bean id="evcListener" class="org.opendaylight.unimgr.mef.netvirt.EvcListener">
-        <argument ref="dataBroker" />
-        <argument ref="uniPortManager" />
-    </bean>
-
-    <bean id="ipvcListener" class="org.opendaylight.unimgr.mef.netvirt.IpvcListener">
-        <argument ref="dataBroker" />
-        <argument ref="uniPortManager" />
-        <argument ref="subnetListener" />
-    </bean>
-
-    <bean id="subnetListener" class="org.opendaylight.unimgr.mef.netvirt.SubnetListener">
-        <argument ref="dataBroker" />
-        <argument ref="notificationPublishService" />
-        <argument ref="qwMacListener" />
-        <argument value="5" />                         
-    </bean>
-
-    <bean id="qwMacListener" class="org.opendaylight.unimgr.mef.netvirt.GwMacListener">
-        <argument ref="dataBroker" />
-        <argument ref="odlArputilService" />
-        <argument value="10" />
-    </bean>
+       xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+       odl:use-default-for-reference-types="true">
+
+       <reference id="dataBroker"
+               interface="org.opendaylight.controller.md.sal.binding.api.DataBroker" />
+       <reference id="notificationPublishService"
+               interface="org.opendaylight.controller.md.sal.binding.api.NotificationPublishService" />
+       <odl:rpc-service id="odlArputilService"
+               interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService" />
+       <odl:rpc-service id="odlInterfaceRpcService"
+               interface="org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService" />
+
+       <bean id="uniPortManager" class="org.opendaylight.unimgr.mef.netvirt.UniPortManager">
+               <argument ref="dataBroker" />
+       </bean>
+
+       <bean id="nodeConnectorListener"
+               class="org.opendaylight.unimgr.mef.netvirt.NodeConnectorListener">
+               <argument ref="dataBroker" />
+               <argument ref="uniPortManager" />
+               <argument value="false" />
+       </bean>
+
+       <bean id="evcListener" class="org.opendaylight.unimgr.mef.netvirt.EvcListener">
+               <argument ref="dataBroker" />
+               <argument ref="uniPortManager" />
+               <argument ref="uniQosManager" />
+       </bean>
+
+       <bean id="ipvcListener" class="org.opendaylight.unimgr.mef.netvirt.IpvcListener">
+               <argument ref="dataBroker" />
+               <argument ref="uniPortManager" />
+               <argument ref="subnetListener" />
+               <argument ref="uniQosManager" />
+       </bean>
+
+       <bean id="subnetListener" class="org.opendaylight.unimgr.mef.netvirt.SubnetListener">
+               <argument ref="dataBroker" />
+               <argument ref="notificationPublishService" />
+               <argument ref="qwMacListener" />
+               <argument value="5" />
+       </bean>
+
+       <bean id="qwMacListener" class="org.opendaylight.unimgr.mef.netvirt.GwMacListener">
+               <argument ref="dataBroker" />
+               <argument ref="odlArputilService" />
+               <argument value="10" />
+       </bean>
+
+       <bean id="uniQosManager" class="org.opendaylight.unimgr.mef.netvirt.UniQosManager">
+               <argument ref="dataBroker" />
+               <argument ref="odlInterfaceRpcService" />
+       </bean>
 </blueprint>