Converted one-ping to use objective service.
Change-Id: I324d0cf3a329425669a3462ac1182565c067a8c0
diff --git a/oneping/src/main/java/org/onos/oneping/OnePing.java b/oneping/src/main/java/org/onos/oneping/OnePing.java
index 273a416..58d2eb4 100644
--- a/oneping/src/main/java/org/onos/oneping/OnePing.java
+++ b/oneping/src/main/java/org/onos/oneping/OnePing.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2015 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.onos.oneping;
import com.google.common.collect.HashMultimap;
@@ -11,13 +26,7 @@
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
-import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowRule;
@@ -26,8 +35,13 @@
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthCriterion;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.slf4j.Logger;
@@ -37,7 +51,7 @@
import java.util.Timer;
import java.util.TimerTask;
-import static org.onosproject.net.flow.criteria.Criterion.Type.ETH_DST;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
import static org.onosproject.net.flow.criteria.Criterion.Type.ETH_SRC;
/**
@@ -47,6 +61,8 @@
@Component(immediate = true)
public class OnePing {
+ private static Logger log = LoggerFactory.getLogger(OnePing.class);
+
private static final String MSG_PINGED_ONCE =
"Thank you, Vasili. One ping from {} to {} received by {}";
private static final String MSG_PINGED_TWICE =
@@ -56,15 +72,15 @@
private static final String MSG_PING_REENABLED =
"Careful next time, Vasili! Re-enabled ping from {} to {} on {}";
-
- private static Logger log = LoggerFactory.getLogger(OnePing.class);
-
private static final int PRIORITY = 128;
private static final int DROP_PRIORITY = 129;
private static final int TIMEOUT_SEC = 60; // seconds
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DeviceService deviceService;
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveService flowObjectiveService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@@ -72,22 +88,16 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected CoreService coreService;
-
private ApplicationId appId;
private final PacketProcessor packetProcessor = new PingPacketProcessor();
- private final DeviceListener deviceListener = new InternalDeviceListener();
private final FlowRuleListener flowListener = new InternalFlowListener();
- private final TrafficSelector selector = DefaultTrafficSelector.builder()
+ // Selector for ICMP traffic that is to be intercepted
+ private final TrafficSelector intercept = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4).matchIPProtocol(IPv4.PROTOCOL_ICMP)
.build();
-// private TrafficTreatment treatment = DefaultTrafficTreatment.builder().punt().build(); // requires ONOS 1.1.0+
- private TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(PortNumber.CONTROLLER).build(); // requires ONOS 1.0.1+
-
+ // Means to track detected pings from each device on a temporary basis
private final HashMultimap<DeviceId, PingRecord> pings = HashMultimap.create();
private final Timer timer = new Timer("oneping-sweeper");
@@ -95,32 +105,19 @@
public void activate() {
appId = coreService.registerApplication("org.onos.oneping");
packetService.addProcessor(packetProcessor, PRIORITY);
- deviceService.addListener(deviceListener);
flowRuleService.addListener(flowListener);
- pushInterceptRules();
+ packetService.requestPackets(intercept, PacketPriority.REACTIVE, appId);
log.info("Started");
}
@Deactivate
public void deactivate() {
- flowRuleService.removeFlowRulesById(appId);
packetService.removeProcessor(packetProcessor);
+ flowRuleService.removeFlowRulesById(appId);
flowRuleService.removeListener(flowListener);
log.info("Stopped");
}
- // Pushes ICMP intercept rules to all connected devices
- private void pushInterceptRules() {
- deviceService.getDevices().forEach(this::pushInterceptRule);
- }
-
- // Pushes ICMP intercept rule to the specified device.
- private void pushInterceptRule(Device device) {
- DefaultFlowRule rule = new DefaultFlowRule(device.id(), selector, treatment,
- PRIORITY, appId, 0, true);
- flowRuleService.applyFlowRules(rule);
- }
-
// Processes the specified ICMP ping packet.
private void processPing(PacketContext context, Ethernet eth) {
DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
@@ -130,10 +127,12 @@
boolean pinged = pings.get(deviceId).contains(ping);
if (pinged) {
+ // Two pings detected; ban further pings and block packet-out
log.warn(MSG_PINGED_TWICE, src, dst, deviceId);
banPings(deviceId, src, dst);
context.block();
} else {
+ // One ping detected; track it for the next minute
log.info(MSG_PINGED_ONCE, src, dst, deviceId);
pings.put(deviceId, ping);
timer.schedule(new PingPruner(deviceId, ping), TIMEOUT_SEC * 1000);
@@ -142,25 +141,26 @@
// Installs a temporary drop rule for the ICMP pings between given srd/dst.
private void banPings(DeviceId deviceId, MacAddress src, MacAddress dst) {
- TrafficSelector sel = DefaultTrafficSelector.builder()
+ TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthSrc(src).matchEthDst(dst).build();
- //The default behavior of DefaultTrafficTreatment.build has changed,
- //where the implicit DROP instruction will not get added when the
- //instruction set is empty, hence explicitly adding it.
- TrafficTreatment treat = DefaultTrafficTreatment.builder().drop().build();
- DefaultFlowRule drop = new DefaultFlowRule(deviceId, sel, treat,
- DROP_PRIORITY, appId,
- TIMEOUT_SEC, false);
- flowRuleService.applyFlowRules(drop);
+ TrafficTreatment drop = DefaultTrafficTreatment.builder()
+ .drop().build();
+
+ flowObjectiveService.forward(deviceId, DefaultForwardingObjective.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(drop)
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(DROP_PRIORITY)
+ .makeTemporary(TIMEOUT_SEC)
+ .add());
}
// Indicates whether the specified packet corresponds to ICMP ping.
private boolean isIcmpPing(Ethernet eth) {
- if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
- return ((IPv4) eth.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP;
- }
- return false;
+ return eth.getEtherType() == Ethernet.TYPE_IPV4 &&
+ ((IPv4) eth.getPayload()).getProtocol() == IPv4.PROTOCOL_ICMP;
}
@@ -175,15 +175,7 @@
}
}
- private class InternalDeviceListener implements DeviceListener {
- @Override
- public void event(DeviceEvent event) {
- if (event.type() == DeviceEvent.Type.DEVICE_ADDED) {
- pushInterceptRule(event.subject());
- }
- }
- }
-
+ // Record of a ping between two end-station MAC addresses
private class PingRecord {
private final MacAddress src;
private final MacAddress dst;
@@ -232,10 +224,10 @@
@Override
public void event(FlowRuleEvent event) {
FlowRule flowRule = event.subject();
- if (event.type() == FlowRuleEvent.Type.RULE_REMOVED &&
- flowRule.appId() == appId.id()) {
- MacAddress src = ((EthCriterion) flowRule.selector().getCriterion(ETH_SRC)).mac();
- MacAddress dst = ((EthCriterion) flowRule.selector().getCriterion(ETH_DST)).mac();
+ if (event.type() == RULE_REMOVED && flowRule.appId() == appId.id()) {
+ Criterion criterion = flowRule.selector().getCriterion(ETH_SRC);
+ MacAddress src = ((EthCriterion) criterion).mac();
+ MacAddress dst = ((EthCriterion) criterion).mac();
log.warn(MSG_PING_REENABLED, src, dst, flowRule.deviceId());
}
}