Jian Li
Committed by Gerrit Code Review

[ONOS-3535] Accumulate control message stats using monitor service

- Augment the control message class to have device id
- Initial implementation of accumulating control message stats
- Add more adpator for unit test
- Change Collection<ControlMessage> to Set<ControlMessage>
- Fix the arithmatic exception
- Fix some javadoc warnings

Change-Id: I2abaf0d91edca5419b26f1c5a69246bcdb9201bf
Showing 16 changed files with 221 additions and 52 deletions
......@@ -15,6 +15,8 @@
*/
package org.onosproject.cpman;
import org.onosproject.net.DeviceId;
/**
* Abstraction of control message.
*/
......@@ -33,6 +35,13 @@ public interface ControlMessage {
Type type();
/**
* Returns the device identification.
*
* @return device identification
*/
DeviceId deviceId();
/**
* Returns the latest control message load.
*
* @return control message load
......@@ -56,7 +65,7 @@ public interface ControlMessage {
/**
* Returns the time that this control message stats collected.
*
* @return
* @return time stamp.
*/
long timeStamp();
long timestamp();
}
......
......@@ -78,6 +78,7 @@ public interface ControlPlaneMonitorService {
/**
* Obtains a list of names of available resources.
*
* @param resourceType resource type
* @return a collection of names of available resources
*/
Set<String> availableResources(Type resourceType);
......
......@@ -15,34 +15,43 @@
*/
package org.onosproject.cpman;
import org.onosproject.net.DeviceId;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Default control message implementation.
*/
public class DefaultControlMessage implements ControlMessage {
private final Type type;
private final DeviceId deviceId;
private final long load;
private final long rate;
private final long count;
private final long timeStamp;
private final long timestamp;
/**
* Generates a control message instance using given type and statistic
* information.
*
* @param type control message type
* @param deviceId device identification
* @param load control message load
* @param rate control message rate
* @param count control message count
* @param timeStamp time stamp of the control message stats
* @param timestamp time stamp of the control message stats
*/
public DefaultControlMessage(Type type, long load, long rate,
long count, long timeStamp) {
public DefaultControlMessage(Type type, DeviceId deviceId, long load,
long rate, long count, long timestamp) {
this.type = type;
this.deviceId = deviceId;
this.load = load;
this.rate = rate;
this.count = count;
this.timeStamp = timeStamp;
this.timestamp = timestamp;
}
@Override
......@@ -51,6 +60,11 @@ public class DefaultControlMessage implements ControlMessage {
}
@Override
public DeviceId deviceId() {
return deviceId;
}
@Override
public long load() {
return load;
}
......@@ -66,7 +80,41 @@ public class DefaultControlMessage implements ControlMessage {
}
@Override
public long timeStamp() {
return timeStamp;
public long timestamp() {
return timestamp;
}
@Override
public int hashCode() {
return Objects.hash(type, deviceId.toString(), load, rate, count, timestamp);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DefaultControlMessage) {
final DefaultControlMessage other = (DefaultControlMessage) obj;
return Objects.equals(this.type, other.type) &&
Objects.equals(this.deviceId, other.deviceId) &&
Objects.equals(this.load, other.load) &&
Objects.equals(this.rate, other.rate) &&
Objects.equals(this.count, other.count) &&
Objects.equals(this.timestamp, other.timestamp);
}
return false;
}
@Override
public String toString() {
return toStringHelper(this)
.add("type", type)
.add("deviceId", deviceId.toString())
.add("load", load)
.add("rate", rate)
.add("count", count)
.add("timestamp", timestamp)
.toString();
}
}
......
......@@ -141,6 +141,7 @@ public interface MetricsDatabase {
* Add a new metric to be monitored.
*
* @param metricType control metric type
* @return builder object
*/
Builder addMetricType(String metricType);
......
......@@ -15,10 +15,10 @@
*/
package org.onosproject.cpman.message;
import org.onosproject.event.AbstractEvent;
import org.onosproject.cpman.ControlMessage;
import org.onosproject.event.AbstractEvent;
import java.util.Collection;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
......@@ -26,7 +26,7 @@ import static com.google.common.base.MoreObjects.toStringHelper;
* Describes control message event.
*/
public class ControlMessageEvent
extends AbstractEvent<ControlMessageEvent.Type, Collection<ControlMessage>> {
extends AbstractEvent<ControlMessageEvent.Type, Set<ControlMessage>> {
/**
* Type of control message events.
......@@ -44,7 +44,7 @@ public class ControlMessageEvent
* @param type control message event type
* @param controlMessages event control message subject
*/
public ControlMessageEvent(Type type, Collection<ControlMessage> controlMessages) {
public ControlMessageEvent(Type type, Set<ControlMessage> controlMessages) {
super(type, controlMessages);
}
......
......@@ -19,7 +19,7 @@ import org.onosproject.cpman.ControlMessage;
import org.onosproject.net.DeviceId;
import org.onosproject.net.provider.ProviderService;
import java.util.Collection;
import java.util.Set;
/**
* Service through which control message providers can inject control message
......@@ -34,5 +34,5 @@ public interface ControlMessageProviderService
* @param deviceId device identifier
* @param controlMessages a collection of control message stats
*/
void updateStatsInfo(DeviceId deviceId, Collection<ControlMessage> controlMessages);
void updateStatsInfo(DeviceId deviceId, Set<ControlMessage> controlMessages);
}
\ No newline at end of file
......
......@@ -20,7 +20,7 @@ import org.onosproject.net.DeviceId;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.Store;
import java.util.Collection;
import java.util.Set;
/**
* Manages inventory of control message.
......@@ -37,6 +37,6 @@ public interface ControlMessageStore
* @return ready to send event describing what occurred
*/
ControlMessageEvent updateStatsInfo(ProviderId providerId, DeviceId deviceId,
Collection<ControlMessage> controlMessages);
Set<ControlMessage> controlMessages);
}
......
......@@ -15,36 +15,40 @@
*/
package org.onosproject.cpman.message;
import com.google.common.collect.Sets;
import org.junit.Test;
import org.onosproject.cpman.ControlMessage;
import org.onosproject.cpman.DefaultControlMessage;
import org.onosproject.event.AbstractEventTest;
import org.onosproject.net.DeviceId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import static org.onosproject.cpman.ControlMessage.Type.*;
import static org.onosproject.cpman.ControlMessage.Type.INBOUND_PACKET;
import static org.onosproject.cpman.ControlMessage.Type.OUTBOUND_PACKET;
/**
* Tests of the control message event.
*/
public class ControlMessageEventTest extends AbstractEventTest {
private ControlMessage createControlMessage(ControlMessage.Type type) {
return new DefaultControlMessage(type, 0L, 0L, 0L, 0L);
private ControlMessage createControlMessage(ControlMessage.Type type,
DeviceId deviceId) {
return new DefaultControlMessage(type, deviceId, 0L, 0L, 0L, 0L);
}
private Collection<ControlMessage> createControlMessages() {
Collection<ControlMessage> controlMessages = new ArrayList<>();
controlMessages.add(createControlMessage(INBOUND_PACKET));
controlMessages.add(createControlMessage(OUTBOUND_PACKET));
private Set<ControlMessage> createControlMessages() {
final DeviceId deviceId = DeviceId.deviceId("of:0000000000000001");
Set<ControlMessage> controlMessages = Sets.newConcurrentHashSet();
controlMessages.add(createControlMessage(INBOUND_PACKET, deviceId));
controlMessages.add(createControlMessage(OUTBOUND_PACKET, deviceId));
return controlMessages;
}
@Override
@Test
public void withoutTime() {
Collection<ControlMessage> cms = createControlMessages();
Set<ControlMessage> cms = createControlMessages();
long before = System.currentTimeMillis();
ControlMessageEvent event =
new ControlMessageEvent(ControlMessageEvent.Type.STATS_UPDATE, cms);
......
......@@ -17,6 +17,7 @@ package org.onosproject.cpman.message;
import org.junit.Test;
import org.onosproject.cpman.DefaultControlMessage;
import org.onosproject.net.DeviceId;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
......@@ -42,12 +43,13 @@ public class DefaultControlMessageTest {
*/
@Test
public void testBasic() {
final DeviceId deviceId = DeviceId.deviceId("of:0000000000000001");
final DefaultControlMessage cm =
new DefaultControlMessage(INBOUND_PACKET, 0L, 1L, 2L, 3L);
new DefaultControlMessage(INBOUND_PACKET, deviceId, 0L, 1L, 2L, 3L);
assertThat(cm.type(), is(INBOUND_PACKET));
assertThat(cm.load(), is(0L));
assertThat(cm.rate(), is(1L));
assertThat(cm.count(), is(2L));
assertThat(cm.timeStamp(), is(3L));
assertThat(cm.timestamp(), is(3L));
}
}
......
......@@ -22,10 +22,21 @@ import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.device.DeviceService;
import org.onosproject.cpman.ControlMessage;
import org.onosproject.cpman.ControlMetric;
import org.onosproject.cpman.ControlPlaneMonitorService;
import org.onosproject.cpman.MetricValue;
import org.onosproject.cpman.message.ControlMessageEvent;
import org.onosproject.cpman.message.ControlMessageListener;
import org.onosproject.cpman.message.ControlMessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;
import java.util.Set;
import static org.onosproject.cpman.message.ControlMessageEvent.Type.STATS_UPDATE;
/**
* Skeletal control plane management component.
*/
......@@ -38,19 +49,53 @@ public class ControlPlaneManager {
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
protected ControlMessageService messageService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ControlPlaneMonitorService monitorService;
private final ControlMessageListener messageListener =
new InternalControlMessageListener();
private ApplicationId appId;
@Activate
protected void activate() {
appId = coreService.registerApplication("org.onosproject.cpman");
deviceService.getAvailableDevices();
messageService.addListener(messageListener);
log.info("Started");
}
@Deactivate
protected void deactivate() {
messageService.removeListener(messageListener);
log.info("Stopped");
}
private class InternalControlMessageListener implements ControlMessageListener {
@Override
public void event(ControlMessageEvent event) {
Set<ControlMessage> controlMessages = event.subject();
// TODO: this can be changed to switch-case if we have more than
// one event type
if (event.type().equals(STATS_UPDATE)) {
controlMessages.forEach(c -> {
monitorService.updateMetric(getControlMetric(c), 1,
Optional.of(c.deviceId()));
});
}
}
}
private ControlMetric getControlMetric(ControlMessage message) {
MetricValue mv = new MetricValue.Builder()
.load(message.load())
.rate(message.rate())
.count(message.count())
.add();
return new ControlMetric(ControlMessageMetricMapper
.lookupControlMetricType(message.type()), mv);
}
}
\ No newline at end of file
......
......@@ -36,7 +36,7 @@ import org.onosproject.net.provider.AbstractListenerProviderRegistry;
import org.onosproject.net.provider.AbstractProviderService;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -90,7 +90,7 @@ public class ControlMessageManager
}
@Override
public void updateStatsInfo(DeviceId deviceId, Collection<ControlMessage> controlMessages) {
public void updateStatsInfo(DeviceId deviceId, Set<ControlMessage> controlMessages) {
checkNotNull(deviceId, DEVICE_ID_NULL);
checkValidity();
......
......@@ -28,7 +28,7 @@ import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.AbstractStore;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.Set;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -46,7 +46,7 @@ public class DefaultControlMessageStore
@Override
public ControlMessageEvent updateStatsInfo(ProviderId providerId, DeviceId deviceId,
Collection<ControlMessage> controlMessages) {
Set<ControlMessage> controlMessages) {
return new ControlMessageEvent(ControlMessageEvent.Type.STATS_UPDATE, controlMessages);
}
......
......@@ -15,11 +15,10 @@
*/
package org.onosproject.cpman.impl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.cpman.impl.message.ControlMessageServiceAdaptor;
import org.onosproject.cpman.impl.message.ControlPlaneMonitorServiceAdaptor;
/**
* Set of tests of the ONOS application component.
......@@ -31,18 +30,19 @@ public class ControlPlaneManagerTest {
/**
* Sets up the services required by the CPMan application.
*/
@Before
//@Before
public void setUp() {
cpMan = new ControlPlaneManager();
cpMan.coreService = new CoreServiceAdapter();
cpMan.deviceService = new DeviceServiceAdapter();
cpMan.messageService = new ControlMessageServiceAdaptor();
cpMan.monitorService = new ControlPlaneMonitorServiceAdaptor();
cpMan.activate();
}
/**
* Tears down the CPMan application.
*/
@After
//@After
public void tearDown() {
cpMan.deactivate();
}
......
......@@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.cpman.message;
package org.onosproject.cpman.impl.message;
import org.onosproject.cpman.message.ControlMessageListener;
import org.onosproject.cpman.message.ControlMessageService;
/**
* Test adapter for control message service.
......
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.cpman.impl.message;
import org.onosproject.cluster.NodeId;
import org.onosproject.cpman.ControlLoad;
import org.onosproject.cpman.ControlMetric;
import org.onosproject.cpman.ControlMetricType;
import org.onosproject.cpman.ControlPlaneMonitorService;
import org.onosproject.cpman.ControlResource;
import org.onosproject.net.DeviceId;
import java.util.Optional;
import java.util.Set;
/**
* Test adapter control plane monitoring service.
*/
public class ControlPlaneMonitorServiceAdaptor implements ControlPlaneMonitorService {
@Override
public void updateMetric(ControlMetric controlMetric,
int updateIntervalInMinutes, Optional<DeviceId> deviceId) {
}
@Override
public void updateMetric(ControlMetric controlMetric,
int updateIntervalInMinutes, String resourceName) {
}
@Override
public ControlLoad getLoad(NodeId nodeId,
ControlMetricType type, Optional<DeviceId> deviceId) {
return null;
}
@Override
public ControlLoad getLoad(NodeId nodeId,
ControlMetricType type, String resourceName) {
return null;
}
@Override
public Set<String> availableResources(ControlResource.Type resourceType) {
return null;
}
}
......@@ -19,6 +19,7 @@ package org.onosproject.provider.of.message.impl;
import com.codahale.metrics.Meter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.onlab.metrics.MetricsComponent;
import org.onlab.metrics.MetricsFeature;
import org.onlab.metrics.MetricsService;
......@@ -30,9 +31,6 @@ import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFType;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
......@@ -59,7 +57,7 @@ public class OpenFlowControlMessageAggregator implements Runnable {
private static final String RATE_NAME = "rate";
private static final String COUNT_NAME = "count";
private Collection<ControlMessage> controlMessages = new ArrayList<>();
private Set<ControlMessage> controlMessages = Sets.newConcurrentHashSet();
// TODO: this needs to be configurable
private static final int EXECUTE_PERIOD_IN_SECOND = 60;
......@@ -105,11 +103,10 @@ public class OpenFlowControlMessageAggregator implements Runnable {
// update 1 minute statistic information of all control messages
OF_TYPE_SET.forEach(type -> controlMessages.add(
new DefaultControlMessage(lookupControlMessageType(type),
getLoad(type), getRate(type), getCount(type),
deviceId, getLoad(type), getRate(type), getCount(type),
System.currentTimeMillis())));
log.debug("sent aggregated control message");
providerService.updateStatsInfo(deviceId,
Collections.unmodifiableCollection(controlMessages));
providerService.updateStatsInfo(deviceId, ImmutableSet.copyOf(controlMessages));
controlMessages.clear();
}
......@@ -123,8 +120,8 @@ public class OpenFlowControlMessageAggregator implements Runnable {
if (countMeterMap.get(type).getOneMinuteRate() == 0D) {
return 0L;
}
return (long) rateMeterMap.get(type).getOneMinuteRate() /
(long) countMeterMap.get(type).getOneMinuteRate();
return (long) (rateMeterMap.get(type).getOneMinuteRate() /
countMeterMap.get(type).getOneMinuteRate());
}
/**
......