blob: 30295d1c1a6c27f85924f71234237622893d4b3b [file] [log] [blame]
Jian Li858ccd72021-02-04 17:25:01 +09001/*
2 * Copyright 2021-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 */
16package org.onosproject.kubevirtnetworking.impl;
17
Jian Li858ccd72021-02-04 17:25:01 +090018import org.onlab.packet.Ethernet;
19import org.onlab.packet.Ip4Address;
20import org.onlab.packet.IpPrefix;
21import org.onosproject.cluster.ClusterService;
22import org.onosproject.cluster.LeadershipService;
23import org.onosproject.cluster.NodeId;
24import org.onosproject.core.ApplicationId;
25import org.onosproject.core.CoreService;
26import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
27import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
Jian Li567b25c2021-05-27 15:17:59 +090028import org.onosproject.kubevirtnetworking.api.KubevirtNetworkEvent;
29import org.onosproject.kubevirtnetworking.api.KubevirtNetworkListener;
Jian Li858ccd72021-02-04 17:25:01 +090030import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
Jian Li858ccd72021-02-04 17:25:01 +090031import org.onosproject.kubevirtnetworking.api.KubevirtPodService;
32import org.onosproject.kubevirtnetworking.api.KubevirtPort;
Jian Lib6dc08f2021-03-24 15:24:18 +090033import org.onosproject.kubevirtnetworking.api.KubevirtPortEvent;
34import org.onosproject.kubevirtnetworking.api.KubevirtPortListener;
Jian Li858ccd72021-02-04 17:25:01 +090035import org.onosproject.kubevirtnetworking.api.KubevirtPortService;
36import org.onosproject.kubevirtnode.api.KubevirtNode;
37import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
38import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
39import org.onosproject.kubevirtnode.api.KubevirtNodeService;
40import org.onosproject.mastership.MastershipService;
41import org.onosproject.net.PortNumber;
42import org.onosproject.net.device.DeviceService;
43import org.onosproject.net.driver.DriverService;
44import org.onosproject.net.flow.DefaultTrafficSelector;
45import org.onosproject.net.flow.DefaultTrafficTreatment;
46import org.onosproject.net.flow.TrafficSelector;
47import org.onosproject.net.flow.TrafficTreatment;
48import org.osgi.service.component.annotations.Activate;
49import org.osgi.service.component.annotations.Component;
50import org.osgi.service.component.annotations.Deactivate;
51import org.osgi.service.component.annotations.Reference;
52import org.osgi.service.component.annotations.ReferenceCardinality;
53import org.slf4j.Logger;
54
55import java.util.Objects;
56import java.util.concurrent.ExecutorService;
57
Jian Li567b25c2021-05-27 15:17:59 +090058import static java.lang.Thread.sleep;
Jian Li858ccd72021-02-04 17:25:01 +090059import static java.util.concurrent.Executors.newSingleThreadExecutor;
60import static org.onlab.util.Tools.groupedThreads;
61import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
62import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_TUNNEL_RULE;
63import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_DEFAULT_TABLE;
64import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.FLAT;
Jian Li2ce718e2021-02-17 20:42:15 +090065import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
Jian Li858ccd72021-02-04 17:25:01 +090066import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelPort;
67import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.tunnelToTenantPort;
68import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildExtension;
69import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.MASTER;
70import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
71import static org.slf4j.LoggerFactory.getLogger;
72
73/**
74 * Populates switching flow rules on OVS for the tenant network (overlay).
75 */
76@Component(immediate = true)
77public class KubevirtSwitchingTenantHandler {
78 private final Logger log = getLogger(getClass());
Jian Li567b25c2021-05-27 15:17:59 +090079 private static final long SLEEP_MS = 3000; // we wait 3s
Jian Li858ccd72021-02-04 17:25:01 +090080
81 @Reference(cardinality = ReferenceCardinality.MANDATORY)
82 protected CoreService coreService;
83 @Reference(cardinality = ReferenceCardinality.MANDATORY)
84 protected MastershipService mastershipService;
85 @Reference(cardinality = ReferenceCardinality.MANDATORY)
86 protected DeviceService deviceService;
87 @Reference(cardinality = ReferenceCardinality.MANDATORY)
88 protected DriverService driverService;
89 @Reference(cardinality = ReferenceCardinality.MANDATORY)
90 protected ClusterService clusterService;
91 @Reference(cardinality = ReferenceCardinality.MANDATORY)
92 protected LeadershipService leadershipService;
93 @Reference(cardinality = ReferenceCardinality.MANDATORY)
94 protected KubevirtFlowRuleService flowRuleService;
95 @Reference(cardinality = ReferenceCardinality.MANDATORY)
96 protected KubevirtNodeService kubevirtNodeService;
97 @Reference(cardinality = ReferenceCardinality.MANDATORY)
98 protected KubevirtNetworkService kubevirtNetworkService;
99 @Reference(cardinality = ReferenceCardinality.MANDATORY)
100 protected KubevirtPortService kubevirtPortService;
101 @Reference(cardinality = ReferenceCardinality.MANDATORY)
102 protected KubevirtPodService kubevirtPodService;
103
104 private final ExecutorService eventExecutor = newSingleThreadExecutor(
105 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
106
Jian Li567b25c2021-05-27 15:17:59 +0900107 private final InternalKubevirtNetworkListener kubevirtNetworkListener =
108 new InternalKubevirtNetworkListener();
Jian Lib6dc08f2021-03-24 15:24:18 +0900109 private final InternalKubevirtPortListener kubevirtPortListener =
110 new InternalKubevirtPortListener();
Jian Li858ccd72021-02-04 17:25:01 +0900111 private final InternalKubevirtNodeListener kubevirtNodeListener =
112 new InternalKubevirtNodeListener();
113
114 private ApplicationId appId;
115 private NodeId localNodeId;
116
117 @Activate
118 protected void activate() {
119 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
120 localNodeId = clusterService.getLocalNode().id();
121 leadershipService.runForLeadership(appId.name());
Jian Lib6dc08f2021-03-24 15:24:18 +0900122 kubevirtPortService.addListener(kubevirtPortListener);
Jian Li567b25c2021-05-27 15:17:59 +0900123 kubevirtNetworkService.addListener(kubevirtNetworkListener);
Jian Li858ccd72021-02-04 17:25:01 +0900124 kubevirtNodeService.addListener(kubevirtNodeListener);
125
126 log.info("Started");
127 }
128
129 @Deactivate
130 protected void deactivate() {
Jian Li567b25c2021-05-27 15:17:59 +0900131 kubevirtNetworkService.removeListener(kubevirtNetworkListener);
Jian Lib6dc08f2021-03-24 15:24:18 +0900132 kubevirtPortService.removeListener(kubevirtPortListener);
Jian Li858ccd72021-02-04 17:25:01 +0900133 kubevirtNodeService.removeListener(kubevirtNodeListener);
134 leadershipService.withdraw(appId.name());
135 eventExecutor.shutdown();
136
137 log.info("Stopped");
138 }
139
Jian Li567b25c2021-05-27 15:17:59 +0900140 private void setIngressRules(KubevirtNetwork network, boolean install) {
Jian Lib6dc08f2021-03-24 15:24:18 +0900141 if (network == null) {
142 return;
143 }
144
145 if (network.type() == FLAT || network.type() == VLAN) {
146 return;
147 }
148
149 if (network.segmentId() == null) {
150 return;
151 }
152
Jian Li567b25c2021-05-27 15:17:59 +0900153 for (KubevirtNode localNode : kubevirtNodeService.completeNodes(WORKER)) {
154
155 while (true) {
156 if (tunnelToTenantPort(localNode, network) != null) {
157 break;
158 } else {
159 try {
160 sleep(SLEEP_MS);
161 } catch (InterruptedException e) {
162 log.error("Failed to install security group default rules.");
163 }
164 }
165 }
166
167 PortNumber patchPortNumber = tunnelToTenantPort(localNode, network);
168
169 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
170 .matchTunnelId(Long.parseLong(network.segmentId()));
171
172 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
173 .setOutput(patchPortNumber);
174
175 flowRuleService.setRule(
176 appId,
177 localNode.tunBridge(),
178 sBuilder.build(),
179 tBuilder.build(),
180 PRIORITY_TUNNEL_RULE,
181 TUNNEL_DEFAULT_TABLE,
182 install);
183
184 log.debug("Install ingress rules for segment ID {}", network.segmentId());
Jian Lib6dc08f2021-03-24 15:24:18 +0900185 }
Jian Li567b25c2021-05-27 15:17:59 +0900186 }
Jian Lib6dc08f2021-03-24 15:24:18 +0900187
Jian Li567b25c2021-05-27 15:17:59 +0900188 private void setIngressRules(KubevirtNode node, boolean install) {
189 for (KubevirtNetwork network : kubevirtNetworkService.tenantNetworks()) {
190 PortNumber patchPortNumber = tunnelToTenantPort(node, network);
191 if (patchPortNumber == null) {
192 return;
193 }
194
195 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
196 .matchTunnelId(Long.parseLong(network.segmentId()));
197
198 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
199 .setOutput(patchPortNumber);
200
201 flowRuleService.setRule(
202 appId,
203 node.tunBridge(),
204 sBuilder.build(),
205 tBuilder.build(),
206 PRIORITY_TUNNEL_RULE,
207 TUNNEL_DEFAULT_TABLE,
208 install);
209
210 log.debug("Install ingress rules for segment ID {}", network.segmentId());
Jian Lib6dc08f2021-03-24 15:24:18 +0900211 }
Jian Lib6dc08f2021-03-24 15:24:18 +0900212 }
213
214 private void setEgressRules(KubevirtPort port, boolean install) {
215 if (port.ipAddress() == null) {
216 return;
217 }
218
219 KubevirtNetwork network = kubevirtNetworkService.network(port.networkId());
220
221 if (network == null) {
222 return;
223 }
224
225 if (network.type() == FLAT || network.type() == VLAN) {
226 return;
227 }
228
229 if (network.segmentId() == null) {
230 return;
231 }
232
233 KubevirtNode localNode = kubevirtNodeService.node(port.deviceId());
234
235 if (localNode == null || localNode.type() == MASTER) {
236 return;
237 }
238
239 for (KubevirtNode remoteNode : kubevirtNodeService.completeNodes(WORKER)) {
240 if (remoteNode.hostname().equals(localNode.hostname())) {
241 continue;
Jian Lid4296d02021-03-12 18:03:58 +0900242 }
243
Jian Lib6dc08f2021-03-24 15:24:18 +0900244 PortNumber patchPortNumber = tunnelToTenantPort(remoteNode, network);
Jian Lid4296d02021-03-12 18:03:58 +0900245 if (patchPortNumber == null) {
246 return;
247 }
248
Jian Lib6dc08f2021-03-24 15:24:18 +0900249 PortNumber tunnelPortNumber = tunnelPort(remoteNode, network);
250 if (tunnelPortNumber == null) {
251 return;
252 }
253
254 TrafficSelector.Builder sIpBuilder = DefaultTrafficSelector.builder()
255 .matchInPort(patchPortNumber)
256 .matchEthType(Ethernet.TYPE_IPV4)
257 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32));
258
259 TrafficSelector.Builder sArpBuilder = DefaultTrafficSelector.builder()
260 .matchInPort(patchPortNumber)
261 .matchEthType(Ethernet.TYPE_ARP)
262 .matchArpTpa(Ip4Address.valueOf(port.ipAddress().toString()));
Jian Lid4296d02021-03-12 18:03:58 +0900263
264 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Jian Lib6dc08f2021-03-24 15:24:18 +0900265 .setTunnelId(Long.parseLong(network.segmentId()))
266 .extension(buildExtension(
267 deviceService,
268 remoteNode.tunBridge(),
269 localNode.dataIp().getIp4Address()),
270 remoteNode.tunBridge())
271 .setOutput(tunnelPortNumber);
Jian Lid4296d02021-03-12 18:03:58 +0900272
273 flowRuleService.setRule(
274 appId,
Jian Lib6dc08f2021-03-24 15:24:18 +0900275 remoteNode.tunBridge(),
276 sIpBuilder.build(),
Jian Lid4296d02021-03-12 18:03:58 +0900277 tBuilder.build(),
278 PRIORITY_TUNNEL_RULE,
279 TUNNEL_DEFAULT_TABLE,
280 install);
281
Jian Lib6dc08f2021-03-24 15:24:18 +0900282 flowRuleService.setRule(
283 appId,
284 remoteNode.tunBridge(),
285 sArpBuilder.build(),
286 tBuilder.build(),
287 PRIORITY_TUNNEL_RULE,
288 TUNNEL_DEFAULT_TABLE,
289 install);
Jian Li858ccd72021-02-04 17:25:01 +0900290 }
291
Jian Lib6dc08f2021-03-24 15:24:18 +0900292 log.debug("Install egress rules for instance {}, segment ID {}",
293 port.ipAddress(), network.segmentId());
Jian Li858ccd72021-02-04 17:25:01 +0900294 }
295
296 private class InternalKubevirtNodeListener implements KubevirtNodeListener {
297
298 private boolean isRelevantHelper() {
299 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
300 }
301
302 @Override
303 public void event(KubevirtNodeEvent event) {
304
305 switch (event.type()) {
306 case KUBEVIRT_NODE_COMPLETE:
307 eventExecutor.execute(() -> processNodeCompletion(event.subject()));
308 break;
309 case KUBEVIRT_NODE_INCOMPLETE:
310 default:
311 // do nothing
312 break;
313 }
314 }
315
316 private void processNodeCompletion(KubevirtNode node) {
317 if (!isRelevantHelper()) {
318 return;
319 }
320
Jian Li567b25c2021-05-27 15:17:59 +0900321 setIngressRules(node, true);
Jian Lib6dc08f2021-03-24 15:24:18 +0900322 kubevirtPortService.ports().stream()
323 .filter(port -> node.equals(kubevirtNodeService.node(port.deviceId())))
324 .forEach(port -> {
Jian Lib6dc08f2021-03-24 15:24:18 +0900325 setEgressRules(port, true);
Jian Li858ccd72021-02-04 17:25:01 +0900326 });
327 }
328 }
329
Jian Li567b25c2021-05-27 15:17:59 +0900330 private class InternalKubevirtNetworkListener implements KubevirtNetworkListener {
331 private boolean isRelevantHelper() {
332 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
333 }
334
335 @Override
336 public void event(KubevirtNetworkEvent event) {
337 switch (event.type()) {
338 case KUBEVIRT_NETWORK_CREATED:
339 eventExecutor.execute(() -> processNetworkAddition(event.subject()));
340 break;
341 case KUBEVIRT_NETWORK_REMOVED:
342 eventExecutor.execute(() -> processNetworkRemoval(event.subject()));
343 break;
344 default:
345 // do nothing
346 break;
347 }
348 }
349
350 private void processNetworkAddition(KubevirtNetwork network) {
351 if (!isRelevantHelper()) {
352 return;
353 }
354
355 setIngressRules(network, true);
356 }
357
358 private void processNetworkRemoval(KubevirtNetwork network) {
359 if (!isRelevantHelper()) {
360 return;
361 }
362
363 setIngressRules(network, false);
364 }
365 }
366
Jian Lib6dc08f2021-03-24 15:24:18 +0900367 private class InternalKubevirtPortListener implements KubevirtPortListener {
368
369 @Override
370 public boolean isRelevant(KubevirtPortEvent event) {
371 return event.subject().deviceId() != null;
372 }
Jian Li858ccd72021-02-04 17:25:01 +0900373
374 private boolean isRelevantHelper() {
375 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
376 }
377
378 @Override
Jian Lib6dc08f2021-03-24 15:24:18 +0900379 public void event(KubevirtPortEvent event) {
Jian Li858ccd72021-02-04 17:25:01 +0900380
381 switch (event.type()) {
Jian Lib6dc08f2021-03-24 15:24:18 +0900382 case KUBEVIRT_PORT_UPDATED:
383 eventExecutor.execute(() -> processPortUpdate(event.subject()));
Jian Li858ccd72021-02-04 17:25:01 +0900384 break;
Jian Lib6dc08f2021-03-24 15:24:18 +0900385 case KUBEVIRT_PORT_REMOVED:
386 eventExecutor.execute(() -> processPortRemoval(event.subject()));
Jian Li858ccd72021-02-04 17:25:01 +0900387 break;
388 default:
389 // do nothing
390 break;
391 }
392 }
393
Jian Lib6dc08f2021-03-24 15:24:18 +0900394 private void processPortUpdate(KubevirtPort port) {
Jian Li858ccd72021-02-04 17:25:01 +0900395 if (!isRelevantHelper()) {
396 return;
397 }
398
Jian Lib6dc08f2021-03-24 15:24:18 +0900399 setEgressRules(port, true);
Jian Li858ccd72021-02-04 17:25:01 +0900400 }
401
Jian Lib6dc08f2021-03-24 15:24:18 +0900402 private void processPortRemoval(KubevirtPort port) {
Jian Li858ccd72021-02-04 17:25:01 +0900403 if (!isRelevantHelper()) {
404 return;
405 }
406
Jian Lib6dc08f2021-03-24 15:24:18 +0900407 setEgressRules(port, false);
Jian Li858ccd72021-02-04 17:25:01 +0900408 }
409 }
410}