blob: d134a22fc83db83fd62065d64620b2ddd1839fc6 [file] [log] [blame]
Carmelo Casconef7aa3f92017-07-06 23:56:50 -04001/*
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.p4runtime.ctl;
18
19import com.google.common.collect.Maps;
20import io.grpc.ManagedChannel;
21import io.grpc.ManagedChannelBuilder;
22import io.grpc.NameResolverProvider;
23import io.grpc.internal.DnsNameResolverProvider;
24import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
27import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.apache.felix.scr.annotations.Service;
30import org.onosproject.event.AbstractListenerManager;
31import org.onosproject.grpc.api.GrpcChannelId;
32import org.onosproject.grpc.api.GrpcController;
33import org.onosproject.net.DeviceId;
34import org.onosproject.p4runtime.api.P4RuntimeClient;
35import org.onosproject.p4runtime.api.P4RuntimeController;
36import org.onosproject.p4runtime.api.P4RuntimeEvent;
37import org.onosproject.p4runtime.api.P4RuntimeEventListener;
38import org.slf4j.Logger;
39
40import java.io.IOException;
41import java.util.Map;
Carmelo Cascone59f57de2017-07-11 19:55:09 -040042import java.util.concurrent.locks.ReadWriteLock;
43import java.util.concurrent.locks.ReentrantReadWriteLock;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040044
45import static com.google.common.base.Preconditions.checkNotNull;
46import static java.lang.String.format;
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040047import static org.slf4j.LoggerFactory.getLogger;
48
49/**
50 * P4Runtime controller implementation.
51 */
52@Component(immediate = true)
53@Service
54public class P4RuntimeControllerImpl
55 extends AbstractListenerManager<P4RuntimeEvent, P4RuntimeEventListener>
56 implements P4RuntimeController {
57
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040058 private final Logger log = getLogger(getClass());
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040059 private final NameResolverProvider nameResolverProvider = new DnsNameResolverProvider();
Carmelo Cascone59f57de2017-07-11 19:55:09 -040060 private final Map<DeviceId, P4RuntimeClient> clients = Maps.newHashMap();
61 private final Map<DeviceId, GrpcChannelId> channelIds = Maps.newHashMap();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040062 // TODO: should use a cache to delete unused locks.
Carmelo Cascone59f57de2017-07-11 19:55:09 -040063 private final Map<DeviceId, ReadWriteLock> deviceLocks = Maps.newConcurrentMap();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040064
Carmelo Cascone8d99b172017-07-18 17:26:31 -040065 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Carmelo Casconec8e84982017-07-26 15:34:42 -040066 public GrpcController grpcController;
Carmelo Cascone8d99b172017-07-18 17:26:31 -040067
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040068 @Activate
69 public void activate() {
70 log.info("Started");
71 }
72
73
74 @Deactivate
75 public void deactivate() {
76 grpcController = null;
77 log.info("Stopped");
78 }
79
80
81 @Override
82 public boolean createClient(DeviceId deviceId, int p4DeviceId, ManagedChannelBuilder channelBuilder) {
83 checkNotNull(deviceId);
84 checkNotNull(channelBuilder);
85
Carmelo Cascone59f57de2017-07-11 19:55:09 -040086 deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
87 deviceLocks.get(deviceId).writeLock().lock();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040088
89 log.info("Creating client for {} (with internal device id {})...", deviceId, p4DeviceId);
90
91 try {
92 if (clients.containsKey(deviceId)) {
93 throw new IllegalStateException(format("A client already exists for %s", deviceId));
94 } else {
95 return doCreateClient(deviceId, p4DeviceId, channelBuilder);
96 }
97 } finally {
Carmelo Cascone59f57de2017-07-11 19:55:09 -040098 deviceLocks.get(deviceId).writeLock().unlock();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -040099 }
100 }
101
102 private boolean doCreateClient(DeviceId deviceId, int p4DeviceId, ManagedChannelBuilder channelBuilder) {
Carmelo Cascone59f57de2017-07-11 19:55:09 -0400103
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400104 GrpcChannelId channelId = GrpcChannelId.of(deviceId, "p4runtime");
105
106 // Channel defaults.
107 channelBuilder.nameResolverFactory(nameResolverProvider);
108
109 ManagedChannel channel;
110 try {
111 channel = grpcController.connectChannel(channelId, channelBuilder);
112 } catch (IOException e) {
113 log.warn("Unable to connect to gRPC server of {}: {}", deviceId, e.getMessage());
114 return false;
115 }
116
Carmelo Cascone8d99b172017-07-18 17:26:31 -0400117 P4RuntimeClient client = new P4RuntimeClientImpl(deviceId, p4DeviceId, channel, this);
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400118
119 channelIds.put(deviceId, channelId);
120 clients.put(deviceId, client);
121
122 return true;
123 }
124
125 @Override
126 public P4RuntimeClient getClient(DeviceId deviceId) {
127
Carmelo Cascone59f57de2017-07-11 19:55:09 -0400128 deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
129 deviceLocks.get(deviceId).readLock().lock();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400130
131 try {
132 return clients.get(deviceId);
133 } finally {
Carmelo Cascone59f57de2017-07-11 19:55:09 -0400134 deviceLocks.get(deviceId).readLock().unlock();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400135 }
136 }
137
138 @Override
139 public void removeClient(DeviceId deviceId) {
140
Carmelo Cascone59f57de2017-07-11 19:55:09 -0400141 deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
142 deviceLocks.get(deviceId).writeLock().lock();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400143
144 try {
145 if (clients.containsKey(deviceId)) {
146 clients.get(deviceId).shutdown();
147 grpcController.disconnectChannel(channelIds.get(deviceId));
148 clients.remove(deviceId);
Carmelo Cascone59f57de2017-07-11 19:55:09 -0400149 channelIds.remove(deviceId);
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400150 }
151 } finally {
Carmelo Cascone59f57de2017-07-11 19:55:09 -0400152 deviceLocks.get(deviceId).writeLock().unlock();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400153 }
154 }
155
156 @Override
157 public boolean hasClient(DeviceId deviceId) {
158
Carmelo Cascone59f57de2017-07-11 19:55:09 -0400159 deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
160 deviceLocks.get(deviceId).readLock().lock();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400161
162 try {
163 return clients.containsKey(deviceId);
164 } finally {
Carmelo Cascone59f57de2017-07-11 19:55:09 -0400165 deviceLocks.get(deviceId).readLock().unlock();
166 }
167 }
168
169 @Override
170 public boolean isReacheable(DeviceId deviceId) {
171
172 deviceLocks.putIfAbsent(deviceId, new ReentrantReadWriteLock());
173 deviceLocks.get(deviceId).readLock().lock();
174
175 try {
176 if (!clients.containsKey(deviceId)) {
177 log.warn("No client for {}, can't check for reachability", deviceId);
178 return false;
179 }
180
181 return grpcController.isChannelOpen(channelIds.get(deviceId));
182 } finally {
183 deviceLocks.get(deviceId).readLock().unlock();
Carmelo Casconef7aa3f92017-07-06 23:56:50 -0400184 }
185 }
186
187 void postEvent(P4RuntimeEvent event) {
188 post(event);
189 }
190}