ONOS-7000 P4 tutorial application and P4 program
Change-Id: Ia0a6befa6374a1950485c1fba0cfacb5ff4ce52c
diff --git a/apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/IcmpDropper.java b/apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/IcmpDropper.java
new file mode 100644
index 0000000..8914ee7
--- /dev/null
+++ b/apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/IcmpDropper.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.p4tutorial.icmpdropper;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.app.ApplicationAdminService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+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;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.criteria.PiCriterion;
+import org.onosproject.net.pi.model.PiPipelineProgrammable;
+import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionId;
+import org.onosproject.net.pi.runtime.PiHeaderFieldId;
+import org.onosproject.net.pi.runtime.PiPipeconfService;
+import org.onosproject.net.pi.runtime.PiTableId;
+import org.onosproject.p4tutorial.pipeconf.PipeconfFactory;
+import org.slf4j.Logger;
+
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Simple application that drops all ICMP packets.
+ */
+@Component(immediate = true)
+public class IcmpDropper {
+
+ private static final Logger log = getLogger(IcmpDropper.class);
+
+ private static final String APP_NAME = "org.onosproject.p4tutorial.icmpdropper";
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private FlowRuleService flowRuleService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private ApplicationAdminService appService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private PiPipeconfService piPipeconfService;
+
+ private final DeviceListener deviceListener = new InternalDeviceListener();
+
+ private ApplicationId appId;
+
+ @Activate
+ public void activate() {
+ log.info("Starting...");
+
+ appId = coreService.registerApplication(APP_NAME);
+ // Register listener for handling new devices.
+ deviceService.addListener(deviceListener);
+ // Install rules to existing devices.
+ deviceService.getDevices()
+ .forEach(device -> installDropRule(device.id()));
+
+ log.info("STARTED", appId.id());
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopping...");
+
+ deviceService.removeListener(deviceListener);
+ flowRuleService.removeFlowRulesById(appId);
+
+ log.info("STOPPED");
+ }
+
+ private boolean checkPipeconf(Device device) {
+ if (!device.is(PiPipelineProgrammable.class)) {
+ // Device is not PI-pipeline programmable. Ignore.
+ return false;
+ }
+ if (!piPipeconfService.ofDevice(device.id()).isPresent() ||
+ !piPipeconfService.ofDevice(device.id()).get().equals(PipeconfFactory.PIPECONF_ID)) {
+ log.warn("Device {} has pipeconf {} instead of {}, can't install flow rule for this device",
+ device.id(), piPipeconfService.ofDevice(device.id()).get(), PipeconfFactory.PIPECONF_ID);
+ return false;
+ }
+
+ return true;
+ }
+
+ private void installDropRule(DeviceId deviceId) {
+ PiHeaderFieldId ipv4ProtoFieldId = PiHeaderFieldId.of("ipv4", "protocol");
+ PiActionId dropActionId = PiActionId.of("_drop");
+
+ PiCriterion piCriterion = PiCriterion.builder()
+ .matchExact(ipv4ProtoFieldId, (byte) 0x01)
+ .build();
+ PiAction dropAction = PiAction.builder()
+ .withId(dropActionId)
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .forTable(PiTableId.of("ip_proto_filter_table"))
+ .fromApp(appId)
+ .makePermanent()
+ .withPriority(1000)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(piCriterion)
+ .build())
+ .withTreatment(
+ DefaultTrafficTreatment.builder()
+ .piTableAction(dropAction)
+ .build())
+ .build();
+
+ log.warn("Installing ICMP drop rule to {}", deviceId);
+
+ flowRuleService.applyFlowRules(flowRule);
+ }
+
+ /**
+ * A listener of device events that installs a rule to drop packet for each new device.
+ */
+ private class InternalDeviceListener implements DeviceListener {
+ @Override
+ public void event(DeviceEvent event) {
+ Device device = event.subject();
+ if (checkPipeconf(device)) {
+ installDropRule(device.id());
+ }
+ }
+
+ @Override
+ public boolean isRelevant(DeviceEvent event) {
+ // Reacts only to new devices.
+ return event.type() == DEVICE_ADDED;
+ }
+ }
+}