blob: affbf7d7411bafa376bd25b2568a3ecefeca6e06 [file] [log] [blame]
Carmelo Casconef7aa3f92017-07-06 23:56:50 -04001/*
Carmelo Cascone4c289b72019-01-22 15:30:45 -08002 * Copyright 2019-present Open Networking Foundation
Carmelo Casconef7aa3f92017-07-06 23:56:50 -04003 *
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
Carmelo Cascone4c289b72019-01-22 15:30:45 -080017package org.onosproject.p4runtime.ctl.controller;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040018
19import com.google.common.collect.Maps;
20import io.grpc.ManagedChannel;
Yi Tseng2a340f72018-11-02 16:52:47 -070021import org.onosproject.grpc.ctl.AbstractGrpcClientController;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040022import org.onosproject.net.DeviceId;
Carmelo Casconee5b28722018-06-22 17:28:28 +020023import org.onosproject.net.device.DeviceAgentEvent;
24import org.onosproject.net.device.DeviceAgentListener;
Carmelo Cascone4c289b72019-01-22 15:30:45 -080025import org.onosproject.net.pi.service.PiPipeconfService;
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070026import org.onosproject.net.provider.ProviderId;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040027import org.onosproject.p4runtime.api.P4RuntimeClient;
Yi Tseng2a340f72018-11-02 16:52:47 -070028import org.onosproject.p4runtime.api.P4RuntimeClientKey;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040029import org.onosproject.p4runtime.api.P4RuntimeController;
30import org.onosproject.p4runtime.api.P4RuntimeEvent;
31import org.onosproject.p4runtime.api.P4RuntimeEventListener;
Carmelo Cascone4c289b72019-01-22 15:30:45 -080032import org.onosproject.p4runtime.ctl.client.P4RuntimeClientImpl;
Yi Tseng3e7f1452017-10-20 10:31:53 -070033import org.onosproject.store.service.StorageService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070034import org.osgi.service.component.annotations.Activate;
35import org.osgi.service.component.annotations.Component;
36import org.osgi.service.component.annotations.Deactivate;
37import org.osgi.service.component.annotations.Reference;
38import org.osgi.service.component.annotations.ReferenceCardinality;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040039import org.slf4j.Logger;
40
Carmelo Casconee5b28722018-06-22 17:28:28 +020041import java.math.BigInteger;
Carmelo Casconee5b28722018-06-22 17:28:28 +020042import java.util.concurrent.ConcurrentMap;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040043
44import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040045import static org.slf4j.LoggerFactory.getLogger;
46
47/**
48 * P4Runtime controller implementation.
49 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070050@Component(immediate = true, service = P4RuntimeController.class)
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040051public class P4RuntimeControllerImpl
Yi Tseng2a340f72018-11-02 16:52:47 -070052 extends AbstractGrpcClientController
53 <P4RuntimeClientKey, P4RuntimeClient, P4RuntimeEvent, P4RuntimeEventListener>
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040054 implements P4RuntimeController {
55
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040056 private final Logger log = getLogger(getClass());
Carmelo Cascone158b8c42018-07-04 19:42:37 +020057
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070058 private final ConcurrentMap<DeviceId, ConcurrentMap<ProviderId, DeviceAgentListener>>
59 deviceAgentListeners = Maps.newConcurrentMap();
Carmelo Cascone158b8c42018-07-04 19:42:37 +020060
Carmelo Casconee5b28722018-06-22 17:28:28 +020061 private DistributedElectionIdGenerator electionIdGenerator;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040062
Ray Milkeyd84f89b2018-08-17 14:54:17 -070063 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Carmelo Cascone44448a52018-06-25 23:36:57 +020064 private StorageService storageService;
Yi Tseng3e7f1452017-10-20 10:31:53 -070065
Carmelo Cascone4c289b72019-01-22 15:30:45 -080066 @Reference(cardinality = ReferenceCardinality.MANDATORY)
67 private PiPipeconfService pipeconfService;
68
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040069 @Activate
70 public void activate() {
Yi Tseng2a340f72018-11-02 16:52:47 -070071 super.activate();
Carmelo Cascone2cad9ef2017-08-01 21:52:07 +020072 eventDispatcher.addSink(P4RuntimeEvent.class, listenerRegistry);
Carmelo Casconee5b28722018-06-22 17:28:28 +020073 electionIdGenerator = new DistributedElectionIdGenerator(storageService);
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040074 log.info("Started");
75 }
76
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040077 @Deactivate
78 public void deactivate() {
Yi Tseng2a340f72018-11-02 16:52:47 -070079 super.deactivate();
Carmelo Cascone158b8c42018-07-04 19:42:37 +020080 deviceAgentListeners.clear();
Carmelo Casconee5b28722018-06-22 17:28:28 +020081 electionIdGenerator.destroy();
82 electionIdGenerator = null;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040083 log.info("Stopped");
84 }
85
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040086 @Override
Yi Tseng2a340f72018-11-02 16:52:47 -070087 protected P4RuntimeClient createClientInstance(P4RuntimeClientKey clientKey, ManagedChannel channel) {
Carmelo Cascone4c289b72019-01-22 15:30:45 -080088 return new P4RuntimeClientImpl(clientKey, channel, this, pipeconfService);
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040089 }
90
Yi Tseng3e7f1452017-10-20 10:31:53 -070091 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070092 public void addDeviceAgentListener(DeviceId deviceId, ProviderId providerId, DeviceAgentListener listener) {
Carmelo Cascone7044efd2018-07-06 13:01:36 +020093 checkNotNull(deviceId, "deviceId cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070094 checkNotNull(deviceId, "providerId cannot be null");
Carmelo Cascone7044efd2018-07-06 13:01:36 +020095 checkNotNull(listener, "listener cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -070096 deviceAgentListeners.putIfAbsent(deviceId, Maps.newConcurrentMap());
97 deviceAgentListeners.get(deviceId).put(providerId, listener);
Yi Tseng3e7f1452017-10-20 10:31:53 -070098 }
99
Andrea Campanella1e573442018-05-17 17:07:13 +0200100 @Override
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700101 public void removeDeviceAgentListener(DeviceId deviceId, ProviderId providerId) {
Carmelo Cascone7044efd2018-07-06 13:01:36 +0200102 checkNotNull(deviceId, "deviceId cannot be null");
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700103 checkNotNull(providerId, "listener cannot be null");
Carmelo Casconee5b28722018-06-22 17:28:28 +0200104 deviceAgentListeners.computeIfPresent(deviceId, (did, listeners) -> {
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700105 listeners.remove(providerId);
Carmelo Casconee5b28722018-06-22 17:28:28 +0200106 return listeners;
Andrea Campanella1e573442018-05-17 17:07:13 +0200107 });
108 }
109
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800110 public BigInteger newMasterElectionId(DeviceId deviceId) {
Carmelo Casconee5b28722018-06-22 17:28:28 +0200111 return electionIdGenerator.generate(deviceId);
Andrea Campanella1e573442018-05-17 17:07:13 +0200112 }
113
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800114 public void postEvent(P4RuntimeEvent event) {
Carmelo Casconee5b28722018-06-22 17:28:28 +0200115 switch (event.type()) {
116 case CHANNEL_EVENT:
117 handleChannelEvent(event);
118 break;
119 case ARBITRATION_RESPONSE:
120 handleArbitrationReply(event);
121 break;
Carmelo Casconede3b6842018-09-05 17:45:10 -0700122 case PERMISSION_DENIED:
123 handlePermissionDenied(event);
124 break;
Carmelo Casconee5b28722018-06-22 17:28:28 +0200125 default:
126 post(event);
127 break;
Andrea Campanella1e573442018-05-17 17:07:13 +0200128 }
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400129 }
Carmelo Cascone44448a52018-06-25 23:36:57 +0200130
Carmelo Casconede3b6842018-09-05 17:45:10 -0700131 private void handlePermissionDenied(P4RuntimeEvent event) {
132 postDeviceAgentEvent(event.subject().deviceId(), new DeviceAgentEvent(
133 DeviceAgentEvent.Type.NOT_MASTER, event.subject().deviceId()));
134 }
135
Carmelo Casconee5b28722018-06-22 17:28:28 +0200136 private void handleChannelEvent(P4RuntimeEvent event) {
137 final ChannelEvent channelEvent = (ChannelEvent) event.subject();
138 final DeviceId deviceId = channelEvent.deviceId();
139 final DeviceAgentEvent.Type agentEventType;
140 switch (channelEvent.type()) {
141 case OPEN:
142 agentEventType = DeviceAgentEvent.Type.CHANNEL_OPEN;
143 break;
144 case CLOSED:
145 agentEventType = DeviceAgentEvent.Type.CHANNEL_CLOSED;
146 break;
147 case ERROR:
Carmelo Cascone158b8c42018-07-04 19:42:37 +0200148 agentEventType = !isReachable(deviceId)
Carmelo Casconee5b28722018-06-22 17:28:28 +0200149 ? DeviceAgentEvent.Type.CHANNEL_CLOSED
150 : DeviceAgentEvent.Type.CHANNEL_ERROR;
151 break;
152 default:
153 log.warn("Unrecognized channel event type {}", channelEvent.type());
154 return;
155 }
156 postDeviceAgentEvent(deviceId, new DeviceAgentEvent(agentEventType, deviceId));
157 }
158
159 private void handleArbitrationReply(P4RuntimeEvent event) {
160 final DeviceId deviceId = event.subject().deviceId();
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800161 final ArbitrationUpdateEvent response = (ArbitrationUpdateEvent) event.subject();
Carmelo Casconee5b28722018-06-22 17:28:28 +0200162 final DeviceAgentEvent.Type roleType = response.isMaster()
163 ? DeviceAgentEvent.Type.ROLE_MASTER
164 : DeviceAgentEvent.Type.ROLE_STANDBY;
165 postDeviceAgentEvent(deviceId, new DeviceAgentEvent(
166 roleType, response.deviceId()));
167 }
168
169 private void postDeviceAgentEvent(DeviceId deviceId, DeviceAgentEvent event) {
170 if (deviceAgentListeners.containsKey(deviceId)) {
Carmelo Cascone9e4972c2018-08-30 00:29:16 -0700171 deviceAgentListeners.get(deviceId).values().forEach(l -> l.event(event));
Carmelo Casconee5b28722018-06-22 17:28:28 +0200172 }
173 }
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400174}