blob: 2fa7493d870338b573391ae3848d92bbae7fa829 [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
Carmelo Cascone4becd352019-08-27 16:06:55 -070020import org.onlab.packet.EthType;
Andrea Campanella14e196d2017-07-24 18:11:36 +020021import org.onosproject.mastership.MastershipService;
wu2883c762017-07-20 16:24:48 +080022import org.onosproject.net.Device;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.device.DeviceService;
25import org.onosproject.net.flow.TrafficTreatment;
26import org.onosproject.net.packet.DefaultOutboundPacket;
27import org.onosproject.net.packet.DefaultPacketContext;
28import org.onosproject.net.packet.InboundPacket;
29import org.onosproject.net.packet.OutboundPacket;
Andrea Campanella288b2732017-07-28 14:16:16 +020030import org.onosproject.net.packet.PacketContext;
wu2883c762017-07-20 16:24:48 +080031import org.onosproject.net.packet.PacketProgrammable;
32import org.onosproject.net.packet.PacketProvider;
33import org.onosproject.net.packet.PacketProviderRegistry;
34import org.onosproject.net.packet.PacketProviderService;
Andrea Campanella288b2732017-07-28 14:16:16 +020035import org.onosproject.net.pi.model.PiPipelineInterpreter;
36import org.onosproject.net.pi.runtime.PiPacketOperation;
wu2883c762017-07-20 16:24:48 +080037import org.onosproject.net.provider.AbstractProvider;
38import org.onosproject.net.provider.ProviderId;
39import org.onosproject.p4runtime.api.P4RuntimeController;
40import org.onosproject.p4runtime.api.P4RuntimeEvent;
41import org.onosproject.p4runtime.api.P4RuntimeEventListener;
Andrea Campanella288b2732017-07-28 14:16:16 +020042import org.onosproject.p4runtime.api.P4RuntimePacketIn;
Carmelo Cascone4c289b72019-01-22 15:30:45 -080043import org.osgi.service.component.annotations.Activate;
44import org.osgi.service.component.annotations.Component;
45import org.osgi.service.component.annotations.Deactivate;
46import org.osgi.service.component.annotations.Reference;
47import org.osgi.service.component.annotations.ReferenceCardinality;
wu2883c762017-07-20 16:24:48 +080048import org.slf4j.Logger;
49
50import java.nio.ByteBuffer;
51
52import static org.onosproject.net.flow.DefaultTrafficTreatment.emptyTreatment;
53import static org.slf4j.LoggerFactory.getLogger;
54
55/**
56 * Implementation of a packet provider for P4Runtime device.
57 */
58@Component(immediate = true)
59public class P4RuntimePacketProvider extends AbstractProvider implements PacketProvider {
60
61 private final Logger log = getLogger(getClass());
62
Ray Milkeyd84f89b2018-08-17 14:54:17 -070063 @Reference(cardinality = ReferenceCardinality.MANDATORY)
wu2883c762017-07-20 16:24:48 +080064 protected P4RuntimeController controller;
65
Ray Milkeyd84f89b2018-08-17 14:54:17 -070066 @Reference(cardinality = ReferenceCardinality.MANDATORY)
wu2883c762017-07-20 16:24:48 +080067 protected PacketProviderRegistry providerRegistry;
68
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069 @Reference(cardinality = ReferenceCardinality.MANDATORY)
wu2883c762017-07-20 16:24:48 +080070 protected DeviceService deviceService;
71
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanella14e196d2017-07-24 18:11:36 +020073 protected MastershipService mastershipService;
74
wu2883c762017-07-20 16:24:48 +080075 private PacketProviderService providerService;
76
77 private InternalPacketListener packetListener = new InternalPacketListener();
78
79 /**
80 * Creates a new P4Runtime packet provider.
81 */
82 public P4RuntimePacketProvider() {
83 super(new ProviderId("p4runtime", "org.onosproject.provider.p4runtime.packet"));
84 }
85
86 @Activate
87 protected void activate() {
88 providerService = providerRegistry.register(this);
89 controller.addListener(packetListener);
90 log.info("Started");
91 }
92
93 @Deactivate
94 public void deactivate() {
95 controller.removeListener(packetListener);
96 providerRegistry.unregister(this);
97 providerService = null;
98 log.info("Stopped");
99 }
100
101 @Override
102 public void emit(OutboundPacket packet) {
103 if (packet != null) {
104 DeviceId deviceId = packet.sendThrough();
105 Device device = deviceService.getDevice(deviceId);
Andrea Campanella14e196d2017-07-24 18:11:36 +0200106 if (device.is(PacketProgrammable.class) && mastershipService.isLocalMaster(deviceId)) {
wu2883c762017-07-20 16:24:48 +0800107 PacketProgrammable packetProgrammable = device.as(PacketProgrammable.class);
108 packetProgrammable.emit(packet);
109 } else {
110 log.warn("No PacketProgrammable behavior for device {}", deviceId);
111 }
112 }
113 }
114
Carmelo Cascone4becd352019-08-27 16:06:55 -0700115 private EthType.EtherType getEtherType(ByteBuffer data) {
116 final short shortEthType = data.getShort(12);
117 data.rewind();
118 return EthType.EtherType.lookup(shortEthType);
119 }
120
wu2883c762017-07-20 16:24:48 +0800121 /**
122 * Internal packet context implementation.
123 */
124 private class P4RuntimePacketContext extends DefaultPacketContext {
125
126 P4RuntimePacketContext(long time, InboundPacket inPkt, OutboundPacket outPkt, boolean block) {
127 super(time, inPkt, outPkt, block);
128 }
129
130 @Override
131 public void send() {
132
133 if (this.block()) {
134 log.info("Unable to send, packet context is blocked");
135 return;
136 }
137
138 DeviceId deviceId = outPacket().sendThrough();
139 ByteBuffer rawData = outPacket().data();
140
141 TrafficTreatment treatment;
142 if (outPacket().treatment() == null) {
143 treatment = (treatmentBuilder() == null) ? emptyTreatment() : treatmentBuilder().build();
144 } else {
145 treatment = outPacket().treatment();
146 }
147
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200148 OutboundPacket outboundPacket = new DefaultOutboundPacket(deviceId, treatment, rawData);
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200149
150 emit(outboundPacket);
wu2883c762017-07-20 16:24:48 +0800151 }
152 }
153
154 /**
155 * Internal packet listener to handle packet-in events received from the P4Runtime controller.
156 */
157 private class InternalPacketListener implements P4RuntimeEventListener {
158
wu2883c762017-07-20 16:24:48 +0800159 @Override
160 public void event(P4RuntimeEvent event) {
Andrea Campanella14e196d2017-07-24 18:11:36 +0200161 //Masterhip message is sent to everybody but picked up only by master.
162 //FIXME we need the device ID into p4RuntimeEvnetSubject to check for mastsership
163 if (!(event.subject() instanceof P4RuntimePacketIn) || event.type() != P4RuntimeEvent.Type.PACKET_IN) {
Carmelo Cascone4becd352019-08-27 16:06:55 -0700164 log.debug("Unrecognized event type {}, discarding", event.type());
Yi Tseng3e7f1452017-10-20 10:31:53 -0700165 // Not a packet-in event, ignore it.
166 return;
167 }
Andrea Campanella288b2732017-07-28 14:16:16 +0200168 P4RuntimePacketIn eventSubject = (P4RuntimePacketIn) event.subject();
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200169 DeviceId deviceId = eventSubject.deviceId();
170
171 Device device = deviceService.getDevice(eventSubject.deviceId());
172 if (device == null) {
173 log.warn("Unable to process packet-in from {}, device is null in the core", deviceId);
174 return;
Andrea Campanella288b2732017-07-28 14:16:16 +0200175 }
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200176
177 if (!device.is(PiPipelineInterpreter.class)) {
178 log.warn("Unable to process packet-in from {}, device has no PiPipelineInterpreter behaviour",
Andrea Campanella14e196d2017-07-24 18:11:36 +0200179 deviceId);
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200180 return;
181 }
182
183 PiPacketOperation operation = eventSubject.packetOperation();
184 InboundPacket inPkt;
185 try {
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800186 inPkt = device.as(PiPipelineInterpreter.class).mapInboundPacket(operation, deviceId);
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200187 } catch (PiPipelineInterpreter.PiInterpreterException e) {
188 log.warn("Unable to interpret inbound packet from {}: {}", deviceId, e.getMessage());
189 return;
190 }
191
Carmelo Cascone4becd352019-08-27 16:06:55 -0700192 if (log.isTraceEnabled()) {
193 final EthType.EtherType etherType = getEtherType(inPkt.unparsed());
194 log.trace("Received PACKET-IN <<< device={} ingress_port={} eth_type={}",
195 inPkt.receivedFrom().deviceId(), inPkt.receivedFrom().port(),
196 etherType.ethType().toString());
197 }
198
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200199 if (inPkt == null) {
200 log.debug("Received null inbound packet. Ignoring.");
201 return;
202 }
203
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200204 OutboundPacket outPkt = new DefaultOutboundPacket(eventSubject.deviceId(), null,
Andrea Campanella14e196d2017-07-24 18:11:36 +0200205 operation.data().asReadOnlyBuffer());
Carmelo Cascone5bff7ca2017-09-12 15:11:03 +0200206 PacketContext pktCtx = new P4RuntimePacketContext(System.currentTimeMillis(), inPkt, outPkt, false);
207
208 // Pushing the packet context up for processing.
209 providerService.processPacket(pktCtx);
wu2883c762017-07-20 16:24:48 +0800210 }
211 }
212}