blob: e689298d5f18fe8df30670a31f45eafe2ad2b0c0 [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;
Carmelo Cascone3977ea42019-02-28 13:43:42 -080024import org.onosproject.net.pi.service.PiPipeconfWatchdogService;
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070025import org.onosproject.net.provider.ProviderId;
Carmelo Cascone158b8c42018-07-04 19:42:37 +020026import org.onosproject.p4runtime.api.P4RuntimeClient;
Carmelo Cascone59f57de2017-07-11 19:55:09 -040027import org.onosproject.p4runtime.api.P4RuntimeController;
Andrea Campanella241896c2017-05-10 13:11:04 -070028
Carmelo Cascone3977ea42019-02-28 13:43:42 -080029import java.math.BigInteger;
Andrea Campanella241896c2017-05-10 13:11:04 -070030import java.util.concurrent.CompletableFuture;
31
Carmelo Cascone3977ea42019-02-28 13:43:42 -080032import static java.util.concurrent.CompletableFuture.completedFuture;
Carmelo Casconec2be50a2019-04-10 00:15:39 -070033import static org.onosproject.drivers.p4runtime.P4RuntimeDriverUtils.extractP4DeviceId;
Carmelo Cascone3977ea42019-02-28 13:43:42 -080034
Andrea Campanella241896c2017-05-10 13:11:04 -070035/**
Carmelo Casconee3a7c742017-09-01 01:25:52 +020036 * Implementation of DeviceHandshaker for P4Runtime.
Andrea Campanella241896c2017-05-10 13:11:04 -070037 */
Carmelo Casconec2be50a2019-04-10 00:15:39 -070038public class P4RuntimeHandshaker
39 extends AbstractGrpcHandshaker<P4RuntimeClient, P4RuntimeController>
40 implements DeviceHandshaker {
Andrea Campanella241896c2017-05-10 13:11:04 -070041
Carmelo Cascone3977ea42019-02-28 13:43:42 -080042 // This is needed to compute an election ID based on mastership term and
43 // preference. At the time of writing the practical maximum cluster size is
44 // 9. Since election IDs are 128bit numbers, we should'nt be too worried of
45 // being conservative when setting a static max size here. Making the
46 // cluster size dynamic would likely cause conflicts when generating
47 // election IDs (e.g. two nodes seeing different cluster sizes).
48 private static final int MAX_CLUSTER_SIZE = 20;
49
Carmelo Casconec2be50a2019-04-10 00:15:39 -070050 private Long p4DeviceId;
51
52 public P4RuntimeHandshaker() {
53 super(P4RuntimeController.class);
Carmelo Cascone3977ea42019-02-28 13:43:42 -080054 }
55
Carmelo Casconec2be50a2019-04-10 00:15:39 -070056 @Override
57 protected boolean setupBehaviour(String opName) {
58 if (!super.setupBehaviour(opName)) {
Carmelo Cascone3977ea42019-02-28 13:43:42 -080059 return false;
60 }
Carmelo Casconec2be50a2019-04-10 00:15:39 -070061
62 p4DeviceId = extractP4DeviceId(mgmtUriFromNetcfg());
63 if (p4DeviceId == null) {
64 log.warn("Unable to obtain the P4Runtime-internal device_id from " +
65 "config of {}, cannot perform {}",
66 deviceId, opName);
Carmelo Cascone3977ea42019-02-28 13:43:42 -080067 return false;
68 }
69 return true;
Andrea Campanella241896c2017-05-10 13:11:04 -070070 }
71
72 @Override
Carmelo Cascone3977ea42019-02-28 13:43:42 -080073 public boolean isAvailable() {
74 // To be available, we require a session open (for packet in/out) and a
75 // pipeline config set.
Carmelo Casconec2be50a2019-04-10 00:15:39 -070076 if (!setupBehaviour("isAvailable()") ||
77 !client.isServerReachable() ||
78 !client.isSessionOpen(p4DeviceId)) {
Carmelo Cascone3977ea42019-02-28 13:43:42 -080079 return false;
80 }
81 // Since we cannot probe the device, we rely on what's known by the
82 // pipeconf watchdog service.
83 return PiPipeconfWatchdogService.PipelineStatus.READY.equals(
84 handler().get(PiPipeconfWatchdogService.class)
85 .getStatus(data().deviceId()));
86 }
87
88 @Override
89 public CompletableFuture<Boolean> probeAvailability() {
90 // To be available, we require a session open (for packet in/out) and a
91 // pipeline config set.
Carmelo Casconec2be50a2019-04-10 00:15:39 -070092 if (!setupBehaviour("probeAvailability()") ||
93 !client.isServerReachable() ||
94 !client.isSessionOpen(p4DeviceId)) {
Carmelo Cascone3977ea42019-02-28 13:43:42 -080095 return completedFuture(false);
96 }
Carmelo Casconec2be50a2019-04-10 00:15:39 -070097 return client.isAnyPipelineConfigSet(p4DeviceId);
Andrea Campanella241896c2017-05-10 13:11:04 -070098 }
99
100 @Override
Carmelo Casconee5b28722018-06-22 17:28:28 +0200101 public void roleChanged(MastershipRole newRole) {
Carmelo Casconec32976e2019-04-08 14:50:52 -0700102 if (!setupBehaviour("roleChanged()")) {
103 return;
104 }
Carmelo Cascone3977ea42019-02-28 13:43:42 -0800105 if (newRole.equals(MastershipRole.NONE)) {
Carmelo Casconec32976e2019-04-08 14:50:52 -0700106 log.info("Notified role NONE, closing session...");
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700107 client.closeSession(p4DeviceId);
Carmelo Cascone3977ea42019-02-28 13:43:42 -0800108 } else {
109 throw new UnsupportedOperationException(
110 "Use preference-based way for setting MASTER or STANDBY roles");
111 }
112 }
113
114 @Override
115 public void roleChanged(int preference, long term) {
Carmelo Casconec32976e2019-04-08 14:50:52 -0700116 if (!setupBehaviour("roleChanged()")) {
117 return;
Yi Tseng3e7f1452017-10-20 10:31:53 -0700118 }
Carmelo Casconec32976e2019-04-08 14:50:52 -0700119 final int clusterSize = handler().get(ClusterService.class)
120 .getNodes().size();
121 if (clusterSize > MAX_CLUSTER_SIZE) {
122 throw new IllegalStateException(
123 "Cluster too big! Maz size supported is " + MAX_CLUSTER_SIZE);
124 }
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700125 final BigInteger electionId = BigInteger.valueOf(term)
Carmelo Casconec32976e2019-04-08 14:50:52 -0700126 .multiply(BigInteger.valueOf(MAX_CLUSTER_SIZE))
127 .subtract(BigInteger.valueOf(preference));
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700128 client.setMastership(p4DeviceId, preference == 0, electionId);
Andrea Campanella241896c2017-05-10 13:11:04 -0700129 }
Andrea Campanella1e573442018-05-17 17:07:13 +0200130
131 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700132 public MastershipRole getRole() {
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700133 if (!setupBehaviour("getRole()") ||
134 !client.isServerReachable() ||
135 !client.isSessionOpen(p4DeviceId)) {
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700136 return MastershipRole.NONE;
137 }
Carmelo Casconec2be50a2019-04-10 00:15:39 -0700138 return client.isMaster(p4DeviceId)
139 ? MastershipRole.MASTER : MastershipRole.STANDBY;
Andrea Campanella1e573442018-05-17 17:07:13 +0200140 }
141
142 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700143 public void addDeviceAgentListener(ProviderId providerId, DeviceAgentListener listener) {
144 // Don't use controller/deviceId class variables as they might be uninitialized.
145 handler().get(P4RuntimeController.class)
146 .addDeviceAgentListener(data().deviceId(), providerId, listener);
147 }
148
149 @Override
150 public void removeDeviceAgentListener(ProviderId providerId) {
Carmelo Cascone7044efd2018-07-06 13:01:36 +0200151 // Don't use controller/deviceId class variable as they might be uninitialized.
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200152 handler().get(P4RuntimeController.class)
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700153 .removeDeviceAgentListener(data().deviceId(), providerId);
Andrea Campanella1e573442018-05-17 17:07:13 +0200154 }
Andrea Campanella241896c2017-05-10 13:11:04 -0700155}