blob: 2c35b740ccb1c86b4e116ee8fedd285ba5ac4da5 [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;
Jian Lifc2d71e2022-10-17 15:34:10 +090054import org.onosproject.net.Device;
Jian Li8f944d42021-03-23 00:43:29 +090055import org.onosproject.net.DeviceId;
Jian Lif89d9602021-04-27 19:05:49 +090056import org.onosproject.net.PortNumber;
Jian Lifc2d71e2022-10-17 15:34:10 +090057import org.onosproject.net.device.DeviceEvent;
58import org.onosproject.net.device.DeviceListener;
Jian Li8f944d42021-03-23 00:43:29 +090059import org.onosproject.net.device.DeviceService;
60import org.onosproject.net.driver.DriverService;
61import org.onosproject.net.flow.DefaultTrafficSelector;
62import org.onosproject.net.flow.DefaultTrafficTreatment;
63import org.onosproject.net.flow.TrafficSelector;
64import org.onosproject.net.flow.TrafficTreatment;
65import org.onosproject.net.flow.criteria.ExtensionSelector;
66import org.onosproject.net.flow.instructions.ExtensionTreatment;
67import org.onosproject.store.service.StorageService;
68import org.osgi.service.component.ComponentContext;
69import org.osgi.service.component.annotations.Activate;
70import org.osgi.service.component.annotations.Component;
71import org.osgi.service.component.annotations.Deactivate;
72import org.osgi.service.component.annotations.Modified;
73import org.osgi.service.component.annotations.Reference;
74import org.osgi.service.component.annotations.ReferenceCardinality;
75import org.slf4j.Logger;
76
77import java.util.Dictionary;
78import java.util.Map;
79import java.util.Objects;
80import java.util.Set;
81import java.util.concurrent.ExecutorService;
82import java.util.stream.Collectors;
83
Jian Li8f944d42021-03-23 00:43:29 +090084import static java.util.concurrent.Executors.newSingleThreadExecutor;
85import static org.onlab.util.Tools.groupedThreads;
Jian Lif89d9602021-04-27 19:05:49 +090086import static org.onosproject.kubevirtnetworking.api.Constants.ACL_CT_TABLE;
87import static org.onosproject.kubevirtnetworking.api.Constants.ACL_EGRESS_TABLE;
88import static org.onosproject.kubevirtnetworking.api.Constants.ACL_INGRESS_TABLE;
89import static org.onosproject.kubevirtnetworking.api.Constants.ACL_RECIRC_TABLE;
Jian Li8f944d42021-03-23 00:43:29 +090090import static org.onosproject.kubevirtnetworking.api.Constants.ERROR_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +090091import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Li8f944d42021-03-23 00:43:29 +090092import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
93import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_INGRESS_RULE;
94import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_RULE;
95import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_DROP_RULE;
96import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
97import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_RULE;
98import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_CT_TABLE;
99import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_EGRESS_TABLE;
100import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_INGRESS_TABLE;
101import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_RECIRC_TABLE;
102import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +0900103import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.FLAT;
Jian Li8f944d42021-03-23 00:43:29 +0900104import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
Jian Li8f944d42021-03-23 00:43:29 +0900105import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP;
106import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP_DEFAULT;
107import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
Jian Li0c656f02021-06-07 13:32:39 +0900108import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.waitFor;
Jian Li8f944d42021-03-23 00:43:29 +0900109import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildPortRangeMatches;
110import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.computeCtMaskFlag;
111import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.computeCtStateFlag;
112import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
113import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
114import static org.slf4j.LoggerFactory.getLogger;
115
116/**
117 * Populates flow rules to handle EdgeStack SecurityGroups.
118 */
119@Component(
120 immediate = true,
121 property = {
122 USE_SECURITY_GROUP + ":Boolean=" + USE_SECURITY_GROUP_DEFAULT
123 }
124)
125public class KubevirtSecurityGroupHandler {
126
127 private final Logger log = getLogger(getClass());
128
129 private static final int VM_IP_PREFIX = 32;
130
131 private static final String STR_NULL = "null";
132 private static final String PROTO_ICMP = "ICMP";
133 private static final String PROTO_ICMP_NUM = "1";
134 private static final String PROTO_TCP = "TCP";
135 private static final String PROTO_TCP_NUM = "6";
136 private static final String PROTO_UDP = "UDP";
137 private static final String PROTO_UDP_NUM = "17";
138 private static final String PROTO_SCTP = "SCTP";
139 private static final String PROTO_SCTP_NUM = "132";
140 private static final byte PROTOCOL_SCTP = (byte) 0x84;
141 private static final String PROTO_ANY = "ANY";
142 private static final String PROTO_ANY_NUM = "0";
143 private static final String ETHTYPE_IPV4 = "IPV4";
144 private static final String EGRESS = "EGRESS";
145 private static final String INGRESS = "INGRESS";
146 private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
147
148 private static final int ICMP_CODE_MIN = 0;
149 private static final int ICMP_CODE_MAX = 255;
150 private static final int ICMP_TYPE_MIN = 0;
151 private static final int ICMP_TYPE_MAX = 255;
152
153 private static final int CT_COMMIT = 0;
154 private static final int CT_NO_COMMIT = 1;
155 private static final short CT_NO_RECIRC = -1;
156
157 private static final int ACTION_NONE = 0;
158 private static final int ACTION_DROP = -1;
159
Jian Li8f944d42021-03-23 00:43:29 +0900160 /** Apply EdgeStack security group rule for VM traffic. */
161 private boolean useSecurityGroup = USE_SECURITY_GROUP_DEFAULT;
162
163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
164 protected CoreService coreService;
165
166 @Reference(cardinality = ReferenceCardinality.MANDATORY)
167 protected MastershipService mastershipService;
168
169 @Reference(cardinality = ReferenceCardinality.MANDATORY)
170 protected DriverService driverService;
171
172 @Reference(cardinality = ReferenceCardinality.MANDATORY)
173 protected DeviceService deviceService;
174
175 @Reference(cardinality = ReferenceCardinality.MANDATORY)
176 protected LeadershipService leadershipService;
177
178 @Reference(cardinality = ReferenceCardinality.MANDATORY)
179 protected ClusterService clusterService;
180
181 @Reference(cardinality = ReferenceCardinality.MANDATORY)
182 protected StorageService storageService;
183
184 @Reference(cardinality = ReferenceCardinality.MANDATORY)
185 protected ComponentConfigService configService;
186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY)
188 protected KubevirtNodeService nodeService;
189
190 @Reference(cardinality = ReferenceCardinality.MANDATORY)
191 protected KubevirtNetworkService networkService;
192
193 @Reference(cardinality = ReferenceCardinality.MANDATORY)
194 protected KubevirtPortService portService;
195
196 @Reference(cardinality = ReferenceCardinality.MANDATORY)
197 protected KubevirtFlowRuleService flowRuleService;
198
199 @Reference(cardinality = ReferenceCardinality.MANDATORY)
200 protected KubevirtSecurityGroupService securityGroupService;
201
Jian Lifc2d71e2022-10-17 15:34:10 +0900202 private final DeviceListener deviceListener =
203 new InternalDeviceListener();
204
Jian Li8f944d42021-03-23 00:43:29 +0900205 private final KubevirtPortListener portListener =
206 new InternalKubevirtPortListener();
207 private final KubevirtSecurityGroupListener securityGroupListener =
208 new InternalSecurityGroupListener();
209 private final KubevirtNodeListener nodeListener =
210 new InternalNodeListener();
211 private final KubevirtNetworkListener networkListener =
212 new InternalNetworkListener();
213
214 private final ExecutorService eventExecutor = newSingleThreadExecutor(
215 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
216
217 private ApplicationId appId;
218 private NodeId localNodeId;
219
220 @Activate
221 protected void activate() {
222 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
223 localNodeId = clusterService.getLocalNode().id();
Jian Lifc2d71e2022-10-17 15:34:10 +0900224 deviceService.addListener(deviceListener);
Jian Li8f944d42021-03-23 00:43:29 +0900225 securityGroupService.addListener(securityGroupListener);
226 portService.addListener(portListener);
227 networkService.addListener(networkListener);
228 configService.registerProperties(getClass());
229 nodeService.addListener(nodeListener);
230
231 log.info("Started");
232 }
233
234 @Deactivate
235 protected void deactivate() {
236 securityGroupService.removeListener(securityGroupListener);
237 portService.removeListener(portListener);
238 configService.unregisterProperties(getClass(), false);
239 nodeService.removeListener(nodeListener);
240 networkService.removeListener(networkListener);
Jian Lifc2d71e2022-10-17 15:34:10 +0900241 deviceService.removeListener(deviceListener);
Jian Li8f944d42021-03-23 00:43:29 +0900242 eventExecutor.shutdown();
243
244 log.info("Stopped");
245 }
246
247 @Modified
248 protected void modified(ComponentContext context) {
249 Dictionary<?, ?> properties = context.getProperties();
250 Boolean flag;
251
252 flag = Tools.isPropertyEnabled(properties, USE_SECURITY_GROUP);
253 if (flag == null) {
254 log.info("useSecurityGroup is not configured, " +
255 "using current value of {}", useSecurityGroup);
256 } else {
257 useSecurityGroup = flag;
258 log.info("Configured. useSecurityGroup is {}",
259 useSecurityGroup ? "enabled" : "disabled");
260 }
261
262 securityGroupService.setSecurityGroupEnabled(useSecurityGroup);
263 resetSecurityGroupRules();
264 }
265
266 private boolean getUseSecurityGroupFlag() {
267 Set<ConfigProperty> properties =
268 configService.getProperties(getClass().getName());
269 return getPropertyValueAsBoolean(properties, USE_SECURITY_GROUP);
270 }
271
Jian Lif89d9602021-04-27 19:05:49 +0900272 private void initializeProviderConnTrackTable(DeviceId deviceId, boolean install) {
273 initializeConnTrackTable(deviceId, ACL_CT_TABLE, FORWARDING_TABLE, install);
274 }
275
276 private void initializeTenantConnTrackTable(DeviceId deviceId, boolean install) {
277 initializeConnTrackTable(deviceId, TENANT_ACL_CT_TABLE, TENANT_FORWARDING_TABLE, install);
278 }
279
280 private void initializeConnTrackTable(DeviceId deviceId, int ctTable,
281 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900282
283 // table={ACL_INGRESS_TABLE(44)},ip,ct_state=-trk, actions=ct(table:{ACL_CT_TABLE(45)})
284 long ctState = computeCtStateFlag(false, false, false);
285 long ctMask = computeCtMaskFlag(true, false, false);
Jian Lif89d9602021-04-27 19:05:49 +0900286 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) ctTable,
Jian Li8f944d42021-03-23 00:43:29 +0900287 ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
288
289 //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:{NORMAL_TABLE(80)}
290 ctState = computeCtStateFlag(true, false, true);
291 ctMask = computeCtMaskFlag(true, false, true);
292 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
Jian Lif89d9602021-04-27 19:05:49 +0900293 forwardTable, PRIORITY_CT_RULE, install);
Jian Li8f944d42021-03-23 00:43:29 +0900294
295 //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
296 ctState = computeCtStateFlag(true, true, false);
297 ctMask = computeCtMaskFlag(true, true, false);
298 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
299 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
300 }
301
Jian Li1bc914c2021-06-08 14:09:14 +0900302 private void initializeProviderAclTable(DeviceId deviceId, boolean install) {
303 initializeAclTable(deviceId, ACL_RECIRC_TABLE, PortNumber.NORMAL, install);
Jian Lif89d9602021-04-27 19:05:49 +0900304 }
305
306 private void initializeTenantAclTable(KubevirtNetwork network,
307 DeviceId deviceId, boolean install) {
Jian Li56f241b2021-06-30 20:59:43 +0900308 // FIXME: in bridge initialization phase, some patch ports may not be
309 // available until they are created, we wait for a while ensure all
310 // patch ports are created via network bootstrap
311 while (true) {
312 if (network.tenantToTunnelPort(deviceId) != null) {
313 break;
314 } else {
315 log.info("Wait for tenant patch ports creation for device {} " +
316 "and network {}", deviceId, network.networkId());
317 waitFor(5);
318 }
319 }
320
Jian Lif89d9602021-04-27 19:05:49 +0900321 PortNumber patchPort = network.tenantToTunnelPort(deviceId);
322 initializeAclTable(deviceId, TENANT_ACL_RECIRC_TABLE, patchPort, install);
323 }
324
325 private void initializeAclTable(DeviceId deviceId, int recircTable,
326 PortNumber outport, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900327
328 ExtensionTreatment ctTreatment =
329 niciraConnTrackTreatmentBuilder(driverService, deviceId)
330 .commit(true)
331 .build();
332
333 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
334 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
335
336 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
337 tBuilder.extension(ctTreatment, deviceId)
Jian Lif89d9602021-04-27 19:05:49 +0900338 .setOutput(outport);
Jian Li8f944d42021-03-23 00:43:29 +0900339
340 flowRuleService.setRule(appId,
341 deviceId,
342 sBuilder.build(),
343 tBuilder.build(),
344 PRIORITY_ACL_INGRESS_RULE,
Jian Lif89d9602021-04-27 19:05:49 +0900345 recircTable,
Jian Li8f944d42021-03-23 00:43:29 +0900346 install);
347 }
348
Jian Lif89d9602021-04-27 19:05:49 +0900349 private void initializeProviderEgressTable(DeviceId deviceId, boolean install) {
350 initializeEgressTable(deviceId, ACL_EGRESS_TABLE, FORWARDING_TABLE, install);
351 }
352
353 private void initializeTenantEgressTable(DeviceId deviceId, boolean install) {
354 initializeEgressTable(deviceId, TENANT_ACL_EGRESS_TABLE, TENANT_FORWARDING_TABLE, install);
355 }
356
357 private void initializeEgressTable(DeviceId deviceId, int egressTable,
358 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900359 if (install) {
360 flowRuleService.setUpTableMissEntry(deviceId, TENANT_ACL_EGRESS_TABLE);
361 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900362 flowRuleService.connectTables(deviceId, egressTable, forwardTable);
Jian Li8f944d42021-03-23 00:43:29 +0900363 }
364 }
365
Jian Lif89d9602021-04-27 19:05:49 +0900366 private void initializeProviderIngressTable(DeviceId deviceId, boolean install) {
367 initializeIngressTable(deviceId, ACL_INGRESS_TABLE, FORWARDING_TABLE, install);
368 }
369
370 private void initializeTenantIngressTable(DeviceId deviceId, boolean install) {
371 initializeIngressTable(deviceId, TENANT_ACL_INGRESS_TABLE, TENANT_FORWARDING_TABLE, install);
372 }
373
374 private void initializeIngressTable(DeviceId deviceId, int ingressTable,
375 int forwardTable, boolean install) {
Jian Li8f944d42021-03-23 00:43:29 +0900376 if (install) {
Jian Lif89d9602021-04-27 19:05:49 +0900377 flowRuleService.setUpTableMissEntry(deviceId, ingressTable);
Jian Li8f944d42021-03-23 00:43:29 +0900378 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900379 flowRuleService.connectTables(deviceId, ingressTable, forwardTable);
Jian Li8f944d42021-03-23 00:43:29 +0900380 }
381 }
382
Jian Lif89d9602021-04-27 19:05:49 +0900383 private void initializeProviderPipeline(KubevirtNode node, boolean install) {
384 initializeProviderIngressTable(node.intgBridge(), install);
385 initializeProviderEgressTable(node.intgBridge(), install);
386 initializeProviderConnTrackTable(node.intgBridge(), install);
Jian Li1bc914c2021-06-08 14:09:14 +0900387 initializeProviderAclTable(node.intgBridge(), install);
Jian Lif89d9602021-04-27 19:05:49 +0900388 }
389
390 private void initializeTenantPipeline(KubevirtNetwork network,
391 KubevirtNode node, boolean install) {
392 DeviceId deviceId = network.tenantDeviceId(node.hostname());
393 if (deviceId == null) {
394 return;
395 }
Jian Li567b25c2021-05-27 15:17:59 +0900396
397 // we check whether the given device is available from the store
398 // if not we will wait until the device is eventually created
399 // FIXME: it would be better to listen to device event to perform
400 // pipeline initialization rather on network events.
401 while (true) {
402 if (deviceService.getDevice(deviceId) != null) {
403 break;
404 } else {
Jian Li0c656f02021-06-07 13:32:39 +0900405 waitFor(5);
Jian Li567b25c2021-05-27 15:17:59 +0900406 }
407 }
408
Jian Lif89d9602021-04-27 19:05:49 +0900409 initializeTenantIngressTable(deviceId, install);
410 initializeTenantEgressTable(deviceId, install);
411 initializeTenantConnTrackTable(deviceId, install);
412 initializeTenantAclTable(network, deviceId, install);
413 }
414
Jian Li8f944d42021-03-23 00:43:29 +0900415 private void updateSecurityGroupRule(KubevirtPort port,
416 KubevirtSecurityGroupRule sgRule, boolean install) {
417
418 if (port == null || sgRule == null) {
419 return;
420 }
421
422 if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().isEmpty()) {
423 getRemotePorts(port, sgRule.remoteGroupId())
424 .forEach(rPort -> {
425 populateSecurityGroupRule(sgRule, port,
426 rPort.ipAddress().toIpPrefix(), install);
427 populateSecurityGroupRule(sgRule, rPort,
428 port.ipAddress().toIpPrefix(), install);
429
430 KubevirtSecurityGroupRule rSgRule = sgRule.updateDirection(
431 sgRule.direction().equalsIgnoreCase(EGRESS) ? INGRESS : EGRESS);
432 populateSecurityGroupRule(rSgRule, port,
433 rPort.ipAddress().toIpPrefix(), install);
434 populateSecurityGroupRule(rSgRule, rPort,
435 port.ipAddress().toIpPrefix(), install);
436 });
437 } else {
438 populateSecurityGroupRule(sgRule, port,
439 sgRule.remoteIpPrefix() == null ? IP_PREFIX_ANY :
440 sgRule.remoteIpPrefix(), install);
441 }
442 }
443
444 private boolean checkProtocol(String protocol) {
445 if (protocol == null) {
446 log.debug("No protocol was specified, use default IP(v4/v6) protocol.");
447 return true;
448 } else {
449 String protocolUpper = protocol.toUpperCase();
450 if (protocolUpper.equals(PROTO_TCP) ||
451 protocolUpper.equals(PROTO_UDP) ||
452 protocolUpper.equals(PROTO_ICMP) ||
453 protocolUpper.equals(PROTO_SCTP) ||
454 protocolUpper.equals(PROTO_ANY) ||
455 protocol.equals(PROTO_TCP_NUM) ||
456 protocol.equals(PROTO_UDP_NUM) ||
457 protocol.equals(PROTO_ICMP_NUM) ||
458 protocol.equals(PROTO_SCTP_NUM) ||
459 protocol.equals(PROTO_ANY_NUM)) {
460 return true;
461 } else {
462 log.error("Unsupported protocol {}, we only support " +
463 "TCP/UDP/ICMP/SCTP protocols.", protocol);
464 return false;
465 }
466 }
467 }
468
469 private void populateSecurityGroupRule(KubevirtSecurityGroupRule sgRule,
470 KubevirtPort port,
471 IpPrefix remoteIp,
472 boolean install) {
473 if (!checkProtocol(sgRule.protocol())) {
474 return;
475 }
476
477 DeviceId deviceId = port.isTenant() ? port.tenantDeviceId() : port.deviceId();
478
Jian Lif89d9602021-04-27 19:05:49 +0900479 Set<TrafficSelector> ctSelectors = buildSelectors(
480 sgRule,
Jian Li8f944d42021-03-23 00:43:29 +0900481 Ip4Address.valueOf(port.ipAddress().toInetAddress()),
Jian Lif89d9602021-04-27 19:05:49 +0900482 port.macAddress(),
Jian Li8f944d42021-03-23 00:43:29 +0900483 remoteIp, port.networkId());
Jian Lif89d9602021-04-27 19:05:49 +0900484 if (ctSelectors == null || ctSelectors.isEmpty()) {
Jian Li8f944d42021-03-23 00:43:29 +0900485 return;
486 }
487
488 // if the device is not available we do not perform any action
489 if (deviceId == null || !deviceService.isAvailable(deviceId)) {
490 return;
491 }
492
493 // XXX All egress traffic needs to go through connection tracking module,
494 // which might hurt its performance.
495 ExtensionTreatment ctTreatment =
496 niciraConnTrackTreatmentBuilder(driverService, deviceId)
497 .commit(true)
498 .build();
499
500 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
501
Jian Lif89d9602021-04-27 19:05:49 +0900502 KubevirtNetwork net = networkService.network(port.networkId());
503
Jian Li8f944d42021-03-23 00:43:29 +0900504 int aclTable;
505 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
Jian Lif89d9602021-04-27 19:05:49 +0900506
507 if (net.type() == FLAT || net.type() == VLAN) {
508 aclTable = ACL_EGRESS_TABLE;
509 } else {
510 aclTable = TENANT_ACL_EGRESS_TABLE;
511 }
512
Jian Li8f944d42021-03-23 00:43:29 +0900513 tBuilder.transition(TENANT_ACL_RECIRC_TABLE);
514 } else {
Jian Lif89d9602021-04-27 19:05:49 +0900515
516 if (net.type() == FLAT || net.type() == VLAN) {
517 aclTable = ACL_INGRESS_TABLE;
518 } else {
519 aclTable = TENANT_ACL_INGRESS_TABLE;
520 }
521
Jian Li8f944d42021-03-23 00:43:29 +0900522 tBuilder.extension(ctTreatment, deviceId)
523 .transition(TENANT_FORWARDING_TABLE);
524 }
525
526 int finalAclTable = aclTable;
Jian Lif89d9602021-04-27 19:05:49 +0900527 ctSelectors.forEach(selector -> {
Jian Li8f944d42021-03-23 00:43:29 +0900528 flowRuleService.setRule(appId,
529 deviceId,
530 selector, tBuilder.build(),
531 PRIORITY_ACL_RULE,
532 finalAclTable,
533 install);
534 });
Jian Lif89d9602021-04-27 19:05:49 +0900535
536 TrafficSelector tSelector = DefaultTrafficSelector.builder()
537 .matchEthType(Ethernet.TYPE_IPV4)
538 .matchEthDst(port.macAddress())
539 .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
540 .build();
541 TrafficTreatment tTreatment = DefaultTrafficTreatment.builder()
542 .transition(TENANT_ACL_INGRESS_TABLE)
543 .build();
544
545 flowRuleService.setRule(appId,
546 deviceId,
547 tSelector,
548 tTreatment,
549 PRIORITY_ACL_RULE,
550 TENANT_ACL_RECIRC_TABLE,
551 install);
Jian Li8f944d42021-03-23 00:43:29 +0900552 }
553
554 /**
555 * Sets connection tracking rule using OVS extension commands.
556 * It is not so graceful, but I don't want to make it more general because
557 * it is going to be used only here.
558 * The following is the usage of the function.
559 *
560 * @param deviceId Device ID
561 * @param ctState ctState: please use RulePopulatorUtil.computeCtStateFlag()
562 * to build the value
563 * @param ctMask crMask: please use RulePopulatorUtil.computeCtMaskFlag()
564 * to build the value
565 * @param commit CT_COMMIT for commit action, CT_NO_COMMIT otherwise
566 * @param recircTable table number for recirculation after CT actions.
567 * CT_NO_RECIRC with no recirculation
568 * @param action Additional actions. ACTION_DROP, ACTION_NONE,
569 * GOTO_XXX_TABLE are supported.
570 * @param priority priority value for the rule
571 * @param install true for insertion, false for removal
572 */
573 private void setConnTrackRule(DeviceId deviceId, long ctState, long ctMask,
574 int commit, short recircTable,
575 int action, int priority, boolean install) {
576
577 ExtensionSelector esCtSate = RulePopulatorUtil
578 .buildCtExtensionSelector(driverService, deviceId, ctState, ctMask);
579 TrafficSelector selector = DefaultTrafficSelector.builder()
580 .extension(esCtSate, deviceId)
581 .matchEthType(Ethernet.TYPE_IPV4)
582 .build();
583
584 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
585
586 if (commit == CT_COMMIT || recircTable > 0) {
587 RulePopulatorUtil.NiciraConnTrackTreatmentBuilder natTreatmentBuilder =
588 niciraConnTrackTreatmentBuilder(driverService, deviceId);
589 natTreatmentBuilder.natAction(false);
590 natTreatmentBuilder.commit(commit == CT_COMMIT);
591 if (recircTable > 0) {
592 natTreatmentBuilder.table(recircTable);
593 }
594 tb.extension(natTreatmentBuilder.build(), deviceId);
595 } else if (action == ACTION_DROP) {
596 tb.drop();
597 }
598
599 if (action != ACTION_NONE && action != ACTION_DROP) {
600 tb.transition(action);
601 }
602
603 int tableType = ERROR_TABLE;
604 if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
605 tableType = TENANT_ACL_CT_TABLE;
606 } else if (priority == PRIORITY_CT_HOOK_RULE) {
607 tableType = TENANT_ACL_INGRESS_TABLE;
608 } else {
609 log.error("Cannot an appropriate table for the conn track rule.");
610 }
611
612 flowRuleService.setRule(
613 appId,
614 deviceId,
615 selector,
616 tb.build(),
617 priority,
618 tableType,
619 install);
620 }
621
622 /**
623 * Returns a set of host IP addresses engaged with supplied security group ID.
624 * It only searches a VM in the same tenant boundary.
625 *
626 * @param srcPort edgestack port
627 * @param sgId security group id
628 * @return set of ip addresses
629 */
630 private Set<KubevirtPort> getRemotePorts(KubevirtPort srcPort, String sgId) {
631 return portService.ports().stream()
632 .filter(port -> !port.macAddress().equals(srcPort.macAddress()))
633 .filter(port -> port.securityGroups().contains(sgId))
634 .filter(port -> port.ipAddress() != null)
635 .collect(Collectors.toSet());
636 }
637
638 private Set<TrafficSelector> buildSelectors(KubevirtSecurityGroupRule sgRule,
639 Ip4Address vmIp,
Jian Lif89d9602021-04-27 19:05:49 +0900640 MacAddress vmMac,
Jian Li8f944d42021-03-23 00:43:29 +0900641 IpPrefix remoteIp,
642 String netId) {
643 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
644 // do nothing if the remote IP is my IP
645 return null;
646 }
647
648 Set<TrafficSelector> selectorSet = Sets.newHashSet();
649
650 if (sgRule.portRangeMax() != null && sgRule.portRangeMin() != null &&
651 sgRule.portRangeMin() < sgRule.portRangeMax()) {
652 Map<TpPort, TpPort> portRangeMatchMap =
653 buildPortRangeMatches(sgRule.portRangeMin(),
654 sgRule.portRangeMax());
655 portRangeMatchMap.forEach((key, value) -> {
656
657 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Lif89d9602021-04-27 19:05:49 +0900658 buildMatches(sBuilder, sgRule, vmIp, vmMac, remoteIp);
Jian Li8f944d42021-03-23 00:43:29 +0900659
660 if (sgRule.protocol().equalsIgnoreCase(PROTO_TCP) ||
661 sgRule.protocol().equals(PROTO_TCP_NUM)) {
662 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
663 if (value.toInt() == TpPort.MAX_PORT) {
664 sBuilder.matchTcpSrc(key);
665 } else {
666 sBuilder.matchTcpSrcMasked(key, value);
667 }
668 } else {
669 if (value.toInt() == TpPort.MAX_PORT) {
670 sBuilder.matchTcpDst(key);
671 } else {
672 sBuilder.matchTcpDstMasked(key, value);
673 }
674 }
675 } else if (sgRule.protocol().equalsIgnoreCase(PROTO_UDP) ||
676 sgRule.protocol().equals(PROTO_UDP_NUM)) {
677 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
678 if (value.toInt() == TpPort.MAX_PORT) {
679 sBuilder.matchUdpSrc(key);
680 } else {
681 sBuilder.matchUdpSrcMasked(key, value);
682 }
683 } else {
684 if (value.toInt() == TpPort.MAX_PORT) {
685 sBuilder.matchUdpDst(key);
686 } else {
687 sBuilder.matchUdpDstMasked(key, value);
688 }
689 }
690 } else if (sgRule.protocol().equalsIgnoreCase(PROTO_SCTP) ||
691 sgRule.protocol().equals(PROTO_SCTP_NUM)) {
692 if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
693 if (value.toInt() == TpPort.MAX_PORT) {
694 sBuilder.matchSctpSrc(key);
695 } else {
696 sBuilder.matchSctpSrcMasked(key, value);
697 }
698 } else {
699 if (value.toInt() == TpPort.MAX_PORT) {
700 sBuilder.matchSctpDst(key);
701 } else {
702 sBuilder.matchSctpDstMasked(key, value);
703 }
704 }
705 }
706
707 selectorSet.add(sBuilder.build());
708 });
709 } else {
710
711 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Lif89d9602021-04-27 19:05:49 +0900712 buildMatches(sBuilder, sgRule, vmIp, vmMac, remoteIp);
Jian Li8f944d42021-03-23 00:43:29 +0900713
714 selectorSet.add(sBuilder.build());
715 }
716
717 return selectorSet;
718 }
719
720 private void buildMatches(TrafficSelector.Builder sBuilder,
721 KubevirtSecurityGroupRule sgRule, Ip4Address vmIp,
Jian Lif89d9602021-04-27 19:05:49 +0900722 MacAddress vmMac, IpPrefix remoteIp) {
Jian Li8f944d42021-03-23 00:43:29 +0900723 buildMatchEthType(sBuilder, sgRule.etherType());
Jian Lif89d9602021-04-27 19:05:49 +0900724 buildMatchDirection(sBuilder, sgRule.direction(), vmIp, vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900725 buildMatchProto(sBuilder, sgRule.protocol());
726 buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(),
727 sgRule.portRangeMin() == null ? 0 : sgRule.portRangeMin(),
728 sgRule.portRangeMax() == null ? 0 : sgRule.portRangeMax());
729 buildMatchIcmp(sBuilder, sgRule.protocol(),
730 sgRule.portRangeMin(), sgRule.portRangeMax());
731 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
732 }
733
Jian Li8f944d42021-03-23 00:43:29 +0900734 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
735 String direction,
Jian Lif89d9602021-04-27 19:05:49 +0900736 Ip4Address vmIp,
737 MacAddress vmMac) {
Jian Li8f944d42021-03-23 00:43:29 +0900738 if (direction.equalsIgnoreCase(EGRESS)) {
739 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
Jian Lif89d9602021-04-27 19:05:49 +0900740 sBuilder.matchEthSrc(vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900741 } else {
742 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
Jian Lif89d9602021-04-27 19:05:49 +0900743 sBuilder.matchEthDst(vmMac);
Jian Li8f944d42021-03-23 00:43:29 +0900744 }
745 }
746
747 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
748 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
749 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
750 if (etherType != null && !Objects.equals(etherType, STR_NULL) &&
751 !etherType.equalsIgnoreCase(ETHTYPE_IPV4)) {
752 log.debug("EthType {} is not supported yet in Security Group", etherType);
753 }
754 }
755
756 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder,
757 IpPrefix remoteIpPrefix, String direction) {
758 if (remoteIpPrefix != null &&
759 !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
760 if (direction.equalsIgnoreCase(EGRESS)) {
761 sBuilder.matchIPDst(remoteIpPrefix);
762 } else {
763 sBuilder.matchIPSrc(remoteIpPrefix);
764 }
765 }
766 }
767
768 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
769 if (protocol != null) {
770 switch (protocol.toUpperCase()) {
771 case PROTO_ICMP:
772 case PROTO_ICMP_NUM:
773 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
774 break;
775 case PROTO_TCP:
776 case PROTO_TCP_NUM:
777 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
778 break;
779 case PROTO_UDP:
780 case PROTO_UDP_NUM:
781 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
782 break;
783 case PROTO_SCTP:
784 case PROTO_SCTP_NUM:
785 sBuilder.matchIPProtocol(PROTOCOL_SCTP);
786 break;
787 default:
788 break;
789 }
790 }
791 }
792
793 private void buildMatchPort(TrafficSelector.Builder sBuilder,
794 String protocol, String direction,
795 int portMin, int portMax) {
796 if (portMax > 0 && portMin == portMax) {
797 if (protocol.equalsIgnoreCase(PROTO_TCP) ||
798 protocol.equals(PROTO_TCP_NUM)) {
799 if (direction.equalsIgnoreCase(EGRESS)) {
800 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
801 } else {
802 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
803 }
804 } else if (protocol.equalsIgnoreCase(PROTO_UDP) ||
805 protocol.equals(PROTO_UDP_NUM)) {
806 if (direction.equalsIgnoreCase(EGRESS)) {
807 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
808 } else {
809 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
810 }
811 } else if (protocol.equalsIgnoreCase(PROTO_SCTP) ||
812 protocol.equals(PROTO_SCTP_NUM)) {
813 if (direction.equalsIgnoreCase(EGRESS)) {
814 sBuilder.matchSctpSrc(TpPort.tpPort(portMax));
815 } else {
816 sBuilder.matchSctpDst(TpPort.tpPort(portMax));
817 }
818 }
819 }
820 }
821
822 private void buildMatchIcmp(TrafficSelector.Builder sBuilder,
823 String protocol, Integer icmpCode, Integer icmpType) {
824 if (protocol != null) {
825 if (protocol.equalsIgnoreCase(PROTO_ICMP) ||
826 protocol.equals(PROTO_ICMP_NUM)) {
827 if (icmpCode != null && icmpCode >= ICMP_CODE_MIN &&
828 icmpCode <= ICMP_CODE_MAX) {
829 sBuilder.matchIcmpCode(icmpCode.byteValue());
830 }
831 if (icmpType != null && icmpType >= ICMP_TYPE_MIN &&
832 icmpType <= ICMP_TYPE_MAX) {
833 sBuilder.matchIcmpType(icmpType.byteValue());
834 }
835 }
836 }
837 }
838
839 private void resetSecurityGroupRules() {
840
841 if (getUseSecurityGroupFlag()) {
842 nodeService.completeNodes(WORKER).forEach(node -> {
Jian Lif89d9602021-04-27 19:05:49 +0900843 initializeProviderPipeline(node, true);
Jian Li8f944d42021-03-23 00:43:29 +0900844
845 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +0900846 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +0900847 }
848 });
849
850 securityGroupService.securityGroups().forEach(securityGroup ->
851 securityGroup.rules().forEach(this::securityGroupRuleAdded));
852 } else {
853 nodeService.completeNodes(WORKER).forEach(node -> {
Jian Lif89d9602021-04-27 19:05:49 +0900854 initializeProviderPipeline(node, false);
Jian Li8f944d42021-03-23 00:43:29 +0900855
856 for (KubevirtNetwork network : networkService.tenantNetworks()) {
Jian Lif89d9602021-04-27 19:05:49 +0900857 initializeTenantPipeline(network, node, false);
Jian Li8f944d42021-03-23 00:43:29 +0900858 }
859 });
860
861 securityGroupService.securityGroups().forEach(securityGroup ->
862 securityGroup.rules().forEach(this::securityGroupRuleRemoved));
863 }
864
865 log.info("Reset security group info " +
866 (getUseSecurityGroupFlag() ? "with" : "without") + " Security Group");
867 }
868
869 private void securityGroupRuleAdded(KubevirtSecurityGroupRule sgRule) {
870 portService.ports().stream()
871 .filter(port -> port.securityGroups().contains(sgRule.securityGroupId()))
872 .forEach(port -> {
873 updateSecurityGroupRule(port, sgRule, true);
874 log.info("Applied security group rule {} to port {}",
875 sgRule.id(), port.macAddress());
876 });
877 }
878
879 private void securityGroupRuleRemoved(KubevirtSecurityGroupRule sgRule) {
880 portService.ports().stream()
881 .filter(port -> port.securityGroups().contains(sgRule.securityGroupId()))
882 .forEach(port -> {
883 updateSecurityGroupRule(port, sgRule, false);
884 log.info("Removed security group rule {} from port {}",
885 sgRule.id(), port.macAddress());
886 });
887 }
888
889 private class InternalKubevirtPortListener implements KubevirtPortListener {
890
891 @Override
892 public boolean isRelevant(KubevirtPortEvent event) {
893 return getUseSecurityGroupFlag();
894 }
895
896 private boolean isRelevantHelper(KubevirtPortEvent event) {
897 DeviceId deviceId = event.subject().deviceId();
898
899 if (deviceId == null) {
900 return false;
901 }
902
903 return mastershipService.isLocalMaster(deviceId);
904 }
905
906 @Override
907 public void event(KubevirtPortEvent event) {
908 log.debug("security group event received {}", event);
909
910 switch (event.type()) {
911 case KUBEVIRT_PORT_SECURITY_GROUP_ADDED:
912 eventExecutor.execute(() -> processPortSgAdd(event));
913 break;
914 case KUBEVIRT_PORT_SECURITY_GROUP_REMOVED:
915 eventExecutor.execute(() -> processPortSgRemove(event));
916 break;
917 case KUBEVIRT_PORT_REMOVED:
918 eventExecutor.execute(() -> processPortRemove(event));
919 break;
920 case KUBEVIRT_PORT_DEVICE_ADDED:
921 eventExecutor.execute(() -> processPortDeviceAdded(event));
922 break;
923 default:
924 // do nothing for the other events
925 break;
926 }
927 }
928
929 private void processPortSgAdd(KubevirtPortEvent event) {
930 if (!isRelevantHelper(event)) {
931 return;
932 }
933
934 if (event.securityGroupId() == null ||
935 securityGroupService.securityGroup(event.securityGroupId()) == null) {
936 return;
937 }
938
939 KubevirtPort port = event.subject();
940 KubevirtSecurityGroup sg = securityGroupService.securityGroup(event.securityGroupId());
941
942 sg.rules().forEach(sgRule -> {
943 updateSecurityGroupRule(port, sgRule, true);
944 });
945 log.info("Added security group {} to port {}",
946 event.securityGroupId(), event.subject().macAddress());
947 }
948
949 private void processPortSgRemove(KubevirtPortEvent event) {
950 if (!isRelevantHelper(event)) {
951 return;
952 }
953
954 if (event.securityGroupId() == null ||
955 securityGroupService.securityGroup(event.securityGroupId()) == null) {
956 return;
957 }
958
959 KubevirtPort port = event.subject();
960 KubevirtSecurityGroup sg = securityGroupService.securityGroup(event.securityGroupId());
961
962 sg.rules().forEach(sgRule -> {
963 updateSecurityGroupRule(port, sgRule, false);
964 });
965 log.info("Removed security group {} from port {}",
966 event.securityGroupId(), event.subject().macAddress());
967 }
968
969 private void processPortRemove(KubevirtPortEvent event) {
970 if (!isRelevantHelper(event)) {
971 return;
972 }
973
974 KubevirtPort port = event.subject();
975 for (String sgStr : port.securityGroups()) {
976 KubevirtSecurityGroup sg = securityGroupService.securityGroup(sgStr);
977 sg.rules().forEach(sgRule -> {
978 updateSecurityGroupRule(port, sgRule, false);
979 });
980 log.info("Removed security group {} from port {}",
981 sgStr, event.subject().macAddress());
982 }
983 }
984
985 private void processPortDeviceAdded(KubevirtPortEvent event) {
986 if (!isRelevantHelper(event)) {
987 return;
988 }
989
990 for (String sgId : event.subject().securityGroups()) {
991 KubevirtSecurityGroup sg = securityGroupService.securityGroup(sgId);
992
993 sg.rules().forEach(sgRule -> {
994 updateSecurityGroupRule(event.subject(), sgRule, true);
995 });
996 log.info("Added security group {} to port {}",
Jian Lif89d9602021-04-27 19:05:49 +0900997 sg.id(), event.subject().macAddress());
Jian Li8f944d42021-03-23 00:43:29 +0900998 }
999 }
1000 }
1001
1002 private class InternalNetworkListener implements KubevirtNetworkListener {
1003
1004 private boolean isRelevantHelper() {
1005 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1006 }
1007
1008 @Override
1009 public void event(KubevirtNetworkEvent event) {
1010 switch (event.type()) {
1011 case KUBEVIRT_NETWORK_CREATED:
1012 eventExecutor.execute(() -> processNetworkCreation(event.subject()));
1013 break;
1014 case KUBEVIRT_NETWORK_REMOVED:
1015 case KUBEVIRT_NETWORK_UPDATED:
1016 default:
1017 // do thing
1018 break;
1019 }
1020 }
1021
1022 private void processNetworkCreation(KubevirtNetwork network) {
1023 if (!isRelevantHelper()) {
1024 return;
1025 }
1026
1027 Set<KubevirtNode> nodes = nodeService.completeNodes(WORKER);
1028
1029 if (nodes.size() > 0) {
1030 // now we wait 5s for all tenant bridges are created,
1031 // FIXME: we need to fina a better way to wait all tenant bridges
1032 // are created before installing default security group rules
Jian Li0c656f02021-06-07 13:32:39 +09001033 waitFor(5);
Jian Li8f944d42021-03-23 00:43:29 +09001034
1035 for (KubevirtNode node : nodes) {
Jian Lif89d9602021-04-27 19:05:49 +09001036 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +09001037 }
1038 }
1039 }
1040 }
1041
1042 private class InternalSecurityGroupListener implements KubevirtSecurityGroupListener {
1043
1044 @Override
1045 public boolean isRelevant(KubevirtSecurityGroupEvent event) {
1046 return getUseSecurityGroupFlag();
1047 }
1048
1049 private boolean isRelevantHelper() {
1050 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1051 }
1052
1053 @Override
1054 public void event(KubevirtSecurityGroupEvent event) {
1055 switch (event.type()) {
1056 case KUBEVIRT_SECURITY_GROUP_RULE_CREATED:
1057 eventExecutor.execute(() -> processSgRuleCreate(event));
1058 break;
1059 case KUBEVIRT_SECURITY_GROUP_RULE_REMOVED:
1060 eventExecutor.execute(() -> processSgRuleRemove(event));
1061 break;
1062 default:
1063 // do nothing
1064 break;
1065 }
1066 }
1067
1068 private void processSgRuleCreate(KubevirtSecurityGroupEvent event) {
1069 if (!isRelevantHelper()) {
1070 return;
1071 }
1072
1073 KubevirtSecurityGroupRule sgRuleToAdd = event.rule();
1074 securityGroupRuleAdded(sgRuleToAdd);
1075 log.info("Applied new security group rule {} to ports", sgRuleToAdd.id());
1076 }
1077
1078 private void processSgRuleRemove(KubevirtSecurityGroupEvent event) {
1079 if (!isRelevantHelper()) {
1080 return;
1081 }
1082
1083 KubevirtSecurityGroupRule sgRuleToRemove = event.rule();
1084 securityGroupRuleRemoved(sgRuleToRemove);
1085 log.info("Removed security group rule {} from ports", sgRuleToRemove.id());
1086 }
1087 }
1088
1089 private class InternalNodeListener implements KubevirtNodeListener {
1090
1091 @Override
1092 public boolean isRelevant(KubevirtNodeEvent event) {
1093 return event.subject().type() == WORKER;
1094 }
1095
1096 private boolean isRelevantHelper() {
1097 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1098 }
1099
1100 @Override
1101 public void event(KubevirtNodeEvent event) {
1102 switch (event.type()) {
1103 case KUBEVIRT_NODE_COMPLETE:
1104 eventExecutor.execute(() -> processNodeComplete(event.subject()));
1105 break;
1106 default:
1107 break;
1108 }
1109 }
1110
1111 private void processNodeComplete(KubevirtNode node) {
1112 if (!isRelevantHelper()) {
1113 return;
1114 }
1115
Jian Lif89d9602021-04-27 19:05:49 +09001116 // FIXME: we wait all port get its deviceId updated
Jian Li0c656f02021-06-07 13:32:39 +09001117 waitFor(5);
Jian Lif89d9602021-04-27 19:05:49 +09001118
Jian Li8f944d42021-03-23 00:43:29 +09001119 resetSecurityGroupRulesByNode(node);
1120 }
Jian Lifc2d71e2022-10-17 15:34:10 +09001121 }
Jian Li8f944d42021-03-23 00:43:29 +09001122
Jian Lifc2d71e2022-10-17 15:34:10 +09001123 /**
1124 * An internal OVS listener. This listener is used for listening the network
1125 * facing events from OVS device. If a new OVS device is detected, discovered,
1126 * ONOS tries to install device related rules into the target kubernetes node.
1127 */
1128 private class InternalDeviceListener implements DeviceListener {
Jian Li8f944d42021-03-23 00:43:29 +09001129
Jian Lifc2d71e2022-10-17 15:34:10 +09001130 @Override
1131 public boolean isRelevant(DeviceEvent event) {
1132 return event.subject().type() == Device.Type.SWITCH;
1133 }
Jian Li8f944d42021-03-23 00:43:29 +09001134
Jian Lifc2d71e2022-10-17 15:34:10 +09001135 private boolean isRelevantHelper() {
1136 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1137 }
Jian Li8f944d42021-03-23 00:43:29 +09001138
Jian Lifc2d71e2022-10-17 15:34:10 +09001139 @Override
1140 public void event(DeviceEvent event) {
1141 Device device = event.subject();
Jian Li8f944d42021-03-23 00:43:29 +09001142
Jian Lifc2d71e2022-10-17 15:34:10 +09001143 switch (event.type()) {
1144 case DEVICE_AVAILABILITY_CHANGED:
1145 case DEVICE_ADDED:
1146 eventExecutor.execute(() -> {
1147 if (!isRelevantHelper()) {
1148 return;
1149 }
1150
1151 KubevirtNode node = nodeService.node(device.id());
1152
1153 if (node == null) {
1154 return;
1155 }
1156
1157 if (deviceService.isAvailable(device.id())) {
1158 resetSecurityGroupRulesByNode(node);
1159 }
1160 });
1161 break;
1162 case DEVICE_REMOVED:
1163 default:
1164 // do nothing
1165 break;
1166 }
1167 }
1168 }
1169
1170 private void resetSecurityGroupRulesByNode(KubevirtNode node) {
1171 if (getUseSecurityGroupFlag()) {
1172 initializeProviderPipeline(node, true);
1173
1174 for (KubevirtNetwork network : networkService.tenantNetworks()) {
1175 initializeTenantPipeline(network, node, true);
Jian Li8f944d42021-03-23 00:43:29 +09001176 }
1177
Jian Lifc2d71e2022-10-17 15:34:10 +09001178 securityGroupService.securityGroups().forEach(securityGroup ->
1179 securityGroup.rules().forEach(
1180 KubevirtSecurityGroupHandler.this::securityGroupRuleAdded));
1181 } else {
1182 initializeProviderPipeline(node, false);
1183
1184 for (KubevirtNetwork network : networkService.tenantNetworks()) {
1185 initializeTenantPipeline(network, node, false);
1186 }
1187
1188 securityGroupService.securityGroups().forEach(securityGroup ->
1189 securityGroup.rules().forEach(
1190 KubevirtSecurityGroupHandler.this::securityGroupRuleRemoved));
Jian Li8f944d42021-03-23 00:43:29 +09001191 }
Jian Lifc2d71e2022-10-17 15:34:10 +09001192
1193 log.info("Reset security group info " +
1194 (getUseSecurityGroupFlag() ? "with" : "without") + " Security Group");
Jian Li8f944d42021-03-23 00:43:29 +09001195 }
1196}