blob: 674c6ca3e4eb9a119553104b74a866b8412c5b6f [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
Jian Li8f944d42021-03-23 00:43:29 +090081import static java.util.concurrent.Executors.newSingleThreadExecutor;
82import static org.onlab.util.Tools.groupedThreads;
Jian Lif89d9602021-04-27 19:05:49 +090083import static org.onosproject.kubevirtnetworking.api.Constants.ACL_CT_TABLE;
84import static org.onosproject.kubevirtnetworking.api.Constants.ACL_EGRESS_TABLE;
85import static org.onosproject.kubevirtnetworking.api.Constants.ACL_INGRESS_TABLE;
86import static org.onosproject.kubevirtnetworking.api.Constants.ACL_RECIRC_TABLE;
Jian Li8f944d42021-03-23 00:43:29 +090087import static org.onosproject.kubevirtnetworking.api.Constants.ERROR_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +090088import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Li8f944d42021-03-23 00:43:29 +090089import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
90import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_INGRESS_RULE;
91import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_RULE;
92import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_DROP_RULE;
93import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
94import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_RULE;
95import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_CT_TABLE;
96import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_EGRESS_TABLE;
97import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_INGRESS_TABLE;
98import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_RECIRC_TABLE;
99import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +0900100import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.FLAT;
Jian Li8f944d42021-03-23 00:43:29 +0900101import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
Jian Li8f944d42021-03-23 00:43:29 +0900102import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP;
103import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP_DEFAULT;
104import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
Jian Li0c656f02021-06-07 13:32:39 +0900105import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.waitFor;
Jian Li8f944d42021-03-23 00:43:29 +0900106import 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
Jian Li8f944d42021-03-23 00:43:29 +0900157 /** Apply EdgeStack security group rule for VM traffic. */
158 private boolean useSecurityGroup = USE_SECURITY_GROUP_DEFAULT;
159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
161 protected CoreService coreService;
162
163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
164 protected MastershipService mastershipService;
165
166 @Reference(cardinality = ReferenceCardinality.MANDATORY)
167 protected DriverService driverService;
168
169 @Reference(cardinality = ReferenceCardinality.MANDATORY)
170 protected DeviceService deviceService;
171
172 @Reference(cardinality = ReferenceCardinality.MANDATORY)
173 protected LeadershipService leadershipService;
174
175 @Reference(cardinality = ReferenceCardinality.MANDATORY)
176 protected ClusterService clusterService;
177
178 @Reference(cardinality = ReferenceCardinality.MANDATORY)
179 protected StorageService storageService;
180
181 @Reference(cardinality = ReferenceCardinality.MANDATORY)
182 protected ComponentConfigService configService;
183
184 @Reference(cardinality = ReferenceCardinality.MANDATORY)
185 protected KubevirtNodeService nodeService;
186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY)
188 protected KubevirtNetworkService networkService;
189
190 @Reference(cardinality = ReferenceCardinality.MANDATORY)
191 protected KubevirtPortService portService;
192
193 @Reference(cardinality = ReferenceCardinality.MANDATORY)
194 protected KubevirtFlowRuleService flowRuleService;
195
196 @Reference(cardinality = ReferenceCardinality.MANDATORY)
197 protected KubevirtSecurityGroupService securityGroupService;
198
199 private final KubevirtPortListener portListener =
200 new InternalKubevirtPortListener();
201 private final KubevirtSecurityGroupListener securityGroupListener =
202 new InternalSecurityGroupListener();
203 private final KubevirtNodeListener nodeListener =
204 new InternalNodeListener();
205 private final KubevirtNetworkListener networkListener =
206 new InternalNetworkListener();
207
208 private final ExecutorService eventExecutor = newSingleThreadExecutor(
209 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
210
211 private ApplicationId appId;
212 private NodeId localNodeId;
213
214 @Activate
215 protected void activate() {
216 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
217 localNodeId = clusterService.getLocalNode().id();
218 securityGroupService.addListener(securityGroupListener);
219 portService.addListener(portListener);
220 networkService.addListener(networkListener);
221 configService.registerProperties(getClass());
222 nodeService.addListener(nodeListener);
223
224 log.info("Started");
225 }
226
227 @Deactivate
228 protected void deactivate() {
229 securityGroupService.removeListener(securityGroupListener);
230 portService.removeListener(portListener);
231 configService.unregisterProperties(getClass(), false);
232 nodeService.removeListener(nodeListener);
233 networkService.removeListener(networkListener);
234 eventExecutor.shutdown();
235
236 log.info("Stopped");
237 }
238
239 @Modified
240 protected void modified(ComponentContext context) {
241 Dictionary<?, ?> properties = context.getProperties();
242 Boolean flag;
243
244 flag = Tools.isPropertyEnabled(properties, USE_SECURITY_GROUP);
245 if (flag == null) {
246 log.info("useSecurityGroup is not configured, " +
247 "using current value of {}", useSecurityGroup);
248 } else {
249 useSecurityGroup = flag;
250 log.info("Configured. useSecurityGroup is {}",
251 useSecurityGroup ? "enabled" : "disabled");
252 }
253
254 securityGroupService.setSecurityGroupEnabled(useSecurityGroup);
255 resetSecurityGroupRules();
256 }
257
258 private boolean getUseSecurityGroupFlag() {
259 Set<ConfigProperty> properties =
260 configService.getProperties(getClass().getName());
261 return getPropertyValueAsBoolean(properties, USE_SECURITY_GROUP);
262 }
263
Jian Lif89d9602021-04-27 19:05:49 +0900264 private void initializeProviderConnTrackTable(DeviceId deviceId, boolean install) {
265 initializeConnTrackTable(deviceId, ACL_CT_TABLE, FORWARDING_TABLE, install);
266 }
267
268 private void initializeTenantConnTrackTable(DeviceId deviceId, boolean install) {
269 initializeConnTrackTable(deviceId, TENANT_ACL_CT_TABLE, TENANT_FORWARDING_TABLE, install);
270 }
271
272 private void initializeConnTrackTable(DeviceId deviceId, int ctTable,
273 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900274
275 // table={ACL_INGRESS_TABLE(44)},ip,ct_state=-trk, actions=ct(table:{ACL_CT_TABLE(45)})
276 long ctState = computeCtStateFlag(false, false, false);
277 long ctMask = computeCtMaskFlag(true, false, false);
Jian Lif89d9602021-04-27 19:05:49 +0900278 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) ctTable,
Jian Li8f944d42021-03-23 00:43:29 +0900279 ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
280
281 //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:{NORMAL_TABLE(80)}
282 ctState = computeCtStateFlag(true, false, true);
283 ctMask = computeCtMaskFlag(true, false, true);
284 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
Jian Lif89d9602021-04-27 19:05:49 +0900285 forwardTable, PRIORITY_CT_RULE, install);
Jian Li8f944d42021-03-23 00:43:29 +0900286
287 //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
288 ctState = computeCtStateFlag(true, true, false);
289 ctMask = computeCtMaskFlag(true, true, false);
290 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
291 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
292 }
293
Jian Li1bc914c2021-06-08 14:09:14 +0900294 private void initializeProviderAclTable(DeviceId deviceId, boolean install) {
295 initializeAclTable(deviceId, ACL_RECIRC_TABLE, PortNumber.NORMAL, install);
Jian Lif89d9602021-04-27 19:05:49 +0900296 }
297
298 private void initializeTenantAclTable(KubevirtNetwork network,
299 DeviceId deviceId, boolean install) {
Jian Li56f241b2021-06-30 20:59:43 +0900300 // FIXME: in bridge initialization phase, some patch ports may not be
301 // available until they are created, we wait for a while ensure all
302 // patch ports are created via network bootstrap
303 while (true) {
304 if (network.tenantToTunnelPort(deviceId) != null) {
305 break;
306 } else {
307 log.info("Wait for tenant patch ports creation for device {} " +
308 "and network {}", deviceId, network.networkId());
309 waitFor(5);
310 }
311 }
312
Jian Lif89d9602021-04-27 19:05:49 +0900313 PortNumber patchPort = network.tenantToTunnelPort(deviceId);
314 initializeAclTable(deviceId, TENANT_ACL_RECIRC_TABLE, patchPort, install);
315 }
316
317 private void initializeAclTable(DeviceId deviceId, int recircTable,
318 PortNumber outport, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900319
320 ExtensionTreatment ctTreatment =
321 niciraConnTrackTreatmentBuilder(driverService, deviceId)
322 .commit(true)
323 .build();
324
325 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
326 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
327
328 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
329 tBuilder.extension(ctTreatment, deviceId)
Jian Lif89d9602021-04-27 19:05:49 +0900330 .setOutput(outport);
Jian Li8f944d42021-03-23 00:43:29 +0900331
332 flowRuleService.setRule(appId,
333 deviceId,
334 sBuilder.build(),
335 tBuilder.build(),
336 PRIORITY_ACL_INGRESS_RULE,
Jian Lif89d9602021-04-27 19:05:49 +0900337 recircTable,
Jian Li8f944d42021-03-23 00:43:29 +0900338 install);
339 }
340
Jian Lif89d9602021-04-27 19:05:49 +0900341 private void initializeProviderEgressTable(DeviceId deviceId, boolean install) {
342 initializeEgressTable(deviceId, ACL_EGRESS_TABLE, FORWARDING_TABLE, install);
343 }
344
345 private void initializeTenantEgressTable(DeviceId deviceId, boolean install) {
346 initializeEgressTable(deviceId, TENANT_ACL_EGRESS_TABLE, TENANT_FORWARDING_TABLE, install);
347 }
348
349 private void initializeEgressTable(DeviceId deviceId, int egressTable,
350 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900351 if (install) {
352 flowRuleService.setUpTableMissEntry(deviceId, TENANT_ACL_EGRESS_TABLE);
353 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900354 flowRuleService.connectTables(deviceId, egressTable, forwardTable);
Jian Li8f944d42021-03-23 00:43:29 +0900355 }
356 }
357
Jian Lif89d9602021-04-27 19:05:49 +0900358 private void initializeProviderIngressTable(DeviceId deviceId, boolean install) {
359 initializeIngressTable(deviceId, ACL_INGRESS_TABLE, FORWARDING_TABLE, install);
360 }
361
362 private void initializeTenantIngressTable(DeviceId deviceId, boolean install) {
363 initializeIngressTable(deviceId, TENANT_ACL_INGRESS_TABLE, TENANT_FORWARDING_TABLE, install);
364 }
365
366 private void initializeIngressTable(DeviceId deviceId, int ingressTable,
367 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900368 if (install) {
Jian Lif89d9602021-04-27 19:05:49 +0900369 flowRuleService.setUpTableMissEntry(deviceId, ingressTable);
Jian Li8f944d42021-03-23 00:43:29 +0900370 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900371 flowRuleService.connectTables(deviceId, ingressTable, forwardTable);
Jian Li8f944d42021-03-23 00:43:29 +0900372 }
373 }
374
Jian Lif89d9602021-04-27 19:05:49 +0900375 private void initializeProviderPipeline(KubevirtNode node, boolean install) {
376 initializeProviderIngressTable(node.intgBridge(), install);
377 initializeProviderEgressTable(node.intgBridge(), install);
378 initializeProviderConnTrackTable(node.intgBridge(), install);
Jian Li1bc914c2021-06-08 14:09:14 +0900379 initializeProviderAclTable(node.intgBridge(), install);
Jian Lif89d9602021-04-27 19:05:49 +0900380 }
381
382 private void initializeTenantPipeline(KubevirtNetwork network,
383 KubevirtNode node, boolean install) {
384 DeviceId deviceId = network.tenantDeviceId(node.hostname());
385 if (deviceId == null) {
386 return;
387 }
Jian Li567b25c2021-05-27 15:17:59 +0900388
389 // we check whether the given device is available from the store
390 // if not we will wait until the device is eventually created
391 // FIXME: it would be better to listen to device event to perform
392 // pipeline initialization rather on network events.
393 while (true) {
394 if (deviceService.getDevice(deviceId) != null) {
395 break;
396 } else {
Jian Li0c656f02021-06-07 13:32:39 +0900397 waitFor(5);
Jian Li567b25c2021-05-27 15:17:59 +0900398 }
399 }
400
Jian Lif89d9602021-04-27 19:05:49 +0900401 initializeTenantIngressTable(deviceId, install);
402 initializeTenantEgressTable(deviceId, install);
403 initializeTenantConnTrackTable(deviceId, install);
404 initializeTenantAclTable(network, deviceId, install);
405 }
406
Jian Li8f944d42021-03-23 00:43:29 +0900407 private void updateSecurityGroupRule(KubevirtPort port,
408 KubevirtSecurityGroupRule sgRule, boolean install) {
409
410 if (port == null || sgRule == null) {
411 return;
412 }
413
414 if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().isEmpty()) {
415 getRemotePorts(port, sgRule.remoteGroupId())
416 .forEach(rPort -> {
417 populateSecurityGroupRule(sgRule, port,
418 rPort.ipAddress().toIpPrefix(), install);
419 populateSecurityGroupRule(sgRule, rPort,
420 port.ipAddress().toIpPrefix(), install);
421
422 KubevirtSecurityGroupRule rSgRule = sgRule.updateDirection(
423 sgRule.direction().equalsIgnoreCase(EGRESS) ? INGRESS : EGRESS);
424 populateSecurityGroupRule(rSgRule, port,
425 rPort.ipAddress().toIpPrefix(), install);
426 populateSecurityGroupRule(rSgRule, rPort,
427 port.ipAddress().toIpPrefix(), install);
428 });
429 } else {
430 populateSecurityGroupRule(sgRule, port,
431 sgRule.remoteIpPrefix() == null ? IP_PREFIX_ANY :
432 sgRule.remoteIpPrefix(), install);
433 }
434 }
435
436 private boolean checkProtocol(String protocol) {
437 if (protocol == null) {
438 log.debug("No protocol was specified, use default IP(v4/v6) protocol.");
439 return true;
440 } else {
441 String protocolUpper = protocol.toUpperCase();
442 if (protocolUpper.equals(PROTO_TCP) ||
443 protocolUpper.equals(PROTO_UDP) ||
444 protocolUpper.equals(PROTO_ICMP) ||
445 protocolUpper.equals(PROTO_SCTP) ||
446 protocolUpper.equals(PROTO_ANY) ||
447 protocol.equals(PROTO_TCP_NUM) ||
448 protocol.equals(PROTO_UDP_NUM) ||
449 protocol.equals(PROTO_ICMP_NUM) ||
450 protocol.equals(PROTO_SCTP_NUM) ||
451 protocol.equals(PROTO_ANY_NUM)) {
452 return true;
453 } else {
454 log.error("Unsupported protocol {}, we only support " +
455 "TCP/UDP/ICMP/SCTP protocols.", protocol);
456 return false;
457 }
458 }
459 }
460
461 private void populateSecurityGroupRule(KubevirtSecurityGroupRule sgRule,
462 KubevirtPort port,
463 IpPrefix remoteIp,
464 boolean install) {
465 if (!checkProtocol(sgRule.protocol())) {
466 return;
467 }
468
469 DeviceId deviceId = port.isTenant() ? port.tenantDeviceId() : port.deviceId();
470
Jian Lif89d9602021-04-27 19:05:49 +0900471 Set<TrafficSelector> ctSelectors = buildSelectors(
472 sgRule,
Jian Li8f944d42021-03-23 00:43:29 +0900473 Ip4Address.valueOf(port.ipAddress().toInetAddress()),
Jian Lif89d9602021-04-27 19:05:49 +0900474 port.macAddress(),
Jian Li8f944d42021-03-23 00:43:29 +0900475 remoteIp, port.networkId());
Jian Lif89d9602021-04-27 19:05:49 +0900476 if (ctSelectors == null || ctSelectors.isEmpty()) {
Jian Li8f944d42021-03-23 00:43:29 +0900477 return;
478 }
479
480 // if the device is not available we do not perform any action
481 if (deviceId == null || !deviceService.isAvailable(deviceId)) {
482 return;
483 }
484
485 // XXX All egress traffic needs to go through connection tracking module,
486 // which might hurt its performance.
487 ExtensionTreatment ctTreatment =
488 niciraConnTrackTreatmentBuilder(driverService, deviceId)
489 .commit(true)
490 .build();
491
492 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
493
Jian Lif89d9602021-04-27 19:05:49 +0900494 KubevirtNetwork net = networkService.network(port.networkId());
495
Jian Li8f944d42021-03-23 00:43:29 +0900496 int aclTable;
497 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
Jian Lif89d9602021-04-27 19:05:49 +0900498
499 if (net.type() == FLAT || net.type() == VLAN) {
500 aclTable = ACL_EGRESS_TABLE;
501 } else {
502 aclTable = TENANT_ACL_EGRESS_TABLE;
503 }
504
Jian Li8f944d42021-03-23 00:43:29 +0900505 tBuilder.transition(TENANT_ACL_RECIRC_TABLE);
506 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900507
508 if (net.type() == FLAT || net.type() == VLAN) {
509 aclTable = ACL_INGRESS_TABLE;
510 } else {
511 aclTable = TENANT_ACL_INGRESS_TABLE;
512 }
513
Jian Li8f944d42021-03-23 00:43:29 +0900514 tBuilder.extension(ctTreatment, deviceId)
515 .transition(TENANT_FORWARDING_TABLE);
516 }
517
518 int finalAclTable = aclTable;
Jian Lif89d9602021-04-27 19:05:49 +0900519 ctSelectors.forEach(selector -> {
Jian Li8f944d42021-03-23 00:43:29 +0900520 flowRuleService.setRule(appId,
521 deviceId,
522 selector, tBuilder.build(),
523 PRIORITY_ACL_RULE,
524 finalAclTable,
525 install);
526 });
Jian Lif89d9602021-04-27 19:05:49 +0900527
528 TrafficSelector tSelector = DefaultTrafficSelector.builder()
529 .matchEthType(Ethernet.TYPE_IPV4)
530 .matchEthDst(port.macAddress())
531 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
532 .build();
533 TrafficTreatment tTreatment = DefaultTrafficTreatment.builder()
534 .transition(TENANT_ACL_INGRESS_TABLE)
535 .build();
536
537 flowRuleService.setRule(appId,
538 deviceId,
539 tSelector,
540 tTreatment,
541 PRIORITY_ACL_RULE,
542 TENANT_ACL_RECIRC_TABLE,
543 install);
Jian Li8f944d42021-03-23 00:43:29 +0900544 }
545
546 /**
547 * Sets connection tracking rule using OVS extension commands.
548 * It is not so graceful, but I don't want to make it more general because
549 * it is going to be used only here.
550 * The following is the usage of the function.
551 *
552 * @param deviceId Device ID
553 * @param ctState ctState: please use RulePopulatorUtil.computeCtStateFlag()
554 * to build the value
555 * @param ctMask crMask: please use RulePopulatorUtil.computeCtMaskFlag()
556 * to build the value
557 * @param commit CT_COMMIT for commit action, CT_NO_COMMIT otherwise
558 * @param recircTable table number for recirculation after CT actions.
559 * CT_NO_RECIRC with no recirculation
560 * @param action Additional actions. ACTION_DROP, ACTION_NONE,
561 * GOTO_XXX_TABLE are supported.
562 * @param priority priority value for the rule
563 * @param install true for insertion, false for removal
564 */
565 private void setConnTrackRule(DeviceId deviceId, long ctState, long ctMask,
566 int commit, short recircTable,
567 int action, int priority, boolean install) {
568
569 ExtensionSelector esCtSate = RulePopulatorUtil
570 .buildCtExtensionSelector(driverService, deviceId, ctState, ctMask);
571 TrafficSelector selector = DefaultTrafficSelector.builder()
572 .extension(esCtSate, deviceId)
573 .matchEthType(Ethernet.TYPE_IPV4)
574 .build();
575
576 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
577
578 if (commit == CT_COMMIT || recircTable > 0) {
579 RulePopulatorUtil.NiciraConnTrackTreatmentBuilder natTreatmentBuilder =
580 niciraConnTrackTreatmentBuilder(driverService, deviceId);
581 natTreatmentBuilder.natAction(false);
582 natTreatmentBuilder.commit(commit == CT_COMMIT);
583 if (recircTable > 0) {
584 natTreatmentBuilder.table(recircTable);
585 }
586 tb.extension(natTreatmentBuilder.build(), deviceId);
587 } else if (action == ACTION_DROP) {
588 tb.drop();
589 }
590
591 if (action != ACTION_NONE && action != ACTION_DROP) {
592 tb.transition(action);
593 }
594
595 int tableType = ERROR_TABLE;
596 if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
597 tableType = TENANT_ACL_CT_TABLE;
598 } else if (priority == PRIORITY_CT_HOOK_RULE) {
599 tableType = TENANT_ACL_INGRESS_TABLE;
600 } else {
601 log.error("Cannot an appropriate table for the conn track rule.");
602 }
603
604 flowRuleService.setRule(
605 appId,
606 deviceId,
607 selector,
608 tb.build(),
609 priority,
610 tableType,
611 install);
612 }
613
614 /**
615 * Returns a set of host IP addresses engaged with supplied security group ID.
616 * It only searches a VM in the same tenant boundary.
617 *
618 * @param srcPort edgestack port
619 * @param sgId security group id
620 * @return set of ip addresses
621 */
622 private Set<KubevirtPort> getRemotePorts(KubevirtPort srcPort, String sgId) {
623 return portService.ports().stream()
624 .filter(port -> !port.macAddress().equals(srcPort.macAddress()))
625 .filter(port -> port.securityGroups().contains(sgId))
626 .filter(port -> port.ipAddress() != null)
627 .collect(Collectors.toSet());
628 }
629
630 private Set<TrafficSelector> buildSelectors(KubevirtSecurityGroupRule sgRule,
631 Ip4Address vmIp,
Jian Lif89d9602021-04-27 19:05:49 +0900632 MacAddress vmMac,
Jian Li8f944d42021-03-23 00:43:29 +0900633 IpPrefix remoteIp,
634 String netId) {
635 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
636 // do nothing if the remote IP is my IP
637 return null;
638 }
639
640 Set<TrafficSelector> selectorSet = Sets.newHashSet();
641
642 if (sgRule.portRangeMax() != null && sgRule.portRangeMin() != null &&
643 sgRule.portRangeMin() < sgRule.portRangeMax()) {
644 Map<TpPort, TpPort> portRangeMatchMap =
645 buildPortRangeMatches(sgRule.portRangeMin(),
646 sgRule.portRangeMax());
647 portRangeMatchMap.forEach((key, value) -> {
648
649 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Lif89d9602021-04-27 19:05:49 +0900650 buildMatches(sBuilder, sgRule, vmIp, vmMac, remoteIp);
Jian Li8f944d42021-03-23 00:43:29 +0900651
652 if (sgRule.protocol().equalsIgnoreCase(PROTO_TCP) ||
653 sgRule.protocol().equals(PROTO_TCP_NUM)) {
654 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
655 if (value.toInt() == TpPort.MAX_PORT) {
656 sBuilder.matchTcpSrc(key);
657 } else {
658 sBuilder.matchTcpSrcMasked(key, value);
659 }
660 } else {
661 if (value.toInt() == TpPort.MAX_PORT) {
662 sBuilder.matchTcpDst(key);
663 } else {
664 sBuilder.matchTcpDstMasked(key, value);
665 }
666 }
667 } else if (sgRule.protocol().equalsIgnoreCase(PROTO_UDP) ||
668 sgRule.protocol().equals(PROTO_UDP_NUM)) {
669 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
670 if (value.toInt() == TpPort.MAX_PORT) {
671 sBuilder.matchUdpSrc(key);
672 } else {
673 sBuilder.matchUdpSrcMasked(key, value);
674 }
675 } else {
676 if (value.toInt() == TpPort.MAX_PORT) {
677 sBuilder.matchUdpDst(key);
678 } else {
679 sBuilder.matchUdpDstMasked(key, value);
680 }
681 }
682 } else if (sgRule.protocol().equalsIgnoreCase(PROTO_SCTP) ||
683 sgRule.protocol().equals(PROTO_SCTP_NUM)) {
684 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
685 if (value.toInt() == TpPort.MAX_PORT) {
686 sBuilder.matchSctpSrc(key);
687 } else {
688 sBuilder.matchSctpSrcMasked(key, value);
689 }
690 } else {
691 if (value.toInt() == TpPort.MAX_PORT) {
692 sBuilder.matchSctpDst(key);
693 } else {
694 sBuilder.matchSctpDstMasked(key, value);
695 }
696 }
697 }
698
699 selectorSet.add(sBuilder.build());
700 });
701 } else {
702
703 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Lif89d9602021-04-27 19:05:49 +0900704 buildMatches(sBuilder, sgRule, vmIp, vmMac, remoteIp);
Jian Li8f944d42021-03-23 00:43:29 +0900705
706 selectorSet.add(sBuilder.build());
707 }
708
709 return selectorSet;
710 }
711
712 private void buildMatches(TrafficSelector.Builder sBuilder,
713 KubevirtSecurityGroupRule sgRule, Ip4Address vmIp,
Jian Lif89d9602021-04-27 19:05:49 +0900714 MacAddress vmMac, IpPrefix remoteIp) {
Jian Li8f944d42021-03-23 00:43:29 +0900715 buildMatchEthType(sBuilder, sgRule.etherType());
Jian Lif89d9602021-04-27 19:05:49 +0900716 buildMatchDirection(sBuilder, sgRule.direction(), vmIp, vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900717 buildMatchProto(sBuilder, sgRule.protocol());
718 buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(),
719 sgRule.portRangeMin() == null ? 0 : sgRule.portRangeMin(),
720 sgRule.portRangeMax() == null ? 0 : sgRule.portRangeMax());
721 buildMatchIcmp(sBuilder, sgRule.protocol(),
722 sgRule.portRangeMin(), sgRule.portRangeMax());
723 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
724 }
725
Jian Li8f944d42021-03-23 00:43:29 +0900726 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
727 String direction,
Jian Lif89d9602021-04-27 19:05:49 +0900728 Ip4Address vmIp,
729 MacAddress vmMac) {
Jian Li8f944d42021-03-23 00:43:29 +0900730 if (direction.equalsIgnoreCase(EGRESS)) {
731 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
Jian Lif89d9602021-04-27 19:05:49 +0900732 sBuilder.matchEthSrc(vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900733 } else {
734 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
Jian Lif89d9602021-04-27 19:05:49 +0900735 sBuilder.matchEthDst(vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900736 }
737 }
738
739 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
740 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
741 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
742 if (etherType != null && !Objects.equals(etherType, STR_NULL) &&
743 !etherType.equalsIgnoreCase(ETHTYPE_IPV4)) {
744 log.debug("EthType {} is not supported yet in Security Group", etherType);
745 }
746 }
747
748 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder,
749 IpPrefix remoteIpPrefix, String direction) {
750 if (remoteIpPrefix != null &&
751 !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
752 if (direction.equalsIgnoreCase(EGRESS)) {
753 sBuilder.matchIPDst(remoteIpPrefix);
754 } else {
755 sBuilder.matchIPSrc(remoteIpPrefix);
756 }
757 }
758 }
759
760 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
761 if (protocol != null) {
762 switch (protocol.toUpperCase()) {
763 case PROTO_ICMP:
764 case PROTO_ICMP_NUM:
765 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
766 break;
767 case PROTO_TCP:
768 case PROTO_TCP_NUM:
769 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
770 break;
771 case PROTO_UDP:
772 case PROTO_UDP_NUM:
773 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
774 break;
775 case PROTO_SCTP:
776 case PROTO_SCTP_NUM:
777 sBuilder.matchIPProtocol(PROTOCOL_SCTP);
778 break;
779 default:
780 break;
781 }
782 }
783 }
784
785 private void buildMatchPort(TrafficSelector.Builder sBuilder,
786 String protocol, String direction,
787 int portMin, int portMax) {
788 if (portMax > 0 && portMin == portMax) {
789 if (protocol.equalsIgnoreCase(PROTO_TCP) ||
790 protocol.equals(PROTO_TCP_NUM)) {
791 if (direction.equalsIgnoreCase(EGRESS)) {
792 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
793 } else {
794 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
795 }
796 } else if (protocol.equalsIgnoreCase(PROTO_UDP) ||
797 protocol.equals(PROTO_UDP_NUM)) {
798 if (direction.equalsIgnoreCase(EGRESS)) {
799 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
800 } else {
801 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
802 }
803 } else if (protocol.equalsIgnoreCase(PROTO_SCTP) ||
804 protocol.equals(PROTO_SCTP_NUM)) {
805 if (direction.equalsIgnoreCase(EGRESS)) {
806 sBuilder.matchSctpSrc(TpPort.tpPort(portMax));
807 } else {
808 sBuilder.matchSctpDst(TpPort.tpPort(portMax));
809 }
810 }
811 }
812 }
813
814 private void buildMatchIcmp(TrafficSelector.Builder sBuilder,
815 String protocol, Integer icmpCode, Integer icmpType) {
816 if (protocol != null) {
817 if (protocol.equalsIgnoreCase(PROTO_ICMP) ||
818 protocol.equals(PROTO_ICMP_NUM)) {
819 if (icmpCode != null && icmpCode >= ICMP_CODE_MIN &&
820 icmpCode <= ICMP_CODE_MAX) {
821 sBuilder.matchIcmpCode(icmpCode.byteValue());
822 }
823 if (icmpType != null && icmpType >= ICMP_TYPE_MIN &&
824 icmpType <= ICMP_TYPE_MAX) {
825 sBuilder.matchIcmpType(icmpType.byteValue());
826 }
827 }
828 }
829 }
830
831 private void resetSecurityGroupRules() {
832
833 if (getUseSecurityGroupFlag()) {
834 nodeService.completeNodes(WORKER).forEach(node -> {
Jian Lif89d9602021-04-27 19:05:49 +0900835 initializeProviderPipeline(node, true);
Jian Li8f944d42021-03-23 00:43:29 +0900836
837 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +0900838 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +0900839 }
840 });
841
842 securityGroupService.securityGroups().forEach(securityGroup ->
843 securityGroup.rules().forEach(this::securityGroupRuleAdded));
844 } else {
845 nodeService.completeNodes(WORKER).forEach(node -> {
Jian Lif89d9602021-04-27 19:05:49 +0900846 initializeProviderPipeline(node, false);
Jian Li8f944d42021-03-23 00:43:29 +0900847
848 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +0900849 initializeTenantPipeline(network, node, false);
Jian Li8f944d42021-03-23 00:43:29 +0900850 }
851 });
852
853 securityGroupService.securityGroups().forEach(securityGroup ->
854 securityGroup.rules().forEach(this::securityGroupRuleRemoved));
855 }
856
857 log.info("Reset security group info " +
858 (getUseSecurityGroupFlag() ? "with" : "without") + " Security Group");
859 }
860
861 private void securityGroupRuleAdded(KubevirtSecurityGroupRule sgRule) {
862 portService.ports().stream()
863 .filter(port -> port.securityGroups().contains(sgRule.securityGroupId()))
864 .forEach(port -> {
865 updateSecurityGroupRule(port, sgRule, true);
866 log.info("Applied security group rule {} to port {}",
867 sgRule.id(), port.macAddress());
868 });
869 }
870
871 private void securityGroupRuleRemoved(KubevirtSecurityGroupRule sgRule) {
872 portService.ports().stream()
873 .filter(port -> port.securityGroups().contains(sgRule.securityGroupId()))
874 .forEach(port -> {
875 updateSecurityGroupRule(port, sgRule, false);
876 log.info("Removed security group rule {} from port {}",
877 sgRule.id(), port.macAddress());
878 });
879 }
880
881 private class InternalKubevirtPortListener implements KubevirtPortListener {
882
883 @Override
884 public boolean isRelevant(KubevirtPortEvent event) {
885 return getUseSecurityGroupFlag();
886 }
887
888 private boolean isRelevantHelper(KubevirtPortEvent event) {
889 DeviceId deviceId = event.subject().deviceId();
890
891 if (deviceId == null) {
892 return false;
893 }
894
895 return mastershipService.isLocalMaster(deviceId);
896 }
897
898 @Override
899 public void event(KubevirtPortEvent event) {
900 log.debug("security group event received {}", event);
901
902 switch (event.type()) {
903 case KUBEVIRT_PORT_SECURITY_GROUP_ADDED:
904 eventExecutor.execute(() -> processPortSgAdd(event));
905 break;
906 case KUBEVIRT_PORT_SECURITY_GROUP_REMOVED:
907 eventExecutor.execute(() -> processPortSgRemove(event));
908 break;
909 case KUBEVIRT_PORT_REMOVED:
910 eventExecutor.execute(() -> processPortRemove(event));
911 break;
912 case KUBEVIRT_PORT_DEVICE_ADDED:
913 eventExecutor.execute(() -> processPortDeviceAdded(event));
914 break;
915 default:
916 // do nothing for the other events
917 break;
918 }
919 }
920
921 private void processPortSgAdd(KubevirtPortEvent event) {
922 if (!isRelevantHelper(event)) {
923 return;
924 }
925
926 if (event.securityGroupId() == null ||
927 securityGroupService.securityGroup(event.securityGroupId()) == null) {
928 return;
929 }
930
931 KubevirtPort port = event.subject();
932 KubevirtSecurityGroup sg = securityGroupService.securityGroup(event.securityGroupId());
933
934 sg.rules().forEach(sgRule -> {
935 updateSecurityGroupRule(port, sgRule, true);
936 });
937 log.info("Added security group {} to port {}",
938 event.securityGroupId(), event.subject().macAddress());
939 }
940
941 private void processPortSgRemove(KubevirtPortEvent event) {
942 if (!isRelevantHelper(event)) {
943 return;
944 }
945
946 if (event.securityGroupId() == null ||
947 securityGroupService.securityGroup(event.securityGroupId()) == null) {
948 return;
949 }
950
951 KubevirtPort port = event.subject();
952 KubevirtSecurityGroup sg = securityGroupService.securityGroup(event.securityGroupId());
953
954 sg.rules().forEach(sgRule -> {
955 updateSecurityGroupRule(port, sgRule, false);
956 });
957 log.info("Removed security group {} from port {}",
958 event.securityGroupId(), event.subject().macAddress());
959 }
960
961 private void processPortRemove(KubevirtPortEvent event) {
962 if (!isRelevantHelper(event)) {
963 return;
964 }
965
966 KubevirtPort port = event.subject();
967 for (String sgStr : port.securityGroups()) {
968 KubevirtSecurityGroup sg = securityGroupService.securityGroup(sgStr);
969 sg.rules().forEach(sgRule -> {
970 updateSecurityGroupRule(port, sgRule, false);
971 });
972 log.info("Removed security group {} from port {}",
973 sgStr, event.subject().macAddress());
974 }
975 }
976
977 private void processPortDeviceAdded(KubevirtPortEvent event) {
978 if (!isRelevantHelper(event)) {
979 return;
980 }
981
982 for (String sgId : event.subject().securityGroups()) {
983 KubevirtSecurityGroup sg = securityGroupService.securityGroup(sgId);
984
985 sg.rules().forEach(sgRule -> {
986 updateSecurityGroupRule(event.subject(), sgRule, true);
987 });
988 log.info("Added security group {} to port {}",
Jian Lif89d9602021-04-27 19:05:49 +0900989 sg.id(), event.subject().macAddress());
Jian Li8f944d42021-03-23 00:43:29 +0900990 }
991 }
992 }
993
994 private class InternalNetworkListener implements KubevirtNetworkListener {
995
996 private boolean isRelevantHelper() {
997 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
998 }
999
1000 @Override
1001 public void event(KubevirtNetworkEvent event) {
1002 switch (event.type()) {
1003 case KUBEVIRT_NETWORK_CREATED:
1004 eventExecutor.execute(() -> processNetworkCreation(event.subject()));
1005 break;
1006 case KUBEVIRT_NETWORK_REMOVED:
1007 case KUBEVIRT_NETWORK_UPDATED:
1008 default:
1009 // do thing
1010 break;
1011 }
1012 }
1013
1014 private void processNetworkCreation(KubevirtNetwork network) {
1015 if (!isRelevantHelper()) {
1016 return;
1017 }
1018
1019 Set<KubevirtNode> nodes = nodeService.completeNodes(WORKER);
1020
1021 if (nodes.size() > 0) {
1022 // now we wait 5s for all tenant bridges are created,
1023 // FIXME: we need to fina a better way to wait all tenant bridges
1024 // are created before installing default security group rules
Jian Li0c656f02021-06-07 13:32:39 +09001025 waitFor(5);
Jian Li8f944d42021-03-23 00:43:29 +09001026
1027 for (KubevirtNode node : nodes) {
Jian Lif89d9602021-04-27 19:05:49 +09001028 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +09001029 }
1030 }
1031 }
1032 }
1033
1034 private class InternalSecurityGroupListener implements KubevirtSecurityGroupListener {
1035
1036 @Override
1037 public boolean isRelevant(KubevirtSecurityGroupEvent event) {
1038 return getUseSecurityGroupFlag();
1039 }
1040
1041 private boolean isRelevantHelper() {
1042 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1043 }
1044
1045 @Override
1046 public void event(KubevirtSecurityGroupEvent event) {
1047 switch (event.type()) {
1048 case KUBEVIRT_SECURITY_GROUP_RULE_CREATED:
1049 eventExecutor.execute(() -> processSgRuleCreate(event));
1050 break;
1051 case KUBEVIRT_SECURITY_GROUP_RULE_REMOVED:
1052 eventExecutor.execute(() -> processSgRuleRemove(event));
1053 break;
1054 default:
1055 // do nothing
1056 break;
1057 }
1058 }
1059
1060 private void processSgRuleCreate(KubevirtSecurityGroupEvent event) {
1061 if (!isRelevantHelper()) {
1062 return;
1063 }
1064
1065 KubevirtSecurityGroupRule sgRuleToAdd = event.rule();
1066 securityGroupRuleAdded(sgRuleToAdd);
1067 log.info("Applied new security group rule {} to ports", sgRuleToAdd.id());
1068 }
1069
1070 private void processSgRuleRemove(KubevirtSecurityGroupEvent event) {
1071 if (!isRelevantHelper()) {
1072 return;
1073 }
1074
1075 KubevirtSecurityGroupRule sgRuleToRemove = event.rule();
1076 securityGroupRuleRemoved(sgRuleToRemove);
1077 log.info("Removed security group rule {} from ports", sgRuleToRemove.id());
1078 }
1079 }
1080
1081 private class InternalNodeListener implements KubevirtNodeListener {
1082
1083 @Override
1084 public boolean isRelevant(KubevirtNodeEvent event) {
1085 return event.subject().type() == WORKER;
1086 }
1087
1088 private boolean isRelevantHelper() {
1089 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1090 }
1091
1092 @Override
1093 public void event(KubevirtNodeEvent event) {
1094 switch (event.type()) {
1095 case KUBEVIRT_NODE_COMPLETE:
1096 eventExecutor.execute(() -> processNodeComplete(event.subject()));
1097 break;
1098 default:
1099 break;
1100 }
1101 }
1102
1103 private void processNodeComplete(KubevirtNode node) {
1104 if (!isRelevantHelper()) {
1105 return;
1106 }
1107
Jian Lif89d9602021-04-27 19:05:49 +09001108 // FIXME: we wait all port get its deviceId updated
Jian Li0c656f02021-06-07 13:32:39 +09001109 waitFor(5);
Jian Lif89d9602021-04-27 19:05:49 +09001110
Jian Li8f944d42021-03-23 00:43:29 +09001111 resetSecurityGroupRulesByNode(node);
1112 }
1113
1114 private void resetSecurityGroupRulesByNode(KubevirtNode node) {
1115 if (getUseSecurityGroupFlag()) {
Jian Lif89d9602021-04-27 19:05:49 +09001116 initializeProviderPipeline(node, true);
Jian Li8f944d42021-03-23 00:43:29 +09001117
1118 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +09001119 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +09001120 }
1121
1122 securityGroupService.securityGroups().forEach(securityGroup ->
1123 securityGroup.rules().forEach(
1124 KubevirtSecurityGroupHandler.this::securityGroupRuleAdded));
1125 } else {
Jian Lif89d9602021-04-27 19:05:49 +09001126 initializeProviderPipeline(node, false);
Jian Li8f944d42021-03-23 00:43:29 +09001127
1128 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +09001129 initializeTenantPipeline(network, node, false);
Jian Li8f944d42021-03-23 00:43:29 +09001130 }
1131
1132 securityGroupService.securityGroups().forEach(securityGroup ->
1133 securityGroup.rules().forEach(
1134 KubevirtSecurityGroupHandler.this::securityGroupRuleRemoved));
1135 }
1136
1137 log.info("Reset security group info " +
1138 (getUseSecurityGroupFlag() ? "with" : "without") + " Security Group");
1139 }
1140 }
1141}