blob: 22cfc02bf7c9313972fa8d351e57909b87a92046 [file] [log] [blame]
wu2883c762017-07-20 16:24:48 +08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
wu2883c762017-07-20 16:24:48 +08003 *
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.provider.p4runtime.packet.impl;
18
19
Ray Milkeyd84f89b2018-08-17 14:54:17 -070020import org.osgi.service.component.annotations.Activate;
21import org.osgi.service.component.annotations.Component;
22import org.osgi.service.component.annotations.Deactivate;
23import org.osgi.service.component.annotations.Reference;
24import org.osgi.service.component.annotations.ReferenceCardinality;
Andrea Campanella14e196d2017-07-24 18:11:36 +020025import org.onosproject.mastership.MastershipService;
wu2883c762017-07-20 16:24:48 +080026import org.onosproject.net.Device;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.device.DeviceService;
29import org.onosproject.net.flow.TrafficTreatment;
30import org.onosproject.net.packet.DefaultOutboundPacket;
31import org.onosproject.net.packet.DefaultPacketContext;
32import org.onosproject.net.packet.InboundPacket;
33import org.onosproject.net.packet.OutboundPacket;
Andrea Campanella288b2732017-07-28 14:16:16 +020034import org.onosproject.net.packet.PacketContext;
wu2883c762017-07-20 16:24:48 +080035import org.onosproject.net.packet.PacketProgrammable;
36import org.onosproject.net.packet.PacketProvider;
37import org.onosproject.net.packet.PacketProviderRegistry;
38import org.onosproject.net.packet.PacketProviderService;
Andrea Campanella288b2732017-07-28 14:16:16 +020039import org.onosproject.net.pi.model.PiPipelineInterpreter;
40import org.onosproject.net.pi.runtime.PiPacketOperation;
wu2883c762017-07-20 16:24:48 +080041import org.onosproject.net.provider.AbstractProvider;
42import org.onosproject.net.provider.ProviderId;
43import org.onosproject.p4runtime.api.P4RuntimeController;
44import org.onosproject.p4runtime.api.P4RuntimeEvent;
45import org.onosproject.p4runtime.api.P4RuntimeEventListener;
Andrea Campanella288b2732017-07-28 14:16:16 +020046import org.onosproject.p4runtime.api.P4RuntimePacketIn;
wu2883c762017-07-20 16:24:48 +080047import org.slf4j.Logger;
48
49import java.nio.ByteBuffer;
50
51import static org.onosproject.net.flow.DefaultTrafficTreatment.emptyTreatment;
52import static org.slf4j.LoggerFactory.getLogger;
53
54/**
55 * Implementation of a packet provider for P4Runtime device.
56 */
57@Component(immediate = true)
58public class P4RuntimePacketProvider extends AbstractProvider implements PacketProvider {
59
60 private final Logger log = getLogger(getClass());
61
Ray Milkeyd84f89b2018-08-17 14:54:17 -070062 @Reference(cardinality = ReferenceCardinality.MANDATORY)
wu2883c762017-07-20 16:24:48 +080063 protected P4RuntimeController controller;
64
Ray Milkeyd84f89b2018-08-17 14:54:17 -070065 @Reference(cardinality = ReferenceCardinality.MANDATORY)
wu2883c762017-07-20 16:24:48 +080066 protected PacketProviderRegistry providerRegistry;
67
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068 @Reference(cardinality = ReferenceCardinality.MANDATORY)
wu2883c762017-07-20 16:24:48 +080069 protected DeviceService deviceService;
70
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanella14e196d2017-07-24 18:11:36 +020072 protected MastershipService mastershipService;
73
wu2883c762017-07-20 16:24:48 +080074 private PacketProviderService providerService;
75
76 private InternalPacketListener packetListener = new InternalPacketListener();
77
78 /**
79 * Creates a new P4Runtime packet provider.
80 */
81 public P4RuntimePacketProvider() {
82 super(new ProviderId("p4runtime", "org.onosproject.provider.p4runtime.packet"));
83 }
84
85 @Activate
86 protected void activate() {
87 providerService = providerRegistry.register(this);
88 controller.addListener(packetListener);
89 log.info("Started");
90 }
91
92 @Deactivate
93 public void deactivate() {
94 controller.removeListener(packetListener);
95 providerRegistry.unregister(this);
96 providerService = null;
97 log.info("Stopped");
98 }
99
100 @Override
101 public void emit(OutboundPacket packet) {
102 if (packet != null) {
103 DeviceId deviceId = packet.sendThrough();
104 Device device = deviceService.getDevice(deviceId);
Andrea Campanella14e196d2017-07-24 18:11:36 +0200105 if (device.is(PacketProgrammable.class) && mastershipService.isLocalMaster(deviceId)) {
wu2883c762017-07-20 16:24:48 +0800106 PacketProgrammable packetProgrammable = device.as(PacketProgrammable.class);
107 packetProgrammable.emit(packet);
108 } else {
109 log.warn("No PacketProgrammable behavior for device {}", deviceId);
110 }
111 }
112 }
113
114 /**
115 * Internal packet context implementation.
116 */
117 private class P4RuntimePacketContext extends DefaultPacketContext {
118
119 P4RuntimePacketContext(long time, InboundPacket inPkt, OutboundPacket outPkt, boolean block) {
120 super(time, inPkt, outPkt, block);
121 }
122
123 @Override
124 public void send() {
125
126 if (this.block()) {
127 log.info("Unable to send, packet context is blocked");
128 return;
129 }
130
131 DeviceId deviceId = outPacket().sendThrough();
132 ByteBuffer rawData = outPacket().data();
133
134 TrafficTreatment treatment;
135 if (outPacket().treatment() == null) {
136 treatment = (treatmentBuilder() == null) ? emptyTreatment() : treatmentBuilder().build();
137 } else {
138 treatment = outPacket().treatment();
139 }
140
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200141 OutboundPacket outboundPacket = new DefaultOutboundPacket(deviceId, treatment, rawData);
142 log.debug("Processing outbound packet: {}", outboundPacket);
143
144 emit(outboundPacket);
wu2883c762017-07-20 16:24:48 +0800145 }
146 }
147
148 /**
149 * Internal packet listener to handle packet-in events received from the P4Runtime controller.
150 */
151 private class InternalPacketListener implements P4RuntimeEventListener {
152
wu2883c762017-07-20 16:24:48 +0800153 @Override
154 public void event(P4RuntimeEvent event) {
Andrea Campanella14e196d2017-07-24 18:11:36 +0200155 //Masterhip message is sent to everybody but picked up only by master.
156 //FIXME we need the device ID into p4RuntimeEvnetSubject to check for mastsership
157 if (!(event.subject() instanceof P4RuntimePacketIn) || event.type() != P4RuntimeEvent.Type.PACKET_IN) {
158 log.debug("Event type {}", event.type());
Yi Tseng3e7f1452017-10-20 10:31:53 -0700159 // Not a packet-in event, ignore it.
160 return;
161 }
Andrea Campanella288b2732017-07-28 14:16:16 +0200162 P4RuntimePacketIn eventSubject = (P4RuntimePacketIn) event.subject();
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200163 DeviceId deviceId = eventSubject.deviceId();
164
165 Device device = deviceService.getDevice(eventSubject.deviceId());
166 if (device == null) {
167 log.warn("Unable to process packet-in from {}, device is null in the core", deviceId);
168 return;
Andrea Campanella288b2732017-07-28 14:16:16 +0200169 }
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200170
171 if (!device.is(PiPipelineInterpreter.class)) {
172 log.warn("Unable to process packet-in from {}, device has no PiPipelineInterpreter behaviour",
Andrea Campanella14e196d2017-07-24 18:11:36 +0200173 deviceId);
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200174 return;
175 }
176
177 PiPacketOperation operation = eventSubject.packetOperation();
178 InboundPacket inPkt;
179 try {
Carmelo Cascone87892e22017-11-13 16:01:29 -0800180 inPkt = device.as(PiPipelineInterpreter.class).mapInboundPacket(operation);
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200181 } catch (PiPipelineInterpreter.PiInterpreterException e) {
182 log.warn("Unable to interpret inbound packet from {}: {}", deviceId, e.getMessage());
183 return;
184 }
185
186 if (inPkt == null) {
187 log.debug("Received null inbound packet. Ignoring.");
188 return;
189 }
190
191 log.debug("Processing inbound packet: {}", inPkt.toString());
192
193 OutboundPacket outPkt = new DefaultOutboundPacket(eventSubject.deviceId(), null,
Andrea Campanella14e196d2017-07-24 18:11:36 +0200194 operation.data().asReadOnlyBuffer());
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200195 PacketContext pktCtx = new P4RuntimePacketContext(System.currentTimeMillis(), inPkt, outPkt, false);
196
197 // Pushing the packet context up for processing.
198 providerService.processPacket(pktCtx);
wu2883c762017-07-20 16:24:48 +0800199 }
200 }
201}