blob: ce1c6826323d5e6640b4615e1ce34a8291409f3d [file] [log] [blame]
Carmelo Cascone770507f2017-09-14 20:58:04 +02001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.p4tutorial.icmpdropper;
18
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onosproject.app.ApplicationAdminService;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.net.Device;
28import org.onosproject.net.DeviceId;
29import org.onosproject.net.device.DeviceEvent;
30import org.onosproject.net.device.DeviceListener;
31import org.onosproject.net.device.DeviceService;
32import org.onosproject.net.flow.DefaultFlowRule;
33import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.FlowRule;
36import org.onosproject.net.flow.FlowRuleService;
37import org.onosproject.net.flow.criteria.PiCriterion;
Carmelo Cascone87892e22017-11-13 16:01:29 -080038import org.onosproject.net.behaviour.PiPipelineProgrammable;
Carmelo Cascone770507f2017-09-14 20:58:04 +020039import org.onosproject.net.pi.runtime.PiAction;
Carmelo Cascone87892e22017-11-13 16:01:29 -080040import org.onosproject.net.pi.model.PiActionId;
41import org.onosproject.net.pi.model.PiMatchFieldId;
Carmelo Cascone39c28ca2017-11-15 13:03:57 -080042import org.onosproject.net.pi.service.PiPipeconfService;
Carmelo Cascone87892e22017-11-13 16:01:29 -080043import org.onosproject.net.pi.model.PiTableId;
Carmelo Cascone770507f2017-09-14 20:58:04 +020044import org.onosproject.p4tutorial.pipeconf.PipeconfFactory;
45import org.slf4j.Logger;
46
47import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
48import static org.slf4j.LoggerFactory.getLogger;
49
50/**
51 * Simple application that drops all ICMP packets.
52 */
53@Component(immediate = true)
54public class IcmpDropper {
55
56 private static final Logger log = getLogger(IcmpDropper.class);
57
58 private static final String APP_NAME = "org.onosproject.p4tutorial.icmpdropper";
59
60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 private DeviceService deviceService;
62
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 private FlowRuleService flowRuleService;
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 private ApplicationAdminService appService;
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 private CoreService coreService;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 private PiPipeconfService piPipeconfService;
74
75 private final DeviceListener deviceListener = new InternalDeviceListener();
76
77 private ApplicationId appId;
78
79 @Activate
80 public void activate() {
81 log.info("Starting...");
82
83 appId = coreService.registerApplication(APP_NAME);
84 // Register listener for handling new devices.
85 deviceService.addListener(deviceListener);
86 // Install rules to existing devices.
87 deviceService.getDevices()
88 .forEach(device -> installDropRule(device.id()));
89
90 log.info("STARTED", appId.id());
91 }
92
93 @Deactivate
94 public void deactivate() {
95 log.info("Stopping...");
96
97 deviceService.removeListener(deviceListener);
98 flowRuleService.removeFlowRulesById(appId);
99
100 log.info("STOPPED");
101 }
102
103 private boolean checkPipeconf(Device device) {
104 if (!device.is(PiPipelineProgrammable.class)) {
105 // Device is not PI-pipeline programmable. Ignore.
106 return false;
107 }
108 if (!piPipeconfService.ofDevice(device.id()).isPresent() ||
109 !piPipeconfService.ofDevice(device.id()).get().equals(PipeconfFactory.PIPECONF_ID)) {
110 log.warn("Device {} has pipeconf {} instead of {}, can't install flow rule for this device",
111 device.id(), piPipeconfService.ofDevice(device.id()).get(), PipeconfFactory.PIPECONF_ID);
112 return false;
113 }
114
115 return true;
116 }
117
118 private void installDropRule(DeviceId deviceId) {
natetang61689942017-11-22 15:03:17 -0800119 PiMatchFieldId ipv4ProtoFieldId = PiMatchFieldId.of("hdr.ipv4.protocol");
Carmelo Cascone770507f2017-09-14 20:58:04 +0200120 PiActionId dropActionId = PiActionId.of("_drop");
121
122 PiCriterion piCriterion = PiCriterion.builder()
123 .matchExact(ipv4ProtoFieldId, (byte) 0x01)
124 .build();
125 PiAction dropAction = PiAction.builder()
126 .withId(dropActionId)
127 .build();
128
129 FlowRule flowRule = DefaultFlowRule.builder()
130 .forDevice(deviceId)
131 .forTable(PiTableId.of("ip_proto_filter_table"))
132 .fromApp(appId)
133 .makePermanent()
134 .withPriority(1000)
135 .withSelector(DefaultTrafficSelector.builder()
136 .matchPi(piCriterion)
137 .build())
138 .withTreatment(
139 DefaultTrafficTreatment.builder()
140 .piTableAction(dropAction)
141 .build())
142 .build();
143
144 log.warn("Installing ICMP drop rule to {}", deviceId);
145
146 flowRuleService.applyFlowRules(flowRule);
147 }
148
149 /**
150 * A listener of device events that installs a rule to drop packet for each new device.
151 */
152 private class InternalDeviceListener implements DeviceListener {
153 @Override
154 public void event(DeviceEvent event) {
155 Device device = event.subject();
156 if (checkPipeconf(device)) {
157 installDropRule(device.id());
158 }
159 }
160
161 @Override
162 public boolean isRelevant(DeviceEvent event) {
163 // Reacts only to new devices.
164 return event.type() == DEVICE_ADDED;
165 }
166 }
167}