blob: 891517229b122ba9437cd4cde99ac8913b7e6187 [file] [log] [blame]
wu2883c762017-07-20 16:24:48 +08001/*
2 * Copyright 2017-present Open Networking Laboratory
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.provider.p4runtime.packet.impl;
18
19
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onosproject.net.Device;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.device.DeviceService;
28import org.onosproject.net.flow.TrafficTreatment;
29import org.onosproject.net.packet.DefaultOutboundPacket;
30import org.onosproject.net.packet.DefaultPacketContext;
31import org.onosproject.net.packet.InboundPacket;
32import org.onosproject.net.packet.OutboundPacket;
Andrea Campanella288b2732017-07-28 14:16:16 +020033import org.onosproject.net.packet.PacketContext;
wu2883c762017-07-20 16:24:48 +080034import org.onosproject.net.packet.PacketProgrammable;
35import org.onosproject.net.packet.PacketProvider;
36import org.onosproject.net.packet.PacketProviderRegistry;
37import org.onosproject.net.packet.PacketProviderService;
Andrea Campanella288b2732017-07-28 14:16:16 +020038import org.onosproject.net.pi.model.PiPipelineInterpreter;
39import org.onosproject.net.pi.runtime.PiPacketOperation;
wu2883c762017-07-20 16:24:48 +080040import org.onosproject.net.provider.AbstractProvider;
41import org.onosproject.net.provider.ProviderId;
42import org.onosproject.p4runtime.api.P4RuntimeController;
43import org.onosproject.p4runtime.api.P4RuntimeEvent;
44import org.onosproject.p4runtime.api.P4RuntimeEventListener;
Andrea Campanella288b2732017-07-28 14:16:16 +020045import org.onosproject.p4runtime.api.P4RuntimePacketIn;
wu2883c762017-07-20 16:24:48 +080046import org.slf4j.Logger;
47
48import java.nio.ByteBuffer;
49
50import static org.onosproject.net.flow.DefaultTrafficTreatment.emptyTreatment;
51import static org.slf4j.LoggerFactory.getLogger;
52
53/**
54 * Implementation of a packet provider for P4Runtime device.
55 */
56@Component(immediate = true)
57public class P4RuntimePacketProvider extends AbstractProvider implements PacketProvider {
58
59 private final Logger log = getLogger(getClass());
60
61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 protected P4RuntimeController controller;
63
64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected PacketProviderRegistry providerRegistry;
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected DeviceService deviceService;
69
70 private PacketProviderService providerService;
71
72 private InternalPacketListener packetListener = new InternalPacketListener();
73
74 /**
75 * Creates a new P4Runtime packet provider.
76 */
77 public P4RuntimePacketProvider() {
78 super(new ProviderId("p4runtime", "org.onosproject.provider.p4runtime.packet"));
79 }
80
81 @Activate
82 protected void activate() {
83 providerService = providerRegistry.register(this);
84 controller.addListener(packetListener);
85 log.info("Started");
86 }
87
88 @Deactivate
89 public void deactivate() {
90 controller.removeListener(packetListener);
91 providerRegistry.unregister(this);
92 providerService = null;
93 log.info("Stopped");
94 }
95
96 @Override
97 public void emit(OutboundPacket packet) {
98 if (packet != null) {
99 DeviceId deviceId = packet.sendThrough();
100 Device device = deviceService.getDevice(deviceId);
101 if (device.is(PacketProgrammable.class)) {
102 PacketProgrammable packetProgrammable = device.as(PacketProgrammable.class);
103 packetProgrammable.emit(packet);
104 } else {
105 log.warn("No PacketProgrammable behavior for device {}", deviceId);
106 }
107 }
108 }
109
110 /**
111 * Internal packet context implementation.
112 */
113 private class P4RuntimePacketContext extends DefaultPacketContext {
114
115 P4RuntimePacketContext(long time, InboundPacket inPkt, OutboundPacket outPkt, boolean block) {
116 super(time, inPkt, outPkt, block);
117 }
118
119 @Override
120 public void send() {
121
122 if (this.block()) {
123 log.info("Unable to send, packet context is blocked");
124 return;
125 }
126
127 DeviceId deviceId = outPacket().sendThrough();
128 ByteBuffer rawData = outPacket().data();
129
130 TrafficTreatment treatment;
131 if (outPacket().treatment() == null) {
132 treatment = (treatmentBuilder() == null) ? emptyTreatment() : treatmentBuilder().build();
133 } else {
134 treatment = outPacket().treatment();
135 }
136
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200137 OutboundPacket outboundPacket = new DefaultOutboundPacket(deviceId, treatment, rawData);
138 log.debug("Processing outbound packet: {}", outboundPacket);
139
140 emit(outboundPacket);
wu2883c762017-07-20 16:24:48 +0800141 }
142 }
143
144 /**
145 * Internal packet listener to handle packet-in events received from the P4Runtime controller.
146 */
147 private class InternalPacketListener implements P4RuntimeEventListener {
148
wu2883c762017-07-20 16:24:48 +0800149 @Override
150 public void event(P4RuntimeEvent event) {
Andrea Campanella288b2732017-07-28 14:16:16 +0200151 P4RuntimePacketIn eventSubject = (P4RuntimePacketIn) event.subject();
152 if (deviceService.getDevice(eventSubject.deviceId()).is(PiPipelineInterpreter.class)) {
153 PiPacketOperation operation = eventSubject.packetOperation();
154 try {
155 InboundPacket inPkt = deviceService.getDevice(eventSubject.deviceId())
156 .as(PiPipelineInterpreter.class)
157 .mapInboundPacket(eventSubject.deviceId(), operation);
158 //Creating the corresponding outbound Packet
159 //FIXME Wrapping of bytebuffer might be optimized with .asReadOnlyByteBuffer()
160 OutboundPacket outPkt = new DefaultOutboundPacket(eventSubject.deviceId(), null,
161 ByteBuffer.wrap(operation.data().asArray()));
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +0200162 log.debug("Processing inbound packet: {}", inPkt.toString());
Andrea Campanella288b2732017-07-28 14:16:16 +0200163 //Creating PacketContext
164 PacketContext pktCtx = new P4RuntimePacketContext(System.currentTimeMillis(), inPkt, outPkt, false);
165 //Sendign the ctx up for processing.
166 providerService.processPacket(pktCtx);
167 } catch (PiPipelineInterpreter.PiInterpreterException e) {
168 log.error("Can't properly interpret the packetIn", e);
169 }
170 }
wu2883c762017-07-20 16:24:48 +0800171 }
172 }
173}