blob: 3219a6cf8c907f5070c1d141aee6eea4d19b3b60 [file] [log] [blame]
Andrea Campanella241896c2017-05-10 13:11:04 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Andrea Campanella241896c2017-05-10 13:11:04 -07003 *
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
Andrea Campanella0288c872017-08-07 18:32:51 +020017package org.onosproject.drivers.p4runtime;
Andrea Campanella241896c2017-05-10 13:11:04 -070018
Carmelo Cascone3977ea42019-02-28 13:43:42 -080019import org.onosproject.cluster.ClusterService;
Carmelo Casconec2be50a2019-04-10 00:15:39 -070020import org.onosproject.grpc.utils.AbstractGrpcHandshaker;
Andrea Campanella241896c2017-05-10 13:11:04 -070021import org.onosproject.net.MastershipRole;
Carmelo Casconee5b28722018-06-22 17:28:28 +020022import org.onosproject.net.device.DeviceAgentListener;
Andrea Campanella241896c2017-05-10 13:11:04 -070023import org.onosproject.net.device.DeviceHandshaker;
pierventre64462f12022-02-24 10:13:06 -080024import org.onosproject.net.pi.model.PiPipeconf;
25import org.onosproject.net.pi.service.PiPipeconfService;
Carmelo Cascone3977ea42019-02-28 13:43:42 -080026import org.onosproject.net.pi.service.PiPipeconfWatchdogService;
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070027import org.onosproject.net.provider.ProviderId;
Carmelo Cascone158b8c42018-07-04 19:42:37 +020028import org.onosproject.p4runtime.api.P4RuntimeClient;
Carmelo Cascone59f57de2017-07-11 19:55:09 -040029import org.onosproject.p4runtime.api.P4RuntimeController;
Andrea Campanella241896c2017-05-10 13:11:04 -070030
Carmelo Cascone3977ea42019-02-28 13:43:42 -080031import java.math.BigInteger;
pierventre64462f12022-02-24 10:13:06 -080032import java.util.Optional;
Andrea Campanella241896c2017-05-10 13:11:04 -070033import java.util.concurrent.CompletableFuture;
34
Carmelo Cascone3977ea42019-02-28 13:43:42 -080035import static java.util.concurrent.CompletableFuture.completedFuture;
Carmelo Casconec2be50a2019-04-10 00:15:39 -070036import static org.onosproject.drivers.p4runtime.P4RuntimeDriverUtils.extractP4DeviceId;
Carmelo Cascone3977ea42019-02-28 13:43:42 -080037
Andrea Campanella241896c2017-05-10 13:11:04 -070038/**
Carmelo Casconee3a7c742017-09-01 01:25:52 +020039 * Implementation of DeviceHandshaker for P4Runtime.
Andrea Campanella241896c2017-05-10 13:11:04 -070040 */
Carmelo Casconec2be50a2019-04-10 00:15:39 -070041public class P4RuntimeHandshaker
42 extends AbstractGrpcHandshaker<P4RuntimeClient, P4RuntimeController>
43 implements DeviceHandshaker {
Andrea Campanella241896c2017-05-10 13:11:04 -070044
Carmelo Cascone3977ea42019-02-28 13:43:42 -080045 // This is needed to compute an election ID based on mastership term and
46 // preference. At the time of writing the practical maximum cluster size is
47 // 9. Since election IDs are 128bit numbers, we should'nt be too worried of
48 // being conservative when setting a static max size here. Making the
49 // cluster size dynamic would likely cause conflicts when generating
50 // election IDs (e.g. two nodes seeing different cluster sizes).
51 private static final int MAX_CLUSTER_SIZE = 20;
52
Carmelo Casconec2be50a2019-04-10 00:15:39 -070053 private Long p4DeviceId;
54
55 public P4RuntimeHandshaker() {
56 super(P4RuntimeController.class);
Carmelo Cascone3977ea42019-02-28 13:43:42 -080057 }
58
Carmelo Casconec2be50a2019-04-10 00:15:39 -070059 @Override
60 protected boolean setupBehaviour(String opName) {
61 if (!super.setupBehaviour(opName)) {
Carmelo Cascone3977ea42019-02-28 13:43:42 -080062 return false;
63 }
Carmelo Casconec2be50a2019-04-10 00:15:39 -070064
65 p4DeviceId = extractP4DeviceId(mgmtUriFromNetcfg());
66 if (p4DeviceId == null) {
67 log.warn("Unable to obtain the P4Runtime-internal device_id from " +
68 "config of {}, cannot perform {}",
69 deviceId, opName);
Carmelo Cascone3977ea42019-02-28 13:43:42 -080070 return false;
71 }
72 return true;
Andrea Campanella241896c2017-05-10 13:11:04 -070073 }
74
75 @Override
Carmelo Cascone3977ea42019-02-28 13:43:42 -080076 public boolean isAvailable() {
77 // To be available, we require a session open (for packet in/out) and a
78 // pipeline config set.
Carmelo Casconec2be50a2019-04-10 00:15:39 -070079 if (!setupBehaviour("isAvailable()") ||
80 !client.isServerReachable() ||
81 !client.isSessionOpen(p4DeviceId)) {
Carmelo Cascone3977ea42019-02-28 13:43:42 -080082 return false;
83 }
84 // Since we cannot probe the device, we rely on what's known by the
85 // pipeconf watchdog service.
86 return PiPipeconfWatchdogService.PipelineStatus.READY.equals(
87 handler().get(PiPipeconfWatchdogService.class)
88 .getStatus(data().deviceId()));
89 }
90
91 @Override
92 public CompletableFuture<Boolean> probeAvailability() {
93 // To be available, we require a session open (for packet in/out) and a
94 // pipeline config set.
Carmelo Casconec2be50a2019-04-10 00:15:39 -070095 if (!setupBehaviour("probeAvailability()") ||
96 !client.isServerReachable() ||
97 !client.isSessionOpen(p4DeviceId)) {
Carmelo Cascone3977ea42019-02-28 13:43:42 -080098 return completedFuture(false);
99 }
pierventre64462f12022-02-24 10:13:06 -0800100
101 PiPipeconfService piPipeconfService = handler().get(PiPipeconfService.class);
102 final Optional<PiPipeconf> optionalPiPipeconf = piPipeconfService.getPipeconf(deviceId);
103 if (optionalPiPipeconf.isEmpty()) {
104 return completedFuture(false);
105 }
106
107 if (!PiPipeconfWatchdogService.PipelineStatus.READY.equals(
108 handler().get(PiPipeconfWatchdogService.class)
109 .getStatus(data().deviceId()))) {
110 return completedFuture(false);
111 }
112
113 return client.isPipelineConfigSet(p4DeviceId, optionalPiPipeconf.get());
Andrea Campanella241896c2017-05-10 13:11:04 -0700114 }
115
116 @Override
Carmelo Casconee5b28722018-06-22 17:28:28 +0200117 public void roleChanged(MastershipRole newRole) {
Carmelo Casconec32976e2019-04-08 14:50:52 -0700118 if (!setupBehaviour("roleChanged()")) {
119 return;
120 }
Carmelo Cascone3977ea42019-02-28 13:43:42 -0800121 if (newRole.equals(MastershipRole.NONE)) {
Carmelo Casconec32976e2019-04-08 14:50:52 -0700122 log.info("Notified role NONE, closing session...");
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700123 client.closeSession(p4DeviceId);
Carmelo Cascone3977ea42019-02-28 13:43:42 -0800124 } else {
125 throw new UnsupportedOperationException(
126 "Use preference-based way for setting MASTER or STANDBY roles");
127 }
128 }
129
130 @Override
131 public void roleChanged(int preference, long term) {
Carmelo Casconec32976e2019-04-08 14:50:52 -0700132 if (!setupBehaviour("roleChanged()")) {
133 return;
Yi Tseng3e7f1452017-10-20 10:31:53 -0700134 }
Carmelo Casconec32976e2019-04-08 14:50:52 -0700135 final int clusterSize = handler().get(ClusterService.class)
136 .getNodes().size();
137 if (clusterSize > MAX_CLUSTER_SIZE) {
138 throw new IllegalStateException(
139 "Cluster too big! Maz size supported is " + MAX_CLUSTER_SIZE);
140 }
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700141 final BigInteger electionId = BigInteger.valueOf(term)
Carmelo Casconec32976e2019-04-08 14:50:52 -0700142 .multiply(BigInteger.valueOf(MAX_CLUSTER_SIZE))
143 .subtract(BigInteger.valueOf(preference));
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700144 client.setMastership(p4DeviceId, preference == 0, electionId);
Andrea Campanella241896c2017-05-10 13:11:04 -0700145 }
Andrea Campanella1e573442018-05-17 17:07:13 +0200146
147 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700148 public MastershipRole getRole() {
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700149 if (!setupBehaviour("getRole()") ||
150 !client.isServerReachable() ||
151 !client.isSessionOpen(p4DeviceId)) {
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700152 return MastershipRole.NONE;
153 }
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700154 return client.isMaster(p4DeviceId)
155 ? MastershipRole.MASTER : MastershipRole.STANDBY;
Andrea Campanella1e573442018-05-17 17:07:13 +0200156 }
157
158 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700159 public void addDeviceAgentListener(ProviderId providerId, DeviceAgentListener listener) {
160 // Don't use controller/deviceId class variables as they might be uninitialized.
161 handler().get(P4RuntimeController.class)
162 .addDeviceAgentListener(data().deviceId(), providerId, listener);
163 }
164
165 @Override
166 public void removeDeviceAgentListener(ProviderId providerId) {
Carmelo Cascone7044efd2018-07-06 13:01:36 +0200167 // Don't use controller/deviceId class variable as they might be uninitialized.
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200168 handler().get(P4RuntimeController.class)
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700169 .removeDeviceAgentListener(data().deviceId(), providerId);
Andrea Campanella1e573442018-05-17 17:07:13 +0200170 }
Andrea Campanella241896c2017-05-10 13:11:04 -0700171}