Added new REST API for ONOS to get group stats of specfic group, Added CLI command 'show switch <dpid> group <groupId>' to stats of specified group
diff --git a/cli/cli/desc/version200/policy.py b/cli/cli/desc/version200/policy.py
index 57c29ae..eac0209 100644
--- a/cli/cli/desc/version200/policy.py
+++ b/cli/cli/desc/version200/policy.py
@@ -254,7 +254,7 @@
'proc' : 'create-policy',
},
),
- 'completion' : 'tunnel-id-completion',
+ 'completion' : 'tunnelid-completion',
'field' : 'tunnel-id',
'type' : 'identifier',
'syntax-help' : 'Enter tunnel id',
diff --git a/cli/cli/desc/version200/switch.py b/cli/cli/desc/version200/switch.py
index 7857329..a78b184 100755
--- a/cli/cli/desc/version200/switch.py
+++ b/cli/cli/desc/version200/switch.py
@@ -211,13 +211,6 @@
'short-help' : 'Show requested item by querying switch',
'doc' : 'switch|realtime-+',
},
- #{
- # 'field' : 'detail',
- # 'optional' : True,
- # 'type' : 'enum',
- # 'values' : ('details','brief'),
- # 'doc' : 'format|+',
- #},
),
(
{
@@ -261,18 +254,27 @@
'format' : 'realtime_%(realtimestats)s_%(tabletype)s_flow',
'doc' : 'format|+',
},
- #{
- # 'field' : 'tableflow',
- # 'type' : 'enum',
- # 'values' : ('flow',
- # ),
- # 'action' : 'display-rest',
- # 'url' : 'realtimestats/%(realtimestats)s/%(tabletype)s/%(tableflow)s/%(dpid)s/',
- # 'rest-type' : 'dict-of-list-of-switch',
- # 'format' : 'realtime_%(realtimestats)s_%(tabletype)s_flow',
- # 'short-help' : 'Show requested item by querying switch',
- # 'doc' : 'switch|realtime-+',
- # },
+ ),
+ (
+ {
+ 'field' : 'realtimestats',
+ 'type' : 'enum',
+ 'values' : 'group',
+ },
+ {
+ 'field' : 'groupId',
+ #'data' : {
+ # 'dpid' : '$dpid',
+ # },
+ #'type' : 'groupId',
+ 'completion' : 'group-id-completion',
+ #'sort' : ['mplsLabel','priority',],
+ 'action' : 'display-rest',
+ 'url' : 'realtimestats/%(realtimestats)s/%(groupId)s/%(dpid)s/',
+ 'rest-type' : 'dict-of-list-of-switch',
+ 'format' : 'realtime_group',
+ 'doc' : 'format|+',
+ },
),
)
}
@@ -1189,3 +1191,23 @@
},
}
"""
+
+def group_id_completion(prefix, data, completions):
+ dpid = data.get('dpid')
+ #print dpid
+ query_url = "http://127.0.0.1:8000/rest/v1/realtimestats/group/%s/" %(dpid)
+ result = command.sdnsh.store.rest_simple_request(query_url)
+ entries = json.loads(result)
+ entries = entries[dpid]
+ #print "result", entries
+ for entry in entries:
+ #print entry['groupId']
+ if str(entry['groupId']).startswith(prefix):
+ completions[str(entry['groupId'])+' '] = entry['groupId']
+ return
+
+command.add_completion('group-id-completion', group_id_completion,
+ {'kwargs': { 'prefix' : '$text',
+ 'data' : '$data',
+ 'completions' : '$completions',
+ }})
diff --git a/cli/sdncon/rest/views.py b/cli/sdncon/rest/views.py
index 41b0acb..66dc75a 100755
--- a/cli/sdncon/rest/views.py
+++ b/cli/sdncon/rest/views.py
@@ -416,6 +416,21 @@
return get_sdnplatform_response(url)
@safe_rest_view
+def do_realtimegroupstats(request, groupId, dpid ):
+ """
+ This returns realtime group statistics for specified groupId
+ for a dpid by calling the localhost sdnplatform
+ """
+ #raise RestInvalidMethodException()
+ if request.method != 'GET':
+ raise RestInvalidMethodException()
+ #url = controller_url('core', 'switch', dpid, stattype, 'json')
+ #import error
+ #raise error.ArgumentValidationError('\n\n\n %s' % (groupId))
+ url = "http://localhost:8080/wm/floodlight/core/switch/%s/groupStats/%s/json" % (dpid, groupId)
+ return get_sdnplatform_response(url)
+
+@safe_rest_view
def do_tablerealtimestats(request, tabletype, dpid):
"""
This returns realtime statistics per table (flows (only)
diff --git a/cli/sdncon/urls.py b/cli/sdncon/urls.py
index 211f3d0..8478eab 100755
--- a/cli/sdncon/urls.py
+++ b/cli/sdncon/urls.py
@@ -62,6 +62,7 @@
(r'^rest/v1/realtimestats/counter/(?P<stattype>[A-Za-z0-9_:.\-]+)/?$', 'sdncon.rest.views.do_sdnplatform_realtimestats'),
(r'^rest/v1/realtimestats/counter/(?P<dpid>[A-Za-z0-9_:.\-]+)/(?P<stattype>[A-Za-z]+)/?$', 'sdncon.rest.views.do_sdnplatform_realtimestats'),
(r'^rest/v1/realtimestats/table/(?P<tabletype>[A-Za-z]+)/flow/(?P<dpid>[A-Za-z0-9_:./\-]+)/?$', 'sdncon.rest.views.do_tablerealtimestats'),
+ (r'^rest/v1/realtimestats/group/(?P<groupId>[0-9]+)/(?P<dpid>[A-Za-z0-9_:./\-]+)/?$', 'sdncon.rest.views.do_realtimegroupstats'),
(r'^rest/v1/realtimestats/(?P<stattype>[A-Za-z]+)/(?P<dpid>[A-Za-z0-9_:./\-]+)/?$', 'sdncon.rest.views.do_realtimestats'),
(r'^rest/v1/controller/stats/(?P<stattype>[A-Za-z]+)/?$', 'sdncon.rest.views.do_controller_stats'),
(r'^rest/v1/controller/storage/tables/?$', 'sdncon.rest.views.do_controller_storage_table_list'),
diff --git a/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java b/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
index 8608b20..a6879f8 100644
--- a/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/core/web/CoreWebRoutable.java
@@ -43,6 +43,8 @@
router.attach("/switch/{switchId}/role/json", SwitchRoleResource.class);
router.attach("/switch/all/{statType}/json", AllSwitchStatisticsResource.class);
router.attach("/switch/{switchId}/{statType}/json", SwitchStatisticsResource.class);
+ //TODO replace {statsType} by groupStats
+ router.attach("/switch/{switchId}/{statType}/{groupId}/json", SwitchStatisticsResource.class);
router.attach("/switch/{switchId}/table/{tableType}/{statType}/json", SwitchStatisticsResource.class);
router.attach("/controller/switches/json", ControllerSwitchesResource.class);
router.attach("/memory/json", ControllerMemoryResource.class);
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
index 56d5355..2334edf 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java
@@ -41,6 +41,7 @@
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsRequest;
import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.types.OFGroup;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.TableId;
import org.projectfloodlight.openflow.util.HexString;
@@ -138,7 +139,7 @@
}
else if (statType == OFStatsType.GROUP){
log.debug("Switch Group Stats: req sent for all "
- + "ports in switch {}", sw.getStringId());
+ + "groups in switch {}", sw.getStringId());
req = sw.getFactory().buildGroupStatsRequest().setXid
(sw.getNextTransactionId()).build();
List<OFGroupStatsEntryMod> groupStats = new ArrayList<OFGroupStatsEntryMod>();
@@ -158,7 +159,7 @@
}
else if (statType == OFStatsType.GROUP_DESC){
log.debug("Switch Group Desc Stats: req sent for all "
- + "ports in switch {}", sw.getStringId());
+ + "groups in switch {}", sw.getStringId());
List<OFGroupDescStatsEntryMod> GroupDescStats= new ArrayList<OFGroupDescStatsEntryMod>();
req = sw.getFactory().buildGroupDescStatsRequest().setXid
(sw.getNextTransactionId()).build();
@@ -211,6 +212,43 @@
protected Object getSwitchStatistics(String switchId, OFStatsType statType) {
return getSwitchStatistics(HexString.toLong(switchId), statType);
}
+
+ protected Object getSwitchGroupStats(String switchId, OFStatsType statType, Integer groupId) {
+
+ IFloodlightProviderService floodlightProvider =
+ (IFloodlightProviderService) getContext().getAttributes().
+ get(IFloodlightProviderService.class.getCanonicalName());
+ IOFSwitch sw = floodlightProvider.getSwitches().get(HexString.toLong(switchId));
+ Future<List<OFStatsReply>> future;
+ List<OFStatsReply> values = null;
+ if (sw != null){
+ log.debug("Switch Group Stats: req sent for groupId {} "
+ + "in switch {}",groupId, sw.getStringId());
+ OFStatsRequest<?> req = null;
+ req = sw.getFactory().buildGroupStatsRequest().setXid
+ (sw.getNextTransactionId()).setGroup(OFGroup.of(groupId)).build();
+ List<OFGroupStatsEntryMod> groupStats = new ArrayList<OFGroupStatsEntryMod>();
+ try {
+ future = sw.getStatistics(req);
+ values = future.get(10, TimeUnit.SECONDS);
+ if(values.isEmpty()){
+ log.warn("group with groupId {} not found", groupId);
+ return null;
+ }
+ for (OFGroupStatsEntry entry : ((OFGroupStatsReply)values.get(0)).getEntries()) {
+ OFGroupStatsEntryMod entryMod = new OFGroupStatsEntryMod(entry);
+ groupStats.add(entryMod);
+ }
+ log.debug("Switch Group Stats Entries from switch {} are {}",
+ sw.getStringId(), groupStats);
+ } catch (Exception e) {
+ log.error("Failure retrieving statistics from switch " + sw, e);
+ }
+ return groupStats;
+
+ }
+ return null;
+ }
//TODO: Java doc
protected List<?> getSwitchStatisticsForTable(long switchId,
OFStatsType statType, String tableType) {
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
index ce2221e..8976100 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java
@@ -42,6 +42,7 @@
String switchId = (String) getRequestAttributes().get("switchId");
String statType = (String) getRequestAttributes().get("statType");
+ String groupId = (String) getRequestAttributes().get("groupId");
String tableType = null;
if(getRequestAttributes().containsKey("tableType")){
tableType = (String) getRequestAttributes().get("tableType");
@@ -70,7 +71,12 @@
}else if (statType.equals("groupDesc")) {
values = getSwitchStatistics(switchId, OFStatsType.GROUP_DESC);
}else if (statType.equals("groupStats")) {
- values = getSwitchStatistics(switchId, OFStatsType.GROUP);
+ if (groupId != null){
+ values = getSwitchGroupStats(switchId, OFStatsType.GROUP, (Integer.valueOf(groupId)));
+ }
+ else{
+ values = getSwitchStatistics(switchId, OFStatsType.GROUP);
+ }
}
result.put(switchId, values);