blob: 127230585e8dae07a9d578234c7a4aea3e971939 [file] [log] [blame]
Carmelo Casconed61fdb32017-10-30 10:09:57 -07001/*
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.drivers.p4runtime;
18
19import org.onlab.util.SharedExecutors;
20import org.onosproject.net.DeviceId;
21import org.onosproject.net.driver.AbstractHandlerBehaviour;
22import org.onosproject.net.pi.model.PiPipeconf;
23import org.onosproject.net.pi.model.PiPipelineProgrammable;
24import org.onosproject.p4runtime.api.P4RuntimeClient;
25import org.onosproject.p4runtime.api.P4RuntimeController;
26import org.slf4j.Logger;
27
28import java.nio.ByteBuffer;
29import java.util.Optional;
30import java.util.concurrent.CompletableFuture;
31import java.util.concurrent.ExecutionException;
32
33import static org.slf4j.LoggerFactory.getLogger;
34
35/**
36 * Abstract implementation of the PiPipelineProgrammable behaviours for a P4Runtime device.
37 */
38public abstract class AbstractP4RuntimePipelineProgrammable extends AbstractHandlerBehaviour
39 implements PiPipelineProgrammable {
40
41 protected final Logger log = getLogger(getClass());
42
43 /**
44 * Returns a byte buffer representing the target-specific device data to be used in the SetPipelineConfig message.
45 *
46 * @param pipeconf pipeconf
47 * @return byte buffer
48 */
49 public abstract ByteBuffer createDeviceDataBuffer(PiPipeconf pipeconf);
50
51 @Override
52 public CompletableFuture<Boolean> deployPipeconf(PiPipeconf pipeconf) {
53 return CompletableFuture.supplyAsync(
54 () -> doDeployConfig(pipeconf),
55 SharedExecutors.getPoolThreadExecutor());
56 }
57
58 private boolean doDeployConfig(PiPipeconf pipeconf) {
59
60 DeviceId deviceId = handler().data().deviceId();
61 P4RuntimeController controller = handler().get(P4RuntimeController.class);
62
63 if (!controller.hasClient(deviceId)) {
64 log.warn("Unable to find client for {}, aborting pipeconf deploy", deviceId);
65 return false;
66 }
67 P4RuntimeClient client = controller.getClient(deviceId);
68
69 ByteBuffer deviceDataBuffer = createDeviceDataBuffer(pipeconf);
70 if (deviceDataBuffer == null) {
71 // Hopefully the child class logged the problem.
72 return false;
73 }
74
75 try {
76 if (!client.setPipelineConfig(pipeconf, deviceDataBuffer).get()) {
77 log.warn("Unable to deploy pipeconf {} to {}", pipeconf.id(), deviceId);
78 return false;
79 }
80 } catch (InterruptedException | ExecutionException e) {
81 log.error("Exception while deploying pipeconf to {}", deviceId, e);
82 return false;
83 }
84
85 try {
86 // It would make more sense to init the stream channel once the client
87 // is created, but P4runtime would reject any command if a P4info has
88 // not been set first.
89 if (!client.initStreamChannel().get()) {
90 log.warn("Unable to init stream channel to {}.", deviceId);
91 return false;
92 }
93 } catch (InterruptedException | ExecutionException e) {
94 log.error("Exception while initializing stream channel on {}", deviceId, e);
95 return false;
96 }
97
98 return true;
99 }
100
101 @Override
102 public abstract Optional<PiPipeconf> getDefaultPipeconf();
103}