blob: 09cc28829117e5258588a38a4e9827810f9de75c [file] [log] [blame]
Jian Li8f944d42021-03-23 00:43:29 +09001/*
2 * Copyright 2020-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
18import com.google.common.collect.Sets;
19import org.onlab.packet.Ethernet;
20import org.onlab.packet.IPv4;
21import org.onlab.packet.Ip4Address;
22import org.onlab.packet.Ip4Prefix;
23import org.onlab.packet.IpPrefix;
Jian Lif89d9602021-04-27 19:05:49 +090024import org.onlab.packet.MacAddress;
Jian Li8f944d42021-03-23 00:43:29 +090025import org.onlab.packet.TpPort;
Jian Li8f944d42021-03-23 00:43:29 +090026import org.onlab.util.Tools;
27import org.onosproject.cfg.ComponentConfigService;
28import org.onosproject.cfg.ConfigProperty;
29import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
35import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
Jian Li8f944d42021-03-23 00:43:29 +090036import org.onosproject.kubevirtnetworking.api.KubevirtNetworkEvent;
37import org.onosproject.kubevirtnetworking.api.KubevirtNetworkListener;
38import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
39import org.onosproject.kubevirtnetworking.api.KubevirtPort;
40import org.onosproject.kubevirtnetworking.api.KubevirtPortEvent;
41import org.onosproject.kubevirtnetworking.api.KubevirtPortListener;
42import org.onosproject.kubevirtnetworking.api.KubevirtPortService;
43import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroup;
44import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupEvent;
45import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupListener;
46import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupRule;
47import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupService;
48import org.onosproject.kubevirtnetworking.util.RulePopulatorUtil;
49import org.onosproject.kubevirtnode.api.KubevirtNode;
50import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
51import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
52import org.onosproject.kubevirtnode.api.KubevirtNodeService;
53import org.onosproject.mastership.MastershipService;
54import org.onosproject.net.DeviceId;
Jian Lif89d9602021-04-27 19:05:49 +090055import org.onosproject.net.PortNumber;
Jian Li8f944d42021-03-23 00:43:29 +090056import org.onosproject.net.device.DeviceService;
57import org.onosproject.net.driver.DriverService;
58import org.onosproject.net.flow.DefaultTrafficSelector;
59import org.onosproject.net.flow.DefaultTrafficTreatment;
60import org.onosproject.net.flow.TrafficSelector;
61import org.onosproject.net.flow.TrafficTreatment;
62import org.onosproject.net.flow.criteria.ExtensionSelector;
63import org.onosproject.net.flow.instructions.ExtensionTreatment;
64import org.onosproject.store.service.StorageService;
65import org.osgi.service.component.ComponentContext;
66import org.osgi.service.component.annotations.Activate;
67import org.osgi.service.component.annotations.Component;
68import org.osgi.service.component.annotations.Deactivate;
69import org.osgi.service.component.annotations.Modified;
70import org.osgi.service.component.annotations.Reference;
71import org.osgi.service.component.annotations.ReferenceCardinality;
72import org.slf4j.Logger;
73
74import java.util.Dictionary;
75import java.util.Map;
76import java.util.Objects;
77import java.util.Set;
78import java.util.concurrent.ExecutorService;
79import java.util.stream.Collectors;
80
81import static java.lang.Thread.sleep;
82import static java.util.concurrent.Executors.newSingleThreadExecutor;
83import static org.onlab.util.Tools.groupedThreads;
Jian Lif89d9602021-04-27 19:05:49 +090084import static org.onosproject.kubevirtnetworking.api.Constants.ACL_CT_TABLE;
85import static org.onosproject.kubevirtnetworking.api.Constants.ACL_EGRESS_TABLE;
86import static org.onosproject.kubevirtnetworking.api.Constants.ACL_INGRESS_TABLE;
87import static org.onosproject.kubevirtnetworking.api.Constants.ACL_RECIRC_TABLE;
Jian Li8f944d42021-03-23 00:43:29 +090088import static org.onosproject.kubevirtnetworking.api.Constants.ERROR_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +090089import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Li8f944d42021-03-23 00:43:29 +090090import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
91import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_INGRESS_RULE;
92import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_RULE;
93import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_DROP_RULE;
94import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
95import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_RULE;
96import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_CT_TABLE;
97import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_EGRESS_TABLE;
98import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_INGRESS_TABLE;
99import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_RECIRC_TABLE;
100import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +0900101import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.FLAT;
Jian Li8f944d42021-03-23 00:43:29 +0900102import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
Jian Li8f944d42021-03-23 00:43:29 +0900103import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP;
104import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP_DEFAULT;
105import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
106import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildPortRangeMatches;
107import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.computeCtMaskFlag;
108import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.computeCtStateFlag;
109import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
110import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
111import static org.slf4j.LoggerFactory.getLogger;
112
113/**
114 * Populates flow rules to handle EdgeStack SecurityGroups.
115 */
116@Component(
117 immediate = true,
118 property = {
119 USE_SECURITY_GROUP + ":Boolean=" + USE_SECURITY_GROUP_DEFAULT
120 }
121)
122public class KubevirtSecurityGroupHandler {
123
124 private final Logger log = getLogger(getClass());
125
126 private static final int VM_IP_PREFIX = 32;
127
128 private static final String STR_NULL = "null";
129 private static final String PROTO_ICMP = "ICMP";
130 private static final String PROTO_ICMP_NUM = "1";
131 private static final String PROTO_TCP = "TCP";
132 private static final String PROTO_TCP_NUM = "6";
133 private static final String PROTO_UDP = "UDP";
134 private static final String PROTO_UDP_NUM = "17";
135 private static final String PROTO_SCTP = "SCTP";
136 private static final String PROTO_SCTP_NUM = "132";
137 private static final byte PROTOCOL_SCTP = (byte) 0x84;
138 private static final String PROTO_ANY = "ANY";
139 private static final String PROTO_ANY_NUM = "0";
140 private static final String ETHTYPE_IPV4 = "IPV4";
141 private static final String EGRESS = "EGRESS";
142 private static final String INGRESS = "INGRESS";
143 private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
144
145 private static final int ICMP_CODE_MIN = 0;
146 private static final int ICMP_CODE_MAX = 255;
147 private static final int ICMP_TYPE_MIN = 0;
148 private static final int ICMP_TYPE_MAX = 255;
149
150 private static final int CT_COMMIT = 0;
151 private static final int CT_NO_COMMIT = 1;
152 private static final short CT_NO_RECIRC = -1;
153
154 private static final int ACTION_NONE = 0;
155 private static final int ACTION_DROP = -1;
156
157 private static final long SLEEP_MS = 5000;
158
159 /** Apply EdgeStack security group rule for VM traffic. */
160 private boolean useSecurityGroup = USE_SECURITY_GROUP_DEFAULT;
161
162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
163 protected CoreService coreService;
164
165 @Reference(cardinality = ReferenceCardinality.MANDATORY)
166 protected MastershipService mastershipService;
167
168 @Reference(cardinality = ReferenceCardinality.MANDATORY)
169 protected DriverService driverService;
170
171 @Reference(cardinality = ReferenceCardinality.MANDATORY)
172 protected DeviceService deviceService;
173
174 @Reference(cardinality = ReferenceCardinality.MANDATORY)
175 protected LeadershipService leadershipService;
176
177 @Reference(cardinality = ReferenceCardinality.MANDATORY)
178 protected ClusterService clusterService;
179
180 @Reference(cardinality = ReferenceCardinality.MANDATORY)
181 protected StorageService storageService;
182
183 @Reference(cardinality = ReferenceCardinality.MANDATORY)
184 protected ComponentConfigService configService;
185
186 @Reference(cardinality = ReferenceCardinality.MANDATORY)
187 protected KubevirtNodeService nodeService;
188
189 @Reference(cardinality = ReferenceCardinality.MANDATORY)
190 protected KubevirtNetworkService networkService;
191
192 @Reference(cardinality = ReferenceCardinality.MANDATORY)
193 protected KubevirtPortService portService;
194
195 @Reference(cardinality = ReferenceCardinality.MANDATORY)
196 protected KubevirtFlowRuleService flowRuleService;
197
198 @Reference(cardinality = ReferenceCardinality.MANDATORY)
199 protected KubevirtSecurityGroupService securityGroupService;
200
201 private final KubevirtPortListener portListener =
202 new InternalKubevirtPortListener();
203 private final KubevirtSecurityGroupListener securityGroupListener =
204 new InternalSecurityGroupListener();
205 private final KubevirtNodeListener nodeListener =
206 new InternalNodeListener();
207 private final KubevirtNetworkListener networkListener =
208 new InternalNetworkListener();
209
210 private final ExecutorService eventExecutor = newSingleThreadExecutor(
211 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
212
213 private ApplicationId appId;
214 private NodeId localNodeId;
215
216 @Activate
217 protected void activate() {
218 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
219 localNodeId = clusterService.getLocalNode().id();
220 securityGroupService.addListener(securityGroupListener);
221 portService.addListener(portListener);
222 networkService.addListener(networkListener);
223 configService.registerProperties(getClass());
224 nodeService.addListener(nodeListener);
225
226 log.info("Started");
227 }
228
229 @Deactivate
230 protected void deactivate() {
231 securityGroupService.removeListener(securityGroupListener);
232 portService.removeListener(portListener);
233 configService.unregisterProperties(getClass(), false);
234 nodeService.removeListener(nodeListener);
235 networkService.removeListener(networkListener);
236 eventExecutor.shutdown();
237
238 log.info("Stopped");
239 }
240
241 @Modified
242 protected void modified(ComponentContext context) {
243 Dictionary<?, ?> properties = context.getProperties();
244 Boolean flag;
245
246 flag = Tools.isPropertyEnabled(properties, USE_SECURITY_GROUP);
247 if (flag == null) {
248 log.info("useSecurityGroup is not configured, " +
249 "using current value of {}", useSecurityGroup);
250 } else {
251 useSecurityGroup = flag;
252 log.info("Configured. useSecurityGroup is {}",
253 useSecurityGroup ? "enabled" : "disabled");
254 }
255
256 securityGroupService.setSecurityGroupEnabled(useSecurityGroup);
257 resetSecurityGroupRules();
258 }
259
260 private boolean getUseSecurityGroupFlag() {
261 Set<ConfigProperty> properties =
262 configService.getProperties(getClass().getName());
263 return getPropertyValueAsBoolean(properties, USE_SECURITY_GROUP);
264 }
265
Jian Lif89d9602021-04-27 19:05:49 +0900266 private void initializeProviderConnTrackTable(DeviceId deviceId, boolean install) {
267 initializeConnTrackTable(deviceId, ACL_CT_TABLE, FORWARDING_TABLE, install);
268 }
269
270 private void initializeTenantConnTrackTable(DeviceId deviceId, boolean install) {
271 initializeConnTrackTable(deviceId, TENANT_ACL_CT_TABLE, TENANT_FORWARDING_TABLE, install);
272 }
273
274 private void initializeConnTrackTable(DeviceId deviceId, int ctTable,
275 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900276
277 // table={ACL_INGRESS_TABLE(44)},ip,ct_state=-trk, actions=ct(table:{ACL_CT_TABLE(45)})
278 long ctState = computeCtStateFlag(false, false, false);
279 long ctMask = computeCtMaskFlag(true, false, false);
Jian Lif89d9602021-04-27 19:05:49 +0900280 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) ctTable,
Jian Li8f944d42021-03-23 00:43:29 +0900281 ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
282
283 //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:{NORMAL_TABLE(80)}
284 ctState = computeCtStateFlag(true, false, true);
285 ctMask = computeCtMaskFlag(true, false, true);
286 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
Jian Lif89d9602021-04-27 19:05:49 +0900287 forwardTable, PRIORITY_CT_RULE, install);
Jian Li8f944d42021-03-23 00:43:29 +0900288
289 //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
290 ctState = computeCtStateFlag(true, true, false);
291 ctMask = computeCtMaskFlag(true, true, false);
292 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
293 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
294 }
295
Jian Lif89d9602021-04-27 19:05:49 +0900296 private void initializeProviderAclTable(KubevirtNode node,
297 DeviceId deviceId, boolean install) {
298 // FIXME: we need to use group table to multi-cast traffic to all
299 // physPatchPorts later, we only choose one of the physPatchPorts to
300 // stream the outbound traffic for now
301 node.physPatchPorts().stream().findFirst().ifPresent(p ->
302 initializeAclTable(deviceId, ACL_RECIRC_TABLE, p, install));
303 }
304
305 private void initializeTenantAclTable(KubevirtNetwork network,
306 DeviceId deviceId, boolean install) {
307 PortNumber patchPort = network.tenantToTunnelPort(deviceId);
308 initializeAclTable(deviceId, TENANT_ACL_RECIRC_TABLE, patchPort, install);
309 }
310
311 private void initializeAclTable(DeviceId deviceId, int recircTable,
312 PortNumber outport, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900313
314 ExtensionTreatment ctTreatment =
315 niciraConnTrackTreatmentBuilder(driverService, deviceId)
316 .commit(true)
317 .build();
318
319 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
320 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
321
322 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
323 tBuilder.extension(ctTreatment, deviceId)
Jian Lif89d9602021-04-27 19:05:49 +0900324 .setOutput(outport);
Jian Li8f944d42021-03-23 00:43:29 +0900325
326 flowRuleService.setRule(appId,
327 deviceId,
328 sBuilder.build(),
329 tBuilder.build(),
330 PRIORITY_ACL_INGRESS_RULE,
Jian Lif89d9602021-04-27 19:05:49 +0900331 recircTable,
Jian Li8f944d42021-03-23 00:43:29 +0900332 install);
333 }
334
Jian Lif89d9602021-04-27 19:05:49 +0900335 private void initializeProviderEgressTable(DeviceId deviceId, boolean install) {
336 initializeEgressTable(deviceId, ACL_EGRESS_TABLE, FORWARDING_TABLE, install);
337 }
338
339 private void initializeTenantEgressTable(DeviceId deviceId, boolean install) {
340 initializeEgressTable(deviceId, TENANT_ACL_EGRESS_TABLE, TENANT_FORWARDING_TABLE, install);
341 }
342
343 private void initializeEgressTable(DeviceId deviceId, int egressTable,
344 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900345 if (install) {
346 flowRuleService.setUpTableMissEntry(deviceId, TENANT_ACL_EGRESS_TABLE);
347 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900348 flowRuleService.connectTables(deviceId, egressTable, forwardTable);
Jian Li8f944d42021-03-23 00:43:29 +0900349 }
350 }
351
Jian Lif89d9602021-04-27 19:05:49 +0900352 private void initializeProviderIngressTable(DeviceId deviceId, boolean install) {
353 initializeIngressTable(deviceId, ACL_INGRESS_TABLE, FORWARDING_TABLE, install);
354 }
355
356 private void initializeTenantIngressTable(DeviceId deviceId, boolean install) {
357 initializeIngressTable(deviceId, TENANT_ACL_INGRESS_TABLE, TENANT_FORWARDING_TABLE, install);
358 }
359
360 private void initializeIngressTable(DeviceId deviceId, int ingressTable,
361 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900362 if (install) {
Jian Lif89d9602021-04-27 19:05:49 +0900363 flowRuleService.setUpTableMissEntry(deviceId, ingressTable);
Jian Li8f944d42021-03-23 00:43:29 +0900364 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900365 flowRuleService.connectTables(deviceId, ingressTable, forwardTable);
Jian Li8f944d42021-03-23 00:43:29 +0900366 }
367 }
368
Jian Lif89d9602021-04-27 19:05:49 +0900369 private void initializeProviderPipeline(KubevirtNode node, boolean install) {
370 initializeProviderIngressTable(node.intgBridge(), install);
371 initializeProviderEgressTable(node.intgBridge(), install);
372 initializeProviderConnTrackTable(node.intgBridge(), install);
373 initializeProviderAclTable(node, node.intgBridge(), install);
374 }
375
376 private void initializeTenantPipeline(KubevirtNetwork network,
377 KubevirtNode node, boolean install) {
378 DeviceId deviceId = network.tenantDeviceId(node.hostname());
379 if (deviceId == null) {
380 return;
381 }
Jian Li567b25c2021-05-27 15:17:59 +0900382
383 // we check whether the given device is available from the store
384 // if not we will wait until the device is eventually created
385 // FIXME: it would be better to listen to device event to perform
386 // pipeline initialization rather on network events.
387 while (true) {
388 if (deviceService.getDevice(deviceId) != null) {
389 break;
390 } else {
391 try {
392 sleep(SLEEP_MS);
393 } catch (InterruptedException e) {
394 log.error("Failed to install security group default rules.");
395 }
396 }
397 }
398
Jian Lif89d9602021-04-27 19:05:49 +0900399 initializeTenantIngressTable(deviceId, install);
400 initializeTenantEgressTable(deviceId, install);
401 initializeTenantConnTrackTable(deviceId, install);
402 initializeTenantAclTable(network, deviceId, install);
403 }
404
Jian Li8f944d42021-03-23 00:43:29 +0900405 private void updateSecurityGroupRule(KubevirtPort port,
406 KubevirtSecurityGroupRule sgRule, boolean install) {
407
408 if (port == null || sgRule == null) {
409 return;
410 }
411
412 if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().isEmpty()) {
413 getRemotePorts(port, sgRule.remoteGroupId())
414 .forEach(rPort -> {
415 populateSecurityGroupRule(sgRule, port,
416 rPort.ipAddress().toIpPrefix(), install);
417 populateSecurityGroupRule(sgRule, rPort,
418 port.ipAddress().toIpPrefix(), install);
419
420 KubevirtSecurityGroupRule rSgRule = sgRule.updateDirection(
421 sgRule.direction().equalsIgnoreCase(EGRESS) ? INGRESS : EGRESS);
422 populateSecurityGroupRule(rSgRule, port,
423 rPort.ipAddress().toIpPrefix(), install);
424 populateSecurityGroupRule(rSgRule, rPort,
425 port.ipAddress().toIpPrefix(), install);
426 });
427 } else {
428 populateSecurityGroupRule(sgRule, port,
429 sgRule.remoteIpPrefix() == null ? IP_PREFIX_ANY :
430 sgRule.remoteIpPrefix(), install);
431 }
432 }
433
434 private boolean checkProtocol(String protocol) {
435 if (protocol == null) {
436 log.debug("No protocol was specified, use default IP(v4/v6) protocol.");
437 return true;
438 } else {
439 String protocolUpper = protocol.toUpperCase();
440 if (protocolUpper.equals(PROTO_TCP) ||
441 protocolUpper.equals(PROTO_UDP) ||
442 protocolUpper.equals(PROTO_ICMP) ||
443 protocolUpper.equals(PROTO_SCTP) ||
444 protocolUpper.equals(PROTO_ANY) ||
445 protocol.equals(PROTO_TCP_NUM) ||
446 protocol.equals(PROTO_UDP_NUM) ||
447 protocol.equals(PROTO_ICMP_NUM) ||
448 protocol.equals(PROTO_SCTP_NUM) ||
449 protocol.equals(PROTO_ANY_NUM)) {
450 return true;
451 } else {
452 log.error("Unsupported protocol {}, we only support " +
453 "TCP/UDP/ICMP/SCTP protocols.", protocol);
454 return false;
455 }
456 }
457 }
458
459 private void populateSecurityGroupRule(KubevirtSecurityGroupRule sgRule,
460 KubevirtPort port,
461 IpPrefix remoteIp,
462 boolean install) {
463 if (!checkProtocol(sgRule.protocol())) {
464 return;
465 }
466
467 DeviceId deviceId = port.isTenant() ? port.tenantDeviceId() : port.deviceId();
468
Jian Lif89d9602021-04-27 19:05:49 +0900469 Set<TrafficSelector> ctSelectors = buildSelectors(
470 sgRule,
Jian Li8f944d42021-03-23 00:43:29 +0900471 Ip4Address.valueOf(port.ipAddress().toInetAddress()),
Jian Lif89d9602021-04-27 19:05:49 +0900472 port.macAddress(),
Jian Li8f944d42021-03-23 00:43:29 +0900473 remoteIp, port.networkId());
Jian Lif89d9602021-04-27 19:05:49 +0900474 if (ctSelectors == null || ctSelectors.isEmpty()) {
Jian Li8f944d42021-03-23 00:43:29 +0900475 return;
476 }
477
478 // if the device is not available we do not perform any action
479 if (deviceId == null || !deviceService.isAvailable(deviceId)) {
480 return;
481 }
482
483 // XXX All egress traffic needs to go through connection tracking module,
484 // which might hurt its performance.
485 ExtensionTreatment ctTreatment =
486 niciraConnTrackTreatmentBuilder(driverService, deviceId)
487 .commit(true)
488 .build();
489
490 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
491
Jian Lif89d9602021-04-27 19:05:49 +0900492 KubevirtNetwork net = networkService.network(port.networkId());
493
Jian Li8f944d42021-03-23 00:43:29 +0900494 int aclTable;
495 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
Jian Lif89d9602021-04-27 19:05:49 +0900496
497 if (net.type() == FLAT || net.type() == VLAN) {
498 aclTable = ACL_EGRESS_TABLE;
499 } else {
500 aclTable = TENANT_ACL_EGRESS_TABLE;
501 }
502
Jian Li8f944d42021-03-23 00:43:29 +0900503 tBuilder.transition(TENANT_ACL_RECIRC_TABLE);
504 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900505
506 if (net.type() == FLAT || net.type() == VLAN) {
507 aclTable = ACL_INGRESS_TABLE;
508 } else {
509 aclTable = TENANT_ACL_INGRESS_TABLE;
510 }
511
Jian Li8f944d42021-03-23 00:43:29 +0900512 tBuilder.extension(ctTreatment, deviceId)
513 .transition(TENANT_FORWARDING_TABLE);
514 }
515
516 int finalAclTable = aclTable;
Jian Lif89d9602021-04-27 19:05:49 +0900517 ctSelectors.forEach(selector -> {
Jian Li8f944d42021-03-23 00:43:29 +0900518 flowRuleService.setRule(appId,
519 deviceId,
520 selector, tBuilder.build(),
521 PRIORITY_ACL_RULE,
522 finalAclTable,
523 install);
524 });
Jian Lif89d9602021-04-27 19:05:49 +0900525
526 TrafficSelector tSelector = DefaultTrafficSelector.builder()
527 .matchEthType(Ethernet.TYPE_IPV4)
528 .matchEthDst(port.macAddress())
529 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
530 .build();
531 TrafficTreatment tTreatment = DefaultTrafficTreatment.builder()
532 .transition(TENANT_ACL_INGRESS_TABLE)
533 .build();
534
535 flowRuleService.setRule(appId,
536 deviceId,
537 tSelector,
538 tTreatment,
539 PRIORITY_ACL_RULE,
540 TENANT_ACL_RECIRC_TABLE,
541 install);
Jian Li8f944d42021-03-23 00:43:29 +0900542 }
543
544 /**
545 * Sets connection tracking rule using OVS extension commands.
546 * It is not so graceful, but I don't want to make it more general because
547 * it is going to be used only here.
548 * The following is the usage of the function.
549 *
550 * @param deviceId Device ID
551 * @param ctState ctState: please use RulePopulatorUtil.computeCtStateFlag()
552 * to build the value
553 * @param ctMask crMask: please use RulePopulatorUtil.computeCtMaskFlag()
554 * to build the value
555 * @param commit CT_COMMIT for commit action, CT_NO_COMMIT otherwise
556 * @param recircTable table number for recirculation after CT actions.
557 * CT_NO_RECIRC with no recirculation
558 * @param action Additional actions. ACTION_DROP, ACTION_NONE,
559 * GOTO_XXX_TABLE are supported.
560 * @param priority priority value for the rule
561 * @param install true for insertion, false for removal
562 */
563 private void setConnTrackRule(DeviceId deviceId, long ctState, long ctMask,
564 int commit, short recircTable,
565 int action, int priority, boolean install) {
566
567 ExtensionSelector esCtSate = RulePopulatorUtil
568 .buildCtExtensionSelector(driverService, deviceId, ctState, ctMask);
569 TrafficSelector selector = DefaultTrafficSelector.builder()
570 .extension(esCtSate, deviceId)
571 .matchEthType(Ethernet.TYPE_IPV4)
572 .build();
573
574 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
575
576 if (commit == CT_COMMIT || recircTable > 0) {
577 RulePopulatorUtil.NiciraConnTrackTreatmentBuilder natTreatmentBuilder =
578 niciraConnTrackTreatmentBuilder(driverService, deviceId);
579 natTreatmentBuilder.natAction(false);
580 natTreatmentBuilder.commit(commit == CT_COMMIT);
581 if (recircTable > 0) {
582 natTreatmentBuilder.table(recircTable);
583 }
584 tb.extension(natTreatmentBuilder.build(), deviceId);
585 } else if (action == ACTION_DROP) {
586 tb.drop();
587 }
588
589 if (action != ACTION_NONE && action != ACTION_DROP) {
590 tb.transition(action);
591 }
592
593 int tableType = ERROR_TABLE;
594 if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
595 tableType = TENANT_ACL_CT_TABLE;
596 } else if (priority == PRIORITY_CT_HOOK_RULE) {
597 tableType = TENANT_ACL_INGRESS_TABLE;
598 } else {
599 log.error("Cannot an appropriate table for the conn track rule.");
600 }
601
602 flowRuleService.setRule(
603 appId,
604 deviceId,
605 selector,
606 tb.build(),
607 priority,
608 tableType,
609 install);
610 }
611
612 /**
613 * Returns a set of host IP addresses engaged with supplied security group ID.
614 * It only searches a VM in the same tenant boundary.
615 *
616 * @param srcPort edgestack port
617 * @param sgId security group id
618 * @return set of ip addresses
619 */
620 private Set<KubevirtPort> getRemotePorts(KubevirtPort srcPort, String sgId) {
621 return portService.ports().stream()
622 .filter(port -> !port.macAddress().equals(srcPort.macAddress()))
623 .filter(port -> port.securityGroups().contains(sgId))
624 .filter(port -> port.ipAddress() != null)
625 .collect(Collectors.toSet());
626 }
627
628 private Set<TrafficSelector> buildSelectors(KubevirtSecurityGroupRule sgRule,
629 Ip4Address vmIp,
Jian Lif89d9602021-04-27 19:05:49 +0900630 MacAddress vmMac,
Jian Li8f944d42021-03-23 00:43:29 +0900631 IpPrefix remoteIp,
632 String netId) {
633 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
634 // do nothing if the remote IP is my IP
635 return null;
636 }
637
638 Set<TrafficSelector> selectorSet = Sets.newHashSet();
639
640 if (sgRule.portRangeMax() != null && sgRule.portRangeMin() != null &&
641 sgRule.portRangeMin() < sgRule.portRangeMax()) {
642 Map<TpPort, TpPort> portRangeMatchMap =
643 buildPortRangeMatches(sgRule.portRangeMin(),
644 sgRule.portRangeMax());
645 portRangeMatchMap.forEach((key, value) -> {
646
647 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Lif89d9602021-04-27 19:05:49 +0900648 buildMatches(sBuilder, sgRule, vmIp, vmMac, remoteIp);
Jian Li8f944d42021-03-23 00:43:29 +0900649
650 if (sgRule.protocol().equalsIgnoreCase(PROTO_TCP) ||
651 sgRule.protocol().equals(PROTO_TCP_NUM)) {
652 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
653 if (value.toInt() == TpPort.MAX_PORT) {
654 sBuilder.matchTcpSrc(key);
655 } else {
656 sBuilder.matchTcpSrcMasked(key, value);
657 }
658 } else {
659 if (value.toInt() == TpPort.MAX_PORT) {
660 sBuilder.matchTcpDst(key);
661 } else {
662 sBuilder.matchTcpDstMasked(key, value);
663 }
664 }
665 } else if (sgRule.protocol().equalsIgnoreCase(PROTO_UDP) ||
666 sgRule.protocol().equals(PROTO_UDP_NUM)) {
667 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
668 if (value.toInt() == TpPort.MAX_PORT) {
669 sBuilder.matchUdpSrc(key);
670 } else {
671 sBuilder.matchUdpSrcMasked(key, value);
672 }
673 } else {
674 if (value.toInt() == TpPort.MAX_PORT) {
675 sBuilder.matchUdpDst(key);
676 } else {
677 sBuilder.matchUdpDstMasked(key, value);
678 }
679 }
680 } else if (sgRule.protocol().equalsIgnoreCase(PROTO_SCTP) ||
681 sgRule.protocol().equals(PROTO_SCTP_NUM)) {
682 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
683 if (value.toInt() == TpPort.MAX_PORT) {
684 sBuilder.matchSctpSrc(key);
685 } else {
686 sBuilder.matchSctpSrcMasked(key, value);
687 }
688 } else {
689 if (value.toInt() == TpPort.MAX_PORT) {
690 sBuilder.matchSctpDst(key);
691 } else {
692 sBuilder.matchSctpDstMasked(key, value);
693 }
694 }
695 }
696
697 selectorSet.add(sBuilder.build());
698 });
699 } else {
700
701 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Lif89d9602021-04-27 19:05:49 +0900702 buildMatches(sBuilder, sgRule, vmIp, vmMac, remoteIp);
Jian Li8f944d42021-03-23 00:43:29 +0900703
704 selectorSet.add(sBuilder.build());
705 }
706
707 return selectorSet;
708 }
709
710 private void buildMatches(TrafficSelector.Builder sBuilder,
711 KubevirtSecurityGroupRule sgRule, Ip4Address vmIp,
Jian Lif89d9602021-04-27 19:05:49 +0900712 MacAddress vmMac, IpPrefix remoteIp) {
Jian Li8f944d42021-03-23 00:43:29 +0900713 buildMatchEthType(sBuilder, sgRule.etherType());
Jian Lif89d9602021-04-27 19:05:49 +0900714 buildMatchDirection(sBuilder, sgRule.direction(), vmIp, vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900715 buildMatchProto(sBuilder, sgRule.protocol());
716 buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(),
717 sgRule.portRangeMin() == null ? 0 : sgRule.portRangeMin(),
718 sgRule.portRangeMax() == null ? 0 : sgRule.portRangeMax());
719 buildMatchIcmp(sBuilder, sgRule.protocol(),
720 sgRule.portRangeMin(), sgRule.portRangeMax());
721 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
722 }
723
Jian Li8f944d42021-03-23 00:43:29 +0900724 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
725 String direction,
Jian Lif89d9602021-04-27 19:05:49 +0900726 Ip4Address vmIp,
727 MacAddress vmMac) {
Jian Li8f944d42021-03-23 00:43:29 +0900728 if (direction.equalsIgnoreCase(EGRESS)) {
729 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
Jian Lif89d9602021-04-27 19:05:49 +0900730 sBuilder.matchEthSrc(vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900731 } else {
732 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
Jian Lif89d9602021-04-27 19:05:49 +0900733 sBuilder.matchEthDst(vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900734 }
735 }
736
737 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
738 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
739 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
740 if (etherType != null && !Objects.equals(etherType, STR_NULL) &&
741 !etherType.equalsIgnoreCase(ETHTYPE_IPV4)) {
742 log.debug("EthType {} is not supported yet in Security Group", etherType);
743 }
744 }
745
746 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder,
747 IpPrefix remoteIpPrefix, String direction) {
748 if (remoteIpPrefix != null &&
749 !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
750 if (direction.equalsIgnoreCase(EGRESS)) {
751 sBuilder.matchIPDst(remoteIpPrefix);
752 } else {
753 sBuilder.matchIPSrc(remoteIpPrefix);
754 }
755 }
756 }
757
758 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
759 if (protocol != null) {
760 switch (protocol.toUpperCase()) {
761 case PROTO_ICMP:
762 case PROTO_ICMP_NUM:
763 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
764 break;
765 case PROTO_TCP:
766 case PROTO_TCP_NUM:
767 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
768 break;
769 case PROTO_UDP:
770 case PROTO_UDP_NUM:
771 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
772 break;
773 case PROTO_SCTP:
774 case PROTO_SCTP_NUM:
775 sBuilder.matchIPProtocol(PROTOCOL_SCTP);
776 break;
777 default:
778 break;
779 }
780 }
781 }
782
783 private void buildMatchPort(TrafficSelector.Builder sBuilder,
784 String protocol, String direction,
785 int portMin, int portMax) {
786 if (portMax > 0 && portMin == portMax) {
787 if (protocol.equalsIgnoreCase(PROTO_TCP) ||
788 protocol.equals(PROTO_TCP_NUM)) {
789 if (direction.equalsIgnoreCase(EGRESS)) {
790 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
791 } else {
792 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
793 }
794 } else if (protocol.equalsIgnoreCase(PROTO_UDP) ||
795 protocol.equals(PROTO_UDP_NUM)) {
796 if (direction.equalsIgnoreCase(EGRESS)) {
797 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
798 } else {
799 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
800 }
801 } else if (protocol.equalsIgnoreCase(PROTO_SCTP) ||
802 protocol.equals(PROTO_SCTP_NUM)) {
803 if (direction.equalsIgnoreCase(EGRESS)) {
804 sBuilder.matchSctpSrc(TpPort.tpPort(portMax));
805 } else {
806 sBuilder.matchSctpDst(TpPort.tpPort(portMax));
807 }
808 }
809 }
810 }
811
812 private void buildMatchIcmp(TrafficSelector.Builder sBuilder,
813 String protocol, Integer icmpCode, Integer icmpType) {
814 if (protocol != null) {
815 if (protocol.equalsIgnoreCase(PROTO_ICMP) ||
816 protocol.equals(PROTO_ICMP_NUM)) {
817 if (icmpCode != null && icmpCode >= ICMP_CODE_MIN &&
818 icmpCode <= ICMP_CODE_MAX) {
819 sBuilder.matchIcmpCode(icmpCode.byteValue());
820 }
821 if (icmpType != null && icmpType >= ICMP_TYPE_MIN &&
822 icmpType <= ICMP_TYPE_MAX) {
823 sBuilder.matchIcmpType(icmpType.byteValue());
824 }
825 }
826 }
827 }
828
829 private void resetSecurityGroupRules() {
830
831 if (getUseSecurityGroupFlag()) {
832 nodeService.completeNodes(WORKER).forEach(node -> {
Jian Lif89d9602021-04-27 19:05:49 +0900833 initializeProviderPipeline(node, true);
Jian Li8f944d42021-03-23 00:43:29 +0900834
835 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +0900836 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +0900837 }
838 });
839
840 securityGroupService.securityGroups().forEach(securityGroup ->
841 securityGroup.rules().forEach(this::securityGroupRuleAdded));
842 } else {
843 nodeService.completeNodes(WORKER).forEach(node -> {
Jian Lif89d9602021-04-27 19:05:49 +0900844 initializeProviderPipeline(node, false);
Jian Li8f944d42021-03-23 00:43:29 +0900845
846 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +0900847 initializeTenantPipeline(network, node, false);
Jian Li8f944d42021-03-23 00:43:29 +0900848 }
849 });
850
851 securityGroupService.securityGroups().forEach(securityGroup ->
852 securityGroup.rules().forEach(this::securityGroupRuleRemoved));
853 }
854
855 log.info("Reset security group info " +
856 (getUseSecurityGroupFlag() ? "with" : "without") + " Security Group");
857 }
858
859 private void securityGroupRuleAdded(KubevirtSecurityGroupRule sgRule) {
860 portService.ports().stream()
861 .filter(port -> port.securityGroups().contains(sgRule.securityGroupId()))
862 .forEach(port -> {
863 updateSecurityGroupRule(port, sgRule, true);
864 log.info("Applied security group rule {} to port {}",
865 sgRule.id(), port.macAddress());
866 });
867 }
868
869 private void securityGroupRuleRemoved(KubevirtSecurityGroupRule sgRule) {
870 portService.ports().stream()
871 .filter(port -> port.securityGroups().contains(sgRule.securityGroupId()))
872 .forEach(port -> {
873 updateSecurityGroupRule(port, sgRule, false);
874 log.info("Removed security group rule {} from port {}",
875 sgRule.id(), port.macAddress());
876 });
877 }
878
879 private class InternalKubevirtPortListener implements KubevirtPortListener {
880
881 @Override
882 public boolean isRelevant(KubevirtPortEvent event) {
883 return getUseSecurityGroupFlag();
884 }
885
886 private boolean isRelevantHelper(KubevirtPortEvent event) {
887 DeviceId deviceId = event.subject().deviceId();
888
889 if (deviceId == null) {
890 return false;
891 }
892
893 return mastershipService.isLocalMaster(deviceId);
894 }
895
896 @Override
897 public void event(KubevirtPortEvent event) {
898 log.debug("security group event received {}", event);
899
900 switch (event.type()) {
901 case KUBEVIRT_PORT_SECURITY_GROUP_ADDED:
902 eventExecutor.execute(() -> processPortSgAdd(event));
903 break;
904 case KUBEVIRT_PORT_SECURITY_GROUP_REMOVED:
905 eventExecutor.execute(() -> processPortSgRemove(event));
906 break;
907 case KUBEVIRT_PORT_REMOVED:
908 eventExecutor.execute(() -> processPortRemove(event));
909 break;
910 case KUBEVIRT_PORT_DEVICE_ADDED:
911 eventExecutor.execute(() -> processPortDeviceAdded(event));
912 break;
913 default:
914 // do nothing for the other events
915 break;
916 }
917 }
918
919 private void processPortSgAdd(KubevirtPortEvent event) {
920 if (!isRelevantHelper(event)) {
921 return;
922 }
923
924 if (event.securityGroupId() == null ||
925 securityGroupService.securityGroup(event.securityGroupId()) == null) {
926 return;
927 }
928
929 KubevirtPort port = event.subject();
930 KubevirtSecurityGroup sg = securityGroupService.securityGroup(event.securityGroupId());
931
932 sg.rules().forEach(sgRule -> {
933 updateSecurityGroupRule(port, sgRule, true);
934 });
935 log.info("Added security group {} to port {}",
936 event.securityGroupId(), event.subject().macAddress());
937 }
938
939 private void processPortSgRemove(KubevirtPortEvent event) {
940 if (!isRelevantHelper(event)) {
941 return;
942 }
943
944 if (event.securityGroupId() == null ||
945 securityGroupService.securityGroup(event.securityGroupId()) == null) {
946 return;
947 }
948
949 KubevirtPort port = event.subject();
950 KubevirtSecurityGroup sg = securityGroupService.securityGroup(event.securityGroupId());
951
952 sg.rules().forEach(sgRule -> {
953 updateSecurityGroupRule(port, sgRule, false);
954 });
955 log.info("Removed security group {} from port {}",
956 event.securityGroupId(), event.subject().macAddress());
957 }
958
959 private void processPortRemove(KubevirtPortEvent event) {
960 if (!isRelevantHelper(event)) {
961 return;
962 }
963
964 KubevirtPort port = event.subject();
965 for (String sgStr : port.securityGroups()) {
966 KubevirtSecurityGroup sg = securityGroupService.securityGroup(sgStr);
967 sg.rules().forEach(sgRule -> {
968 updateSecurityGroupRule(port, sgRule, false);
969 });
970 log.info("Removed security group {} from port {}",
971 sgStr, event.subject().macAddress());
972 }
973 }
974
975 private void processPortDeviceAdded(KubevirtPortEvent event) {
976 if (!isRelevantHelper(event)) {
977 return;
978 }
979
980 for (String sgId : event.subject().securityGroups()) {
981 KubevirtSecurityGroup sg = securityGroupService.securityGroup(sgId);
982
983 sg.rules().forEach(sgRule -> {
984 updateSecurityGroupRule(event.subject(), sgRule, true);
985 });
986 log.info("Added security group {} to port {}",
Jian Lif89d9602021-04-27 19:05:49 +0900987 sg.id(), event.subject().macAddress());
Jian Li8f944d42021-03-23 00:43:29 +0900988 }
989 }
990 }
991
992 private class InternalNetworkListener implements KubevirtNetworkListener {
993
994 private boolean isRelevantHelper() {
995 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
996 }
997
998 @Override
999 public void event(KubevirtNetworkEvent event) {
1000 switch (event.type()) {
1001 case KUBEVIRT_NETWORK_CREATED:
1002 eventExecutor.execute(() -> processNetworkCreation(event.subject()));
1003 break;
1004 case KUBEVIRT_NETWORK_REMOVED:
1005 case KUBEVIRT_NETWORK_UPDATED:
1006 default:
1007 // do thing
1008 break;
1009 }
1010 }
1011
1012 private void processNetworkCreation(KubevirtNetwork network) {
1013 if (!isRelevantHelper()) {
1014 return;
1015 }
1016
1017 Set<KubevirtNode> nodes = nodeService.completeNodes(WORKER);
1018
1019 if (nodes.size() > 0) {
1020 // now we wait 5s for all tenant bridges are created,
1021 // FIXME: we need to fina a better way to wait all tenant bridges
1022 // are created before installing default security group rules
1023 try {
1024 sleep(SLEEP_MS);
1025 } catch (InterruptedException e) {
1026 log.error("Failed to install security group default rules.");
1027 }
1028
1029 for (KubevirtNode node : nodes) {
Jian Lif89d9602021-04-27 19:05:49 +09001030 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +09001031 }
1032 }
1033 }
1034 }
1035
1036 private class InternalSecurityGroupListener implements KubevirtSecurityGroupListener {
1037
1038 @Override
1039 public boolean isRelevant(KubevirtSecurityGroupEvent event) {
1040 return getUseSecurityGroupFlag();
1041 }
1042
1043 private boolean isRelevantHelper() {
1044 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1045 }
1046
1047 @Override
1048 public void event(KubevirtSecurityGroupEvent event) {
1049 switch (event.type()) {
1050 case KUBEVIRT_SECURITY_GROUP_RULE_CREATED:
1051 eventExecutor.execute(() -> processSgRuleCreate(event));
1052 break;
1053 case KUBEVIRT_SECURITY_GROUP_RULE_REMOVED:
1054 eventExecutor.execute(() -> processSgRuleRemove(event));
1055 break;
1056 default:
1057 // do nothing
1058 break;
1059 }
1060 }
1061
1062 private void processSgRuleCreate(KubevirtSecurityGroupEvent event) {
1063 if (!isRelevantHelper()) {
1064 return;
1065 }
1066
1067 KubevirtSecurityGroupRule sgRuleToAdd = event.rule();
1068 securityGroupRuleAdded(sgRuleToAdd);
1069 log.info("Applied new security group rule {} to ports", sgRuleToAdd.id());
1070 }
1071
1072 private void processSgRuleRemove(KubevirtSecurityGroupEvent event) {
1073 if (!isRelevantHelper()) {
1074 return;
1075 }
1076
1077 KubevirtSecurityGroupRule sgRuleToRemove = event.rule();
1078 securityGroupRuleRemoved(sgRuleToRemove);
1079 log.info("Removed security group rule {} from ports", sgRuleToRemove.id());
1080 }
1081 }
1082
1083 private class InternalNodeListener implements KubevirtNodeListener {
1084
1085 @Override
1086 public boolean isRelevant(KubevirtNodeEvent event) {
1087 return event.subject().type() == WORKER;
1088 }
1089
1090 private boolean isRelevantHelper() {
1091 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1092 }
1093
1094 @Override
1095 public void event(KubevirtNodeEvent event) {
1096 switch (event.type()) {
1097 case KUBEVIRT_NODE_COMPLETE:
1098 eventExecutor.execute(() -> processNodeComplete(event.subject()));
1099 break;
1100 default:
1101 break;
1102 }
1103 }
1104
1105 private void processNodeComplete(KubevirtNode node) {
1106 if (!isRelevantHelper()) {
1107 return;
1108 }
1109
Jian Lif89d9602021-04-27 19:05:49 +09001110 // FIXME: we wait all port get its deviceId updated
1111 try {
1112 sleep(SLEEP_MS);
1113 } catch (InterruptedException e) {
1114 log.error("Failed to install security group default rules.");
1115 }
1116
Jian Li8f944d42021-03-23 00:43:29 +09001117 resetSecurityGroupRulesByNode(node);
1118 }
1119
1120 private void resetSecurityGroupRulesByNode(KubevirtNode node) {
1121 if (getUseSecurityGroupFlag()) {
Jian Lif89d9602021-04-27 19:05:49 +09001122 initializeProviderPipeline(node, true);
Jian Li8f944d42021-03-23 00:43:29 +09001123
1124 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +09001125 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +09001126 }
1127
1128 securityGroupService.securityGroups().forEach(securityGroup ->
1129 securityGroup.rules().forEach(
1130 KubevirtSecurityGroupHandler.this::securityGroupRuleAdded));
1131 } else {
Jian Lif89d9602021-04-27 19:05:49 +09001132 initializeProviderPipeline(node, false);
Jian Li8f944d42021-03-23 00:43:29 +09001133
1134 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +09001135 initializeTenantPipeline(network, node, false);
Jian Li8f944d42021-03-23 00:43:29 +09001136 }
1137
1138 securityGroupService.securityGroups().forEach(securityGroup ->
1139 securityGroup.rules().forEach(
1140 KubevirtSecurityGroupHandler.this::securityGroupRuleRemoved));
1141 }
1142
1143 log.info("Reset security group info " +
1144 (getUseSecurityGroupFlag() ? "with" : "without") + " Security Group");
1145 }
1146 }
1147}