blob: 8e8bc83368acba9b6ecaf704719ced13d4616881 [file] [log] [blame]
sangho6a9ff0d2017-03-27 11:23:37 +09001/*
Jian Li26949762018-03-30 15:46:37 +09002 * Copyright 2017-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 */
sangho6a9ff0d2017-03-27 11:23:37 +090016
17package org.onosproject.openstacknetworking.impl;
18
19import com.google.common.base.Strings;
sangho2e97be02017-07-03 18:18:27 +090020import com.google.common.collect.Maps;
21import com.google.common.collect.Sets;
sangho6a9ff0d2017-03-27 11:23:37 +090022import org.onlab.packet.Ethernet;
23import org.onlab.packet.IPv4;
24import org.onlab.packet.Ip4Address;
25import org.onlab.packet.Ip4Prefix;
26import org.onlab.packet.IpPrefix;
27import org.onlab.packet.TpPort;
Jian Lie8b28db2018-10-17 14:04:09 +090028import org.onlab.packet.VlanId;
Jian Liac30e272018-10-18 23:08:03 +090029import org.onlab.util.KryoNamespace;
sangho0248ca22017-05-31 13:22:47 +090030import org.onlab.util.Tools;
31import org.onosproject.cfg.ComponentConfigService;
Jian Li627e0162020-03-12 17:50:36 +090032import org.onosproject.cfg.ConfigProperty;
sangho1aaa7882017-05-31 13:22:47 +090033import org.onosproject.cluster.ClusterService;
34import org.onosproject.cluster.LeadershipService;
35import org.onosproject.cluster.NodeId;
sangho6a9ff0d2017-03-27 11:23:37 +090036import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
38import org.onosproject.mastership.MastershipService;
sangho1aaa7882017-05-31 13:22:47 +090039import org.onosproject.net.DeviceId;
Jian Li857f1b02019-09-20 16:58:19 +090040import org.onosproject.net.device.DeviceService;
sangho1aaa7882017-05-31 13:22:47 +090041import org.onosproject.net.driver.DriverService;
sangho6a9ff0d2017-03-27 11:23:37 +090042import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.TrafficSelector;
sangho1aaa7882017-05-31 13:22:47 +090045import org.onosproject.net.flow.TrafficTreatment;
46import org.onosproject.net.flow.criteria.ExtensionSelector;
Jian Li28ec77f2018-10-31 07:07:25 +090047import org.onosproject.net.flow.instructions.ExtensionTreatment;
sangho6a9ff0d2017-03-27 11:23:37 +090048import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li9d35bd62018-10-13 01:43:24 +090049import org.onosproject.openstacknetworking.api.InstancePortAdminService;
sangho6a9ff0d2017-03-27 11:23:37 +090050import org.onosproject.openstacknetworking.api.InstancePortEvent;
51import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090052import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090053import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
sangho6a9ff0d2017-03-27 11:23:37 +090054import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
55import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
56import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
57import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupEvent;
58import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupListener;
59import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Jian Li26949762018-03-30 15:46:37 +090060import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Jian Li627e0162020-03-12 17:50:36 +090061import org.onosproject.openstacknode.api.OpenstackNode;
sangho1aaa7882017-05-31 13:22:47 +090062import org.onosproject.openstacknode.api.OpenstackNodeEvent;
63import org.onosproject.openstacknode.api.OpenstackNodeListener;
sangho3dd2a8b2017-07-19 15:54:31 +090064import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Liac30e272018-10-18 23:08:03 +090065import org.onosproject.store.serializers.KryoNamespaces;
66import org.onosproject.store.service.ConsistentMap;
67import org.onosproject.store.service.Serializer;
68import org.onosproject.store.service.StorageService;
Jian Li1e9cb732018-11-25 23:17:21 +090069import org.openstack4j.model.network.Network;
sangho6a9ff0d2017-03-27 11:23:37 +090070import org.openstack4j.model.network.Port;
71import org.openstack4j.model.network.SecurityGroup;
72import org.openstack4j.model.network.SecurityGroupRule;
Jian Liac30e272018-10-18 23:08:03 +090073import org.openstack4j.model.network.State;
74import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
75import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
76import org.openstack4j.openstack.networking.domain.NeutronIP;
77import org.openstack4j.openstack.networking.domain.NeutronPort;
sangho6a9ff0d2017-03-27 11:23:37 +090078import org.openstack4j.openstack.networking.domain.NeutronSecurityGroupRule;
sangho0248ca22017-05-31 13:22:47 +090079import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080import org.osgi.service.component.annotations.Activate;
81import org.osgi.service.component.annotations.Component;
82import org.osgi.service.component.annotations.Deactivate;
83import org.osgi.service.component.annotations.Modified;
84import org.osgi.service.component.annotations.Reference;
85import org.osgi.service.component.annotations.ReferenceCardinality;
sangho6a9ff0d2017-03-27 11:23:37 +090086import org.slf4j.Logger;
87
sangho6a9ff0d2017-03-27 11:23:37 +090088import java.util.Collections;
sangho0248ca22017-05-31 13:22:47 +090089import java.util.Dictionary;
Jian Liac30e272018-10-18 23:08:03 +090090import java.util.HashSet;
91import java.util.LinkedHashMap;
Jian Li362f9fd2018-11-28 11:14:40 +090092import java.util.List;
sangho2e97be02017-07-03 18:18:27 +090093import java.util.Map;
sangho6a9ff0d2017-03-27 11:23:37 +090094import java.util.Objects;
95import java.util.Set;
96import java.util.concurrent.ExecutorService;
97import java.util.stream.Collectors;
98
99import static java.util.concurrent.Executors.newSingleThreadExecutor;
100import static org.onlab.util.Tools.groupedThreads;
Jian Li1e9cb732018-11-25 23:17:21 +0900101import static org.onosproject.openstacknetworking.api.Constants.ACL_EGRESS_TABLE;
102import static org.onosproject.openstacknetworking.api.Constants.ACL_INGRESS_TABLE;
103import static org.onosproject.openstacknetworking.api.Constants.ACL_RECIRC_TABLE;
sangho1aaa7882017-05-31 13:22:47 +0900104import static org.onosproject.openstacknetworking.api.Constants.CT_TABLE;
105import static org.onosproject.openstacknetworking.api.Constants.ERROR_TABLE;
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700106import static org.onosproject.openstacknetworking.api.Constants.JUMP_TABLE;
sangho6a9ff0d2017-03-27 11:23:37 +0900107import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li1e9cb732018-11-25 23:17:21 +0900108import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_INGRESS_RULE;
sangho6a9ff0d2017-03-27 11:23:37 +0900109import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_RULE;
sangho1aaa7882017-05-31 13:22:47 +0900110import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_DROP_RULE;
111import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
112import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_RULE;
Jian Li621f73c2018-12-15 01:49:22 +0900113import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +0900114import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
115import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
116import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Jian Li4d138702018-11-27 17:25:28 +0900117import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Ray Milkey8e406512018-10-24 15:56:50 -0700118import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP;
119import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP_DEFAULT;
Jian Li0f6ef9c2020-07-08 21:37:26 +0900120import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Lib8cdcc12018-10-23 01:53:10 +0900121import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Libcc42282018-09-13 20:59:34 +0900122import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtMaskFlag;
123import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtStateFlag;
124import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
sangho1aaa7882017-05-31 13:22:47 +0900125import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
sangho6a9ff0d2017-03-27 11:23:37 +0900126import static org.slf4j.LoggerFactory.getLogger;
127
128/**
129 * Populates flow rules to handle OpenStack SecurityGroups.
130 */
Ray Milkey8e406512018-10-24 15:56:50 -0700131@Component(
132 immediate = true,
133 property = {
134 USE_SECURITY_GROUP + ":Boolean=" + USE_SECURITY_GROUP_DEFAULT
135 }
136)
sangho6a9ff0d2017-03-27 11:23:37 +0900137public class OpenstackSecurityGroupHandler {
138
139 private final Logger log = getLogger(getClass());
140
Jian Li2b9838c2018-10-28 17:09:42 +0900141 private static final int VM_IP_PREFIX = 32;
142
Jian Li4d138702018-11-27 17:25:28 +0900143 private static final String STR_ZERO = "0";
144 private static final String STR_ONE = "1";
145 private static final String STR_NULL = "null";
146 private static final String STR_PADDING = "0000000000000000";
147 private static final int MASK_BEGIN_IDX = 0;
148 private static final int MASK_MAX_IDX = 16;
149 private static final int MASK_RADIX = 2;
150 private static final int PORT_RADIX = 16;
151
Jian Li900b7232018-12-14 14:04:51 +0900152 /** Apply OpenStack security group rule for VM traffic. */
Ray Milkey8e406512018-10-24 15:56:50 -0700153 private boolean useSecurityGroup = USE_SECURITY_GROUP_DEFAULT;
sangho0248ca22017-05-31 13:22:47 +0900154
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900156 protected CoreService coreService;
157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d35bd62018-10-13 01:43:24 +0900159 protected InstancePortAdminService instancePortService;
sangho6a9ff0d2017-03-27 11:23:37 +0900160
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900162 protected MastershipService mastershipService;
163
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moonae51e732017-04-25 17:46:21 +0900165 protected OpenstackNetworkService osNetService;
sangho6a9ff0d2017-03-27 11:23:37 +0900166
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900168 protected OpenstackSecurityGroupService securityGroupService;
169
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900171 protected OpenstackFlowRuleService osFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +0900172
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700173 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho0248ca22017-05-31 13:22:47 +0900174 protected ComponentConfigService configService;
175
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700176 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho3dd2a8b2017-07-19 15:54:31 +0900177 protected OpenstackNodeService osNodeService;
178
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700179 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900180 protected DriverService driverService;
181
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700182 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li857f1b02019-09-20 16:58:19 +0900183 protected DeviceService deviceService;
184
185 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900186 protected LeadershipService leadershipService;
187
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700188 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900189 protected ClusterService clusterService;
190
Ray Milkey0b18b722018-10-16 13:19:15 -0700191 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liac30e272018-10-18 23:08:03 +0900192 protected StorageService storageService;
193
194 private static final KryoNamespace SERIALIZER_PORT = KryoNamespace.newBuilder()
195 .register(KryoNamespaces.API)
196 .register(Port.class)
197 .register(NeutronPort.class)
198 .register(NeutronIP.class)
199 .register(State.class)
200 .register(NeutronAllowedAddressPair.class)
201 .register(NeutronExtraDhcpOptCreate.class)
202 .register(LinkedHashMap.class)
203 .build();
Jian Li9d35bd62018-10-13 01:43:24 +0900204
Jian Libcc42282018-09-13 20:59:34 +0900205 private final InstancePortListener instancePortListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900206 new InternalInstancePortListener();
Jian Libcc42282018-09-13 20:59:34 +0900207 private final OpenstackNetworkListener osNetworkListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900208 new InternalOpenstackNetworkListener();
Jian Libcc42282018-09-13 20:59:34 +0900209 private final OpenstackNetworkListener osPortListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900210 new InternalOpenstackPortListener();
Jian Libcc42282018-09-13 20:59:34 +0900211 private final OpenstackSecurityGroupListener securityGroupListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900212 new InternalSecurityGroupListener();
sangho1aaa7882017-05-31 13:22:47 +0900213 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Liac30e272018-10-18 23:08:03 +0900214
215 private ConsistentMap<String, Port> removedOsPortStore;
216
sangho6a9ff0d2017-03-27 11:23:37 +0900217 private ApplicationId appId;
sangho1aaa7882017-05-31 13:22:47 +0900218 private NodeId localNodeId;
sangho6a9ff0d2017-03-27 11:23:37 +0900219
220 private final ExecutorService eventExecutor = newSingleThreadExecutor(
221 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
222
223 private static final String PROTO_ICMP = "ICMP";
Jian Li0f6ef9c2020-07-08 21:37:26 +0900224 private static final String PROTO_ICMP_NUM = "1";
sangho6a9ff0d2017-03-27 11:23:37 +0900225 private static final String PROTO_TCP = "TCP";
Jian Li0f6ef9c2020-07-08 21:37:26 +0900226 private static final String PROTO_TCP_NUM = "6";
sangho6a9ff0d2017-03-27 11:23:37 +0900227 private static final String PROTO_UDP = "UDP";
Jian Li0f6ef9c2020-07-08 21:37:26 +0900228 private static final String PROTO_UDP_NUM = "17";
229 private static final String PROTO_SCTP = "SCTP";
230 private static final String PROTO_SCTP_NUM = "132";
231 private static final byte PROTOCOL_SCTP = (byte) 0x84;
232 private static final String PROTO_ANY = "ANY";
233 private static final String PROTO_ANY_NUM = "0";
sangho6a9ff0d2017-03-27 11:23:37 +0900234 private static final String ETHTYPE_IPV4 = "IPV4";
235 private static final String EGRESS = "EGRESS";
236 private static final String INGRESS = "INGRESS";
237 private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
238
sangho1aaa7882017-05-31 13:22:47 +0900239 // We expose pipeline structure to SONA application considering removing pipeline soon.
sanghoshinbbeb31a2018-09-11 17:01:01 +0800240 private static final int GOTO_CONNTRACK_TABLE = CT_TABLE;
241 private static final int GOTO_JUMP_TABLE = JUMP_TABLE;
sangho1aaa7882017-05-31 13:22:47 +0900242
243 private static final int CT_COMMIT = 0;
244 private static final int CT_NO_COMMIT = 1;
245 private static final short CT_NO_RECIRC = -1;
246
247 private static final int ACTION_NONE = 0;
248 private static final int ACTION_DROP = -1;
249
sangho6a9ff0d2017-03-27 11:23:37 +0900250 @Activate
251 protected void activate() {
252 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
sangho1aaa7882017-05-31 13:22:47 +0900253 localNodeId = clusterService.getLocalNode().id();
sangho6a9ff0d2017-03-27 11:23:37 +0900254 instancePortService.addListener(instancePortListener);
255 securityGroupService.addListener(securityGroupListener);
Jian Libcc42282018-09-13 20:59:34 +0900256 osNetService.addListener(osPortListener);
257 osNetService.addListener(osNetworkListener);
sangho0248ca22017-05-31 13:22:47 +0900258 configService.registerProperties(getClass());
sangho1aaa7882017-05-31 13:22:47 +0900259 osNodeService.addListener(osNodeListener);
sangho6a9ff0d2017-03-27 11:23:37 +0900260
Jian Liac30e272018-10-18 23:08:03 +0900261 removedOsPortStore = storageService.<String, Port>consistentMapBuilder()
262 .withSerializer(Serializer.using(SERIALIZER_PORT))
263 .withName("openstack-removed-portstore")
264 .withApplicationId(appId)
265 .build();
266
sangho6a9ff0d2017-03-27 11:23:37 +0900267 log.info("Started");
268 }
269
270 @Deactivate
271 protected void deactivate() {
272 instancePortService.removeListener(instancePortListener);
273 securityGroupService.removeListener(securityGroupListener);
Jian Libcc42282018-09-13 20:59:34 +0900274 osNetService.removeListener(osNetworkListener);
275 osNetService.removeListener(osPortListener);
sangho0248ca22017-05-31 13:22:47 +0900276 configService.unregisterProperties(getClass(), false);
sangho1aaa7882017-05-31 13:22:47 +0900277 osNodeService.removeListener(osNodeListener);
sangho6a9ff0d2017-03-27 11:23:37 +0900278 eventExecutor.shutdown();
279
280 log.info("Stopped");
281 }
282
sangho0248ca22017-05-31 13:22:47 +0900283 @Modified
284 protected void modified(ComponentContext context) {
285 Dictionary<?, ?> properties = context.getProperties();
286 Boolean flag;
287
Ray Milkey8e406512018-10-24 15:56:50 -0700288 flag = Tools.isPropertyEnabled(properties, USE_SECURITY_GROUP);
sangho0248ca22017-05-31 13:22:47 +0900289 if (flag == null) {
290 log.info("useSecurityGroup is not configured, " +
291 "using current value of {}", useSecurityGroup);
292 } else {
293 useSecurityGroup = flag;
294 log.info("Configured. useSecurityGroup is {}",
295 useSecurityGroup ? "enabled" : "disabled");
296 }
297
sanghoe6457a32017-08-24 14:31:19 +0900298 securityGroupService.setSecurityGroupEnabled(useSecurityGroup);
sangho0248ca22017-05-31 13:22:47 +0900299 resetSecurityGroupRules();
300 }
301
Jian Li627e0162020-03-12 17:50:36 +0900302 private boolean getUseSecurityGroupFlag() {
303 Set<ConfigProperty> properties =
304 configService.getProperties(getClass().getName());
305 return getPropertyValueAsBoolean(properties, USE_SECURITY_GROUP);
306 }
307
sangho1aaa7882017-05-31 13:22:47 +0900308 private void initializeConnTrackTable(DeviceId deviceId, boolean install) {
309
310 //table=1,ip,ct_state=-trk, actions=ct(table:2)
Jian Libcc42282018-09-13 20:59:34 +0900311 long ctState = computeCtStateFlag(false, false, false);
312 long ctMask = computeCtMaskFlag(true, false, false);
sangho1aaa7882017-05-31 13:22:47 +0900313 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) GOTO_CONNTRACK_TABLE,
314 ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
315
316 //table=2,ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:3
Jian Libcc42282018-09-13 20:59:34 +0900317 ctState = computeCtStateFlag(true, false, true);
318 ctMask = computeCtMaskFlag(true, false, true);
sangho1aaa7882017-05-31 13:22:47 +0900319 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
320 GOTO_JUMP_TABLE, PRIORITY_CT_RULE, install);
321
322 //table=2,ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
Jian Libcc42282018-09-13 20:59:34 +0900323 ctState = computeCtStateFlag(true, true, false);
324 ctMask = computeCtMaskFlag(true, true, false);
sangho1aaa7882017-05-31 13:22:47 +0900325 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
326 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
327 }
328
Jian Li1e9cb732018-11-25 23:17:21 +0900329 private void initializeAclTable(DeviceId deviceId, boolean install) {
330
331 ExtensionTreatment ctTreatment =
332 niciraConnTrackTreatmentBuilder(driverService, deviceId)
333 .commit(true)
334 .build();
335
336 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
337 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
338
339 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
340 tBuilder.extension(ctTreatment, deviceId)
341 .transition(JUMP_TABLE);
342
343 osFlowRuleService.setRule(appId,
344 deviceId,
345 sBuilder.build(),
346 tBuilder.build(),
347 PRIORITY_ACL_INGRESS_RULE,
348 ACL_RECIRC_TABLE,
349 install);
350 }
351
352 private void initializeIngressTable(DeviceId deviceId, boolean install) {
353 if (install) {
354 osFlowRuleService.setUpTableMissEntry(deviceId, ACL_INGRESS_TABLE);
355 } else {
356 osFlowRuleService.connectTables(deviceId, ACL_INGRESS_TABLE, JUMP_TABLE);
357 }
358 }
359
Jian Libcc42282018-09-13 20:59:34 +0900360 private void updateSecurityGroupRule(InstancePort instPort, Port port,
361 SecurityGroupRule sgRule, boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900362
Daniel Park3a140592018-06-28 18:33:10 +0900363 if (instPort == null || port == null || sgRule == null) {
364 return;
365 }
366
sangho6a9ff0d2017-03-27 11:23:37 +0900367 if (sgRule.getRemoteGroupId() != null && !sgRule.getRemoteGroupId().isEmpty()) {
Jian Lia70fdb602018-11-05 01:32:22 +0900368 getRemoteInstPorts(port, sgRule.getRemoteGroupId(), install)
Jian Libcc42282018-09-13 20:59:34 +0900369 .forEach(rInstPort -> {
Jian Li1e9cb732018-11-25 23:17:21 +0900370 populateSecurityGroupRule(sgRule, instPort,
Jian Libcc42282018-09-13 20:59:34 +0900371 rInstPort.ipAddress().toIpPrefix(), install);
Jian Li1e9cb732018-11-25 23:17:21 +0900372 populateSecurityGroupRule(sgRule, rInstPort,
Jian Libcc42282018-09-13 20:59:34 +0900373 instPort.ipAddress().toIpPrefix(), install);
sangho6a9ff0d2017-03-27 11:23:37 +0900374
Jian Libcc42282018-09-13 20:59:34 +0900375 SecurityGroupRule rSgRule =
376 new NeutronSecurityGroupRule
377 .SecurityGroupRuleConcreteBuilder()
Jian Li28ec77f2018-10-31 07:07:25 +0900378 .from(sgRule)
Jian Li4d138702018-11-27 17:25:28 +0900379 .direction(sgRule.getDirection()
380 .equalsIgnoreCase(EGRESS) ? INGRESS : EGRESS)
Jian Li28ec77f2018-10-31 07:07:25 +0900381 .build();
Jian Li1e9cb732018-11-25 23:17:21 +0900382 populateSecurityGroupRule(rSgRule, instPort,
Jian Libcc42282018-09-13 20:59:34 +0900383 rInstPort.ipAddress().toIpPrefix(), install);
Jian Li1e9cb732018-11-25 23:17:21 +0900384 populateSecurityGroupRule(rSgRule, rInstPort,
Jian Libcc42282018-09-13 20:59:34 +0900385 instPort.ipAddress().toIpPrefix(), install);
386 });
sangho6a9ff0d2017-03-27 11:23:37 +0900387 } else {
Jian Li1e9cb732018-11-25 23:17:21 +0900388 populateSecurityGroupRule(sgRule, instPort,
Jian Libcc42282018-09-13 20:59:34 +0900389 sgRule.getRemoteIpPrefix() == null ? IP_PREFIX_ANY :
Jian Li28ec77f2018-10-31 07:07:25 +0900390 IpPrefix.valueOf(sgRule.getRemoteIpPrefix()), install);
sangho6a9ff0d2017-03-27 11:23:37 +0900391 }
392 }
393
Jian Li0f6ef9c2020-07-08 21:37:26 +0900394 private boolean checkProtocol(String protocol) {
395 if (protocol == null) {
396 log.debug("No protocol was specified, use default IP(v4/v6) protocol.");
397 return true;
398 } else {
399 String protocolUpper = protocol.toUpperCase();
400 if (protocolUpper.equals(PROTO_TCP) ||
401 protocolUpper.equals(PROTO_UDP) ||
402 protocolUpper.equals(PROTO_ICMP) ||
403 protocolUpper.equals(PROTO_SCTP) ||
404 protocolUpper.equals(PROTO_ANY) ||
405 protocol.equals(PROTO_TCP_NUM) ||
406 protocol.equals(PROTO_UDP_NUM) ||
407 protocol.equals(PROTO_ICMP_NUM) ||
408 protocol.equals(PROTO_SCTP_NUM) ||
409 protocol.equals(PROTO_ANY_NUM)) {
410 return true;
411 } else {
412 log.error("Unsupported protocol {}, we only support " +
413 "TCP/UDP/ICMP/SCTP protocols.", protocol);
414 return false;
415 }
416 }
417 }
418
Jian Libcc42282018-09-13 20:59:34 +0900419 private void populateSecurityGroupRule(SecurityGroupRule sgRule,
420 InstancePort instPort,
Jian Lie8b28db2018-10-17 14:04:09 +0900421 IpPrefix remoteIp,
422 boolean install) {
Jian Li0f6ef9c2020-07-08 21:37:26 +0900423 if (!checkProtocol(sgRule.getProtocol())) {
424 return;
425 }
426
sangho2e97be02017-07-03 18:18:27 +0900427 Set<TrafficSelector> selectors = buildSelectors(sgRule,
Jian Li1e9cb732018-11-25 23:17:21 +0900428 Ip4Address.valueOf(instPort.ipAddress().toInetAddress()),
429 remoteIp, instPort.networkId());
sangho2e97be02017-07-03 18:18:27 +0900430 if (selectors == null || selectors.isEmpty()) {
sangho6a9ff0d2017-03-27 11:23:37 +0900431 return;
432 }
433
Jian Li857f1b02019-09-20 16:58:19 +0900434 // if the device is not available we do not perform any action
435 if (instPort.deviceId() == null || !deviceService.isAvailable(instPort.deviceId())) {
436 return;
437 }
438
Jian Li362f9fd2018-11-28 11:14:40 +0900439 // in case a port is bound to multiple security groups, we do NOT remove
440 // egress rules unless all security groups bound to the port to be removed
441 Port osPort = osNetService.port(instPort.portId());
442 if (!install && osPort != null && sgRule.getDirection().equalsIgnoreCase(EGRESS)) {
443 List<String> sgIds = osPort.getSecurityGroups();
444 if (!sgIds.contains(sgRule.getSecurityGroupId()) && !sgIds.isEmpty()) {
445 return;
446 }
447 }
448
Jian Li28ec77f2018-10-31 07:07:25 +0900449 // XXX All egress traffic needs to go through connection tracking module,
450 // which might hurt its performance.
451 ExtensionTreatment ctTreatment =
452 niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
453 .commit(true)
454 .build();
455
Jian Li1e9cb732018-11-25 23:17:21 +0900456 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li28ec77f2018-10-31 07:07:25 +0900457
Jian Li1e9cb732018-11-25 23:17:21 +0900458 int aclTable;
Jian Li4d138702018-11-27 17:25:28 +0900459 if (sgRule.getDirection().equalsIgnoreCase(EGRESS)) {
Jian Li1e9cb732018-11-25 23:17:21 +0900460 aclTable = ACL_EGRESS_TABLE;
461 tBuilder.transition(ACL_RECIRC_TABLE);
462 } else {
463 aclTable = ACL_INGRESS_TABLE;
464 tBuilder.extension(ctTreatment, instPort.deviceId())
465 .transition(JUMP_TABLE);
466 }
467
468 int finalAclTable = aclTable;
469 selectors.forEach(selector -> {
470 osFlowRuleService.setRule(appId,
471 instPort.deviceId(),
472 selector, tBuilder.build(),
473 PRIORITY_ACL_RULE,
474 finalAclTable,
475 install);
476 });
sangho6a9ff0d2017-03-27 11:23:37 +0900477 }
478
479 /**
sangho1aaa7882017-05-31 13:22:47 +0900480 * Sets connection tracking rule using OVS extension commands.
Jian Li2b9838c2018-10-28 17:09:42 +0900481 * It is not so graceful, but I don't want to make it more general because
482 * it is going to be used only here.
483 * The following is the usage of the function.
sangho1aaa7882017-05-31 13:22:47 +0900484 *
485 * @param deviceId Device ID
Jian Li2b9838c2018-10-28 17:09:42 +0900486 * @param ctState ctState: please use RulePopulatorUtil.computeCtStateFlag()
487 * to build the value
488 * @param ctMask crMask: please use RulePopulatorUtil.computeCtMaskFlag()
489 * to build the value
sangho1aaa7882017-05-31 13:22:47 +0900490 * @param commit CT_COMMIT for commit action, CT_NO_COMMIT otherwise
Jian Li2b9838c2018-10-28 17:09:42 +0900491 * @param recircTable table number for recirculation after CT actions.
492 * CT_NO_RECIRC with no recirculation
493 * @param action Additional actions. ACTION_DROP, ACTION_NONE,
494 * GOTO_XXX_TABLE are supported.
sangho1aaa7882017-05-31 13:22:47 +0900495 * @param priority priority value for the rule
496 * @param install true for insertion, false for removal
497 */
498 private void setConnTrackRule(DeviceId deviceId, long ctState, long ctMask,
499 int commit, short recircTable,
500 int action, int priority, boolean install) {
501
Jian Libcc42282018-09-13 20:59:34 +0900502 ExtensionSelector esCtSate = RulePopulatorUtil
503 .buildCtExtensionSelector(driverService, deviceId, ctState, ctMask);
sangho1aaa7882017-05-31 13:22:47 +0900504 TrafficSelector selector = DefaultTrafficSelector.builder()
505 .extension(esCtSate, deviceId)
506 .matchEthType(Ethernet.TYPE_IPV4)
507 .build();
508
509 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
510
511 if (commit == CT_COMMIT || recircTable > 0) {
Jian Li5a26ab32019-03-21 15:20:01 +0900512 RulePopulatorUtil.NiciraConnTrackTreatmentBuilder natTreatmentBuilder =
Jian Libcc42282018-09-13 20:59:34 +0900513 niciraConnTrackTreatmentBuilder(driverService, deviceId);
sangho1aaa7882017-05-31 13:22:47 +0900514 natTreatmentBuilder.natAction(false);
515 if (commit == CT_COMMIT) {
516 natTreatmentBuilder.commit(true);
517 } else {
518 natTreatmentBuilder.commit(false);
519 }
520 if (recircTable > 0) {
521 natTreatmentBuilder.table(recircTable);
522 }
523 tb.extension(natTreatmentBuilder.build(), deviceId);
524 } else if (action == ACTION_DROP) {
525 tb.drop();
526 }
527
sanghoshinbbeb31a2018-09-11 17:01:01 +0800528 if (action != ACTION_NONE && action != ACTION_DROP) {
sangho1aaa7882017-05-31 13:22:47 +0900529 tb.transition(action);
530 }
531
532 int tableType = ERROR_TABLE;
533 if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
534 tableType = CT_TABLE;
535 } else if (priority == PRIORITY_CT_HOOK_RULE) {
Jian Li1e9cb732018-11-25 23:17:21 +0900536 tableType = ACL_INGRESS_TABLE;
sangho1aaa7882017-05-31 13:22:47 +0900537 } else {
538 log.error("Cannot an appropriate table for the conn track rule.");
539 }
540
541 osFlowRuleService.setRule(
542 appId,
543 deviceId,
544 selector,
545 tb.build(),
546 priority,
547 tableType,
548 install);
549 }
550
551 /**
sangho6a9ff0d2017-03-27 11:23:37 +0900552 * Returns a set of host IP addresses engaged with supplied security group ID.
553 * It only searches a VM in the same tenant boundary.
554 *
Jian Lia70fdb602018-11-05 01:32:22 +0900555 * @param srcPort openstack port
sangho6a9ff0d2017-03-27 11:23:37 +0900556 * @param sgId security group id
557 * @return set of ip addresses
558 */
Jian Lia70fdb602018-11-05 01:32:22 +0900559 private Set<InstancePort> getRemoteInstPorts(Port srcPort,
Jian Li2b9838c2018-10-28 17:09:42 +0900560 String sgId, boolean install) {
sangho6a9ff0d2017-03-27 11:23:37 +0900561 Set<InstancePort> remoteInstPorts;
562
Jian Liac30e272018-10-18 23:08:03 +0900563 Set<Port> removedPorts = Sets.newConcurrentHashSet();
564
565 if (!install) {
566 removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
567 }
568
569 remoteInstPorts = Sets.union(osNetService.ports(), removedPorts).stream()
Jian Lia70fdb602018-11-05 01:32:22 +0900570 .filter(port -> !port.getId().equals(srcPort.getId()))
571 .filter(port -> port.getTenantId().equals(srcPort.getTenantId()))
sangho6a9ff0d2017-03-27 11:23:37 +0900572 .filter(port -> port.getSecurityGroups().contains(sgId))
Jian Lia70fdb602018-11-05 01:32:22 +0900573 .filter(port -> port.getNetworkId().equals(srcPort.getNetworkId()))
sangho6a9ff0d2017-03-27 11:23:37 +0900574 .map(port -> instancePortService.instancePort(port.getId()))
575 .filter(instPort -> instPort != null && instPort.ipAddress() != null)
576 .collect(Collectors.toSet());
577
578 return Collections.unmodifiableSet(remoteInstPorts);
579 }
580
sangho2e97be02017-07-03 18:18:27 +0900581 private Set<TrafficSelector> buildSelectors(SecurityGroupRule sgRule,
582 Ip4Address vmIp,
Jian Lie8b28db2018-10-17 14:04:09 +0900583 IpPrefix remoteIp,
Jian Li1e9cb732018-11-25 23:17:21 +0900584 String netId) {
Jian Li2b9838c2018-10-28 17:09:42 +0900585 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
sangho2e97be02017-07-03 18:18:27 +0900586 // do nothing if the remote IP is my IP
587 return null;
588 }
589
590 Set<TrafficSelector> selectorSet = Sets.newHashSet();
591
sangho2e97be02017-07-03 18:18:27 +0900592 if (sgRule.getPortRangeMax() != null && sgRule.getPortRangeMin() != null &&
593 sgRule.getPortRangeMin() < sgRule.getPortRangeMax()) {
Jian Libcc42282018-09-13 20:59:34 +0900594 Map<TpPort, TpPort> portRangeMatchMap =
595 buildPortRangeMatches(sgRule.getPortRangeMin(),
Jian Li28ec77f2018-10-31 07:07:25 +0900596 sgRule.getPortRangeMax());
Jian Li2b9838c2018-10-28 17:09:42 +0900597 portRangeMatchMap.forEach((key, value) -> {
sangho2e97be02017-07-03 18:18:27 +0900598
Jian Li22ce4672020-05-26 00:31:27 +0900599 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
600 buildMatches(sBuilder, sgRule, vmIp, remoteIp, netId);
601
Jian Li0f6ef9c2020-07-08 21:37:26 +0900602 if (sgRule.getProtocol().equalsIgnoreCase(PROTO_TCP) ||
603 sgRule.getProtocol().equals(PROTO_TCP_NUM)) {
Jian Li4d138702018-11-27 17:25:28 +0900604 if (sgRule.getDirection().equalsIgnoreCase(EGRESS)) {
Jian Li22ce4672020-05-26 00:31:27 +0900605 if (value.toInt() == TpPort.MAX_PORT) {
606 sBuilder.matchTcpSrc(key);
607 } else {
608 sBuilder.matchTcpSrcMasked(key, value);
609 }
Jian Li2b9838c2018-10-28 17:09:42 +0900610 } else {
Jian Li22ce4672020-05-26 00:31:27 +0900611 if (value.toInt() == TpPort.MAX_PORT) {
612 sBuilder.matchTcpDst(key);
613 } else {
614 sBuilder.matchTcpDstMasked(key, value);
615 }
Jian Libcc42282018-09-13 20:59:34 +0900616 }
Jian Li0f6ef9c2020-07-08 21:37:26 +0900617 } else if (sgRule.getProtocol().equalsIgnoreCase(PROTO_UDP) ||
618 sgRule.getProtocol().equals(PROTO_UDP_NUM)) {
Jian Li4d138702018-11-27 17:25:28 +0900619 if (sgRule.getDirection().equalsIgnoreCase(EGRESS)) {
Jian Li22ce4672020-05-26 00:31:27 +0900620 if (value.toInt() == TpPort.MAX_PORT) {
621 sBuilder.matchUdpSrc(key);
622 } else {
623 sBuilder.matchUdpSrcMasked(key, value);
624 }
Jian Li2b9838c2018-10-28 17:09:42 +0900625 } else {
Jian Li22ce4672020-05-26 00:31:27 +0900626 if (value.toInt() == TpPort.MAX_PORT) {
627 sBuilder.matchUdpDst(key);
628 } else {
629 sBuilder.matchUdpDstMasked(key, value);
630 }
Jian Li2b9838c2018-10-28 17:09:42 +0900631 }
Jian Li0f6ef9c2020-07-08 21:37:26 +0900632 } else if (sgRule.getProtocol().equalsIgnoreCase(PROTO_SCTP) ||
633 sgRule.getProtocol().equals(PROTO_SCTP_NUM)) {
634 if (sgRule.getDirection().equalsIgnoreCase(EGRESS)) {
635 if (value.toInt() == TpPort.MAX_PORT) {
636 sBuilder.matchSctpSrc(key);
637 } else {
638 sBuilder.matchSctpSrcMasked(key, value);
639 }
640 } else {
641 if (value.toInt() == TpPort.MAX_PORT) {
642 sBuilder.matchSctpDst(key);
643 } else {
644 sBuilder.matchSctpDstMasked(key, value);
645 }
646 }
Jian Li2b9838c2018-10-28 17:09:42 +0900647 }
648
649 selectorSet.add(sBuilder.build());
650 });
sangho2e97be02017-07-03 18:18:27 +0900651 } else {
Jian Li22ce4672020-05-26 00:31:27 +0900652
653 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
654 buildMatches(sBuilder, sgRule, vmIp, remoteIp, netId);
655
sangho2e97be02017-07-03 18:18:27 +0900656 selectorSet.add(sBuilder.build());
657 }
658
659 return selectorSet;
660 }
661
Jian Libcc42282018-09-13 20:59:34 +0900662 private void buildMatches(TrafficSelector.Builder sBuilder,
Jian Li1e9cb732018-11-25 23:17:21 +0900663 SecurityGroupRule sgRule, Ip4Address vmIp,
664 IpPrefix remoteIp, String netId) {
665 buildTunnelId(sBuilder, netId);
sangho6a9ff0d2017-03-27 11:23:37 +0900666 buildMatchEthType(sBuilder, sgRule.getEtherType());
667 buildMatchDirection(sBuilder, sgRule.getDirection(), vmIp);
668 buildMatchProto(sBuilder, sgRule.getProtocol());
669 buildMatchPort(sBuilder, sgRule.getProtocol(), sgRule.getDirection(),
sangho2e97be02017-07-03 18:18:27 +0900670 sgRule.getPortRangeMin() == null ? 0 : sgRule.getPortRangeMin(),
671 sgRule.getPortRangeMax() == null ? 0 : sgRule.getPortRangeMax());
Jian Li0f6ef9c2020-07-08 21:37:26 +0900672 buildMatchIcmp(sBuilder, sgRule.getProtocol(),
673 sgRule.getPortRangeMin(), sgRule.getPortRangeMax());
sangho6a9ff0d2017-03-27 11:23:37 +0900674 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
sangho6a9ff0d2017-03-27 11:23:37 +0900675 }
676
Jian Li1e9cb732018-11-25 23:17:21 +0900677 private void buildTunnelId(TrafficSelector.Builder sBuilder, String netId) {
678 String segId = osNetService.segmentId(netId);
SONA Project6bc5c4a2018-12-14 23:49:52 +0900679 Type netType = osNetService.networkType(netId);
Jian Lie8b28db2018-10-17 14:04:09 +0900680
SONA Project6bc5c4a2018-12-14 23:49:52 +0900681 if (netType == VLAN) {
Jian Lie8b28db2018-10-17 14:04:09 +0900682 sBuilder.matchVlanId(VlanId.vlanId(segId));
Jian Li621f73c2018-12-15 01:49:22 +0900683 } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
Jian Lie8b28db2018-10-17 14:04:09 +0900684 sBuilder.matchTunnelId(Long.valueOf(segId));
Jian Li28ec77f2018-10-31 07:07:25 +0900685 } else {
Jian Li2dc37592019-03-14 17:32:15 +0900686 log.debug("Cannot tag the VID due to lack of support of virtual network type {}", netType);
Jian Lie8b28db2018-10-17 14:04:09 +0900687 }
688 }
689
sangho6a9ff0d2017-03-27 11:23:37 +0900690 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
691 String direction,
692 Ip4Address vmIp) {
Jian Li4d138702018-11-27 17:25:28 +0900693 if (direction.equalsIgnoreCase(EGRESS)) {
Jian Li2b9838c2018-10-28 17:09:42 +0900694 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
sangho6a9ff0d2017-03-27 11:23:37 +0900695 } else {
Jian Li2b9838c2018-10-28 17:09:42 +0900696 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
sangho6a9ff0d2017-03-27 11:23:37 +0900697 }
698 }
699
700 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
701 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
702 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
Jian Li4d138702018-11-27 17:25:28 +0900703 if (etherType != null && !Objects.equals(etherType, STR_NULL) &&
704 !etherType.equalsIgnoreCase(ETHTYPE_IPV4)) {
sangho6a9ff0d2017-03-27 11:23:37 +0900705 log.debug("EthType {} is not supported yet in Security Group", etherType);
706 }
707 }
708
Jian Libcc42282018-09-13 20:59:34 +0900709 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder,
710 IpPrefix remoteIpPrefix, String direction) {
711 if (remoteIpPrefix != null &&
712 !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
Jian Li4d138702018-11-27 17:25:28 +0900713 if (direction.equalsIgnoreCase(EGRESS)) {
sangho6a9ff0d2017-03-27 11:23:37 +0900714 sBuilder.matchIPDst(remoteIpPrefix);
715 } else {
716 sBuilder.matchIPSrc(remoteIpPrefix);
717 }
718 }
719 }
720
721 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
722 if (protocol != null) {
723 switch (protocol.toUpperCase()) {
724 case PROTO_ICMP:
Jian Li0f6ef9c2020-07-08 21:37:26 +0900725 case PROTO_ICMP_NUM:
sangho6a9ff0d2017-03-27 11:23:37 +0900726 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
727 break;
728 case PROTO_TCP:
Jian Li0f6ef9c2020-07-08 21:37:26 +0900729 case PROTO_TCP_NUM:
sangho6a9ff0d2017-03-27 11:23:37 +0900730 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
731 break;
732 case PROTO_UDP:
Jian Li0f6ef9c2020-07-08 21:37:26 +0900733 case PROTO_UDP_NUM:
sangho6a9ff0d2017-03-27 11:23:37 +0900734 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
735 break;
Jian Li0f6ef9c2020-07-08 21:37:26 +0900736 case PROTO_SCTP:
737 case PROTO_SCTP_NUM:
738 sBuilder.matchIPProtocol(PROTOCOL_SCTP);
739 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900740 default:
Jian Li0f6ef9c2020-07-08 21:37:26 +0900741 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900742 }
743 }
744 }
745
Jian Libcc42282018-09-13 20:59:34 +0900746 private void buildMatchPort(TrafficSelector.Builder sBuilder,
747 String protocol, String direction,
sangho6a9ff0d2017-03-27 11:23:37 +0900748 int portMin, int portMax) {
Jian Li0f6ef9c2020-07-08 21:37:26 +0900749 if (portMax > 0 && portMin == portMax) {
750 if (protocol.equalsIgnoreCase(PROTO_TCP) ||
751 protocol.equals(PROTO_TCP_NUM)) {
Jian Li4d138702018-11-27 17:25:28 +0900752 if (direction.equalsIgnoreCase(EGRESS)) {
sangho6a9ff0d2017-03-27 11:23:37 +0900753 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
754 } else {
755 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
756 }
Jian Li0f6ef9c2020-07-08 21:37:26 +0900757 } else if (protocol.equalsIgnoreCase(PROTO_UDP) ||
758 protocol.equals(PROTO_UDP_NUM)) {
Jian Li4d138702018-11-27 17:25:28 +0900759 if (direction.equalsIgnoreCase(EGRESS)) {
sangho6a9ff0d2017-03-27 11:23:37 +0900760 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
761 } else {
762 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
763 }
Jian Li0f6ef9c2020-07-08 21:37:26 +0900764 } else if (protocol.equalsIgnoreCase(PROTO_SCTP) ||
765 protocol.equals(PROTO_SCTP_NUM)) {
766 if (direction.equalsIgnoreCase(EGRESS)) {
767 sBuilder.matchSctpSrc(TpPort.tpPort(portMax));
768 } else {
769 sBuilder.matchSctpDst(TpPort.tpPort(portMax));
770 }
771 }
772 }
773
774
775 }
776
777 private void buildMatchIcmp(TrafficSelector.Builder sBuilder,
778 String protocol, Integer icmpCode, Integer icmpType) {
779 if (protocol != null) {
780 if (protocol.equalsIgnoreCase(PROTO_ICMP) ||
781 protocol.equals(PROTO_ICMP_NUM)) {
782 if (icmpCode != null && icmpCode >= 0 && icmpCode <= 255) {
783 sBuilder.matchIcmpCode(icmpCode.byteValue());
784 }
785 if (icmpType != null && icmpType >= 0 && icmpType <= 255) {
786 sBuilder.matchIcmpType(icmpType.byteValue());
787 }
sangho6a9ff0d2017-03-27 11:23:37 +0900788 }
789 }
790 }
791
sangho0248ca22017-05-31 13:22:47 +0900792 private void resetSecurityGroupRules() {
793
Jian Li627e0162020-03-12 17:50:36 +0900794 if (getUseSecurityGroupFlag()) {
Jian Lib6969502018-10-30 20:38:07 +0900795 osNodeService.completeNodes(COMPUTE).forEach(node -> {
Jian Li1e9cb732018-11-25 23:17:21 +0900796 osFlowRuleService.setUpTableMissEntry(node.intgBridge(), ACL_EGRESS_TABLE);
Jian Lib6969502018-10-30 20:38:07 +0900797 initializeConnTrackTable(node.intgBridge(), true);
Jian Li1e9cb732018-11-25 23:17:21 +0900798 initializeAclTable(node.intgBridge(), true);
799 initializeIngressTable(node.intgBridge(), true);
Jian Lib6969502018-10-30 20:38:07 +0900800 });
801
sangho0248ca22017-05-31 13:22:47 +0900802 securityGroupService.securityGroups().forEach(securityGroup ->
803 securityGroup.getRules().forEach(this::securityGroupRuleAdded));
804 } else {
Jian Lib6969502018-10-30 20:38:07 +0900805 osNodeService.completeNodes(COMPUTE).forEach(node -> {
Jian Li1e9cb732018-11-25 23:17:21 +0900806 osFlowRuleService.connectTables(node.intgBridge(), ACL_EGRESS_TABLE, JUMP_TABLE);
Jian Lib6969502018-10-30 20:38:07 +0900807 initializeConnTrackTable(node.intgBridge(), false);
Jian Li1e9cb732018-11-25 23:17:21 +0900808 initializeAclTable(node.intgBridge(), false);
809 initializeIngressTable(node.intgBridge(), false);
Jian Lib6969502018-10-30 20:38:07 +0900810 });
811
sangho0248ca22017-05-31 13:22:47 +0900812 securityGroupService.securityGroups().forEach(securityGroup ->
813 securityGroup.getRules().forEach(this::securityGroupRuleRemoved));
814 }
815
Jian Libcc42282018-09-13 20:59:34 +0900816 log.info("Reset security group info " +
Jian Li38c82f72020-04-02 11:15:38 +0900817 (getUseSecurityGroupFlag() ? " with " : " without") + " Security Group");
sangho0248ca22017-05-31 13:22:47 +0900818 }
819
820 private void securityGroupRuleAdded(SecurityGroupRule sgRule) {
821 osNetService.ports().stream()
Jian Libcc42282018-09-13 20:59:34 +0900822 .filter(port -> port.getSecurityGroups()
Jian Li28ec77f2018-10-31 07:07:25 +0900823 .contains(sgRule.getSecurityGroupId()))
sangho0248ca22017-05-31 13:22:47 +0900824 .forEach(port -> {
825 updateSecurityGroupRule(
826 instancePortService.instancePort(port.getId()),
827 port, sgRule, true);
828 log.debug("Applied security group rule {} to port {}",
829 sgRule.getId(), port.getId());
830 });
831 }
832
833 private void securityGroupRuleRemoved(SecurityGroupRule sgRule) {
Jian Liac30e272018-10-18 23:08:03 +0900834 Set<Port> removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
835
836 Sets.union(osNetService.ports(), removedPorts).stream()
Jian Libcc42282018-09-13 20:59:34 +0900837 .filter(port -> port.getSecurityGroups()
Jian Li28ec77f2018-10-31 07:07:25 +0900838 .contains(sgRule.getSecurityGroupId()))
sangho0248ca22017-05-31 13:22:47 +0900839 .forEach(port -> {
840 updateSecurityGroupRule(
841 instancePortService.instancePort(port.getId()),
842 port, sgRule, false);
843 log.debug("Removed security group rule {} from port {}",
844 sgRule.getId(), port.getId());
845 });
846 }
847
sangho2e97be02017-07-03 18:18:27 +0900848 private int binLower(String binStr, int bits) {
Jian Li4d138702018-11-27 17:25:28 +0900849 StringBuilder outBin = new StringBuilder(
850 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
sangho2e97be02017-07-03 18:18:27 +0900851 for (int i = 0; i < bits; i++) {
Jian Li4d138702018-11-27 17:25:28 +0900852 outBin.append(STR_ZERO);
sangho2e97be02017-07-03 18:18:27 +0900853 }
854
Jian Li4d138702018-11-27 17:25:28 +0900855 return Integer.parseInt(outBin.toString(), MASK_RADIX);
sangho2e97be02017-07-03 18:18:27 +0900856 }
857
858 private int binHigher(String binStr, int bits) {
Jian Li4d138702018-11-27 17:25:28 +0900859 StringBuilder outBin = new StringBuilder(
860 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
sangho2e97be02017-07-03 18:18:27 +0900861 for (int i = 0; i < bits; i++) {
Jian Li4d138702018-11-27 17:25:28 +0900862 outBin.append(STR_ONE);
sangho2e97be02017-07-03 18:18:27 +0900863 }
864
Jian Li4d138702018-11-27 17:25:28 +0900865 return Integer.parseInt(outBin.toString(), MASK_RADIX);
sangho2e97be02017-07-03 18:18:27 +0900866 }
867
868 private int testMasks(String binStr, int start, int end) {
Jian Li4d138702018-11-27 17:25:28 +0900869 int mask = MASK_BEGIN_IDX;
870 for (; mask <= MASK_MAX_IDX; mask++) {
sangho2e97be02017-07-03 18:18:27 +0900871 int maskStart = binLower(binStr, mask);
872 int maskEnd = binHigher(binStr, mask);
873 if (maskStart < start || maskEnd > end) {
874 return mask - 1;
875 }
876 }
877
878 return mask;
879 }
880
881 private String getMask(int bits) {
882 switch (bits) {
883 case 0: return "ffff";
884 case 1: return "fffe";
885 case 2: return "fffc";
886 case 3: return "fff8";
887 case 4: return "fff0";
888 case 5: return "ffe0";
889 case 6: return "ffc0";
890 case 7: return "ff80";
891 case 8: return "ff00";
892 case 9: return "fe00";
893 case 10: return "fc00";
894 case 11: return "f800";
895 case 12: return "f000";
896 case 13: return "e000";
897 case 14: return "c000";
898 case 15: return "8000";
899 case 16: return "0000";
900 default: return null;
901 }
902 }
903
904 private Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
905
906 boolean processing = true;
907 int start = portMin;
908 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
909 while (processing) {
910 String minStr = Integer.toBinaryString(start);
Jian Li4d138702018-11-27 17:25:28 +0900911 String binStrMinPadded = STR_PADDING.substring(minStr.length()) + minStr;
sangho2e97be02017-07-03 18:18:27 +0900912
913 int mask = testMasks(binStrMinPadded, start, portMax);
914 int maskStart = binLower(binStrMinPadded, mask);
915 int maskEnd = binHigher(binStrMinPadded, mask);
916
917 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
Jian Libcc42282018-09-13 20:59:34 +0900918 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
Jian Li4d138702018-11-27 17:25:28 +0900919 Integer.parseInt(Objects.requireNonNull(getMask(mask)), PORT_RADIX)));
sangho2e97be02017-07-03 18:18:27 +0900920
921 start = maskEnd + 1;
922 if (start > portMax) {
923 processing = false;
924 }
925 }
926
927 return portMaskMap;
928 }
929
sangho6a9ff0d2017-03-27 11:23:37 +0900930 private class InternalInstancePortListener implements InstancePortListener {
931
932 @Override
933 public boolean isRelevant(InstancePortEvent event) {
Jian Li38c82f72020-04-02 11:15:38 +0900934 return getUseSecurityGroupFlag();
Jian Li34220ea2018-11-14 01:30:24 +0900935 }
936
937 private boolean isRelevantHelper(InstancePortEvent event) {
938 return mastershipService.isLocalMaster(event.subject().deviceId());
sangho6a9ff0d2017-03-27 11:23:37 +0900939 }
940
941 @Override
942 public void event(InstancePortEvent event) {
sangho6a9ff0d2017-03-27 11:23:37 +0900943 switch (event.type()) {
Jian Liec5c32b2018-07-13 14:28:58 +0900944 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Lie8b28db2018-10-17 14:04:09 +0900945 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liac30e272018-10-18 23:08:03 +0900946 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900947 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Liac30e272018-10-18 23:08:03 +0900948 break;
949 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li4d138702018-11-27 17:25:28 +0900950 eventExecutor.execute(() -> processInstancePortVanish(event));
sangho6a9ff0d2017-03-27 11:23:37 +0900951 break;
Jian Lib8cdcc12018-10-23 01:53:10 +0900952 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900953 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
sangho6a9ff0d2017-03-27 11:23:37 +0900954 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900955 default:
956 break;
957 }
958 }
Jian Liac30e272018-10-18 23:08:03 +0900959
Jian Li4d138702018-11-27 17:25:28 +0900960 private void processInstanceMigrationStart(InstancePortEvent event) {
961 if (!isRelevantHelper(event)) {
962 return;
963 }
964
965 InstancePort instPort = event.subject();
966 installSecurityGroupRules(event, instPort);
967 setAclRecircRules(instPort, true);
968 }
969
970 private void processInstancePortVanish(InstancePortEvent event) {
971 if (!isRelevantHelper(event)) {
972 return;
973 }
974
975 InstancePort instPort = event.subject();
976 Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
977 setSecurityGroupRules(instPort, osPort, false);
978 removedOsPortStore.remove(instPort.portId());
979 setAclRecircRules(instPort, false);
980 }
981
982 private void processInstanceMigrationEnd(InstancePortEvent event) {
983 if (!isRelevantHelper(event)) {
984 return;
985 }
986
987 InstancePort instPort = event.subject();
988 InstancePort revisedInstPort = swapStaleLocation(instPort);
989 Port port = osNetService.port(instPort.portId());
990 setSecurityGroupRules(revisedInstPort, port, false);
991 setAclRecircRules(revisedInstPort, false);
992 }
993
Jian Liac30e272018-10-18 23:08:03 +0900994 private void installSecurityGroupRules(InstancePortEvent event,
995 InstancePort instPort) {
996 log.debug("Instance port detected/updated MAC:{} IP:{}",
997 instPort.macAddress(),
998 instPort.ipAddress());
Jian Li2b9838c2018-10-28 17:09:42 +0900999 eventExecutor.execute(() ->
1000 setSecurityGroupRules(instPort,
1001 osNetService.port(event.subject().portId()), true));
Jian Liac30e272018-10-18 23:08:03 +09001002 }
Jian Li1e9cb732018-11-25 23:17:21 +09001003
Jian Li4d138702018-11-27 17:25:28 +09001004 private void setSecurityGroupRules(InstancePort instPort,
1005 Port port, boolean install) {
1006 Port osPort = port;
1007
1008 if (!install) {
1009 Port rmvPort = removedOsPortStore.asJavaMap().get(instPort.portId());
1010 if (osPort == null && rmvPort == null) {
1011 return;
1012 }
1013
1014 if (port == null) {
1015 osPort = rmvPort;
1016 }
1017 }
1018
1019 final Port finalPort = osPort;
1020
1021 osPort.getSecurityGroups().forEach(sgId -> {
1022 SecurityGroup sg = securityGroupService.securityGroup(sgId);
1023 if (sg == null) {
1024 log.error("Security Group {} not found", sgId);
1025 return;
1026 }
1027 sg.getRules().forEach(sgRule ->
1028 updateSecurityGroupRule(instPort, finalPort, sgRule, install));
1029 final String action = install ? "Installed " : "Removed ";
1030 log.debug(action + "Security Group Rule ID : " + sgId);
1031 });
1032 }
1033
Jian Li1e9cb732018-11-25 23:17:21 +09001034 private void setAclRecircRules(InstancePort instPort, boolean install) {
1035 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1036
1037 Network net = osNetService.network(instPort.networkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +09001038 Type netType = osNetService.networkType(instPort.networkId());
Jian Li1e9cb732018-11-25 23:17:21 +09001039 String segId = net.getProviderSegID();
1040
1041 switch (netType) {
1042 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +09001043 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +09001044 case GENEVE:
Jian Li1e9cb732018-11-25 23:17:21 +09001045 sBuilder.matchTunnelId(Long.valueOf(segId));
1046 break;
1047 case VLAN:
1048 sBuilder.matchVlanId(VlanId.vlanId(segId));
1049 break;
1050 default:
1051 break;
1052 }
1053
1054 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
1055 sBuilder.matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_IP_PREFIX));
1056
1057 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1058 tBuilder.transition(ACL_INGRESS_TABLE);
1059
1060 osFlowRuleService.setRule(
1061 appId,
1062 instPort.deviceId(),
1063 sBuilder.build(),
1064 tBuilder.build(),
1065 PRIORITY_ACL_RULE,
1066 ACL_RECIRC_TABLE,
1067 install);
1068 }
sangho6a9ff0d2017-03-27 11:23:37 +09001069 }
1070
1071 private class InternalOpenstackPortListener implements OpenstackNetworkListener {
1072
1073 @Override
1074 public boolean isRelevant(OpenstackNetworkEvent event) {
sanghoshinbbeb31a2018-09-11 17:01:01 +08001075 if (event.port() == null || Strings.isNullOrEmpty(event.port().getId())) {
sangho6a9ff0d2017-03-27 11:23:37 +09001076 return false;
1077 }
Jian Libcc42282018-09-13 20:59:34 +09001078
Jian Li38c82f72020-04-02 11:15:38 +09001079 return getUseSecurityGroupFlag();
Jian Li34220ea2018-11-14 01:30:24 +09001080 }
1081
1082 private boolean isRelevantHelper(OpenstackNetworkEvent event) {
Jian Libcc42282018-09-13 20:59:34 +09001083 InstancePort instPort = instancePortService.instancePort(event.port().getId());
1084
1085 if (instPort == null) {
1086 return false;
1087 }
1088
Jian Li34220ea2018-11-14 01:30:24 +09001089 return mastershipService.isLocalMaster(instPort.deviceId());
Jian Libcc42282018-09-13 20:59:34 +09001090 }
1091
1092 @Override
1093 public void event(OpenstackNetworkEvent event) {
1094 log.debug("openstack port event received {}", event);
Jian Libcc42282018-09-13 20:59:34 +09001095
Jian Li4d138702018-11-27 17:25:28 +09001096 if (event.type() == OPENSTACK_PORT_PRE_REMOVE) {
1097 eventExecutor.execute(() -> processPortPreRemove(event));
Jian Libcc42282018-09-13 20:59:34 +09001098 }
1099 }
Jian Li4d138702018-11-27 17:25:28 +09001100
1101 private void processPortPreRemove(OpenstackNetworkEvent event) {
1102 if (!isRelevantHelper(event)) {
1103 return;
1104 }
1105
1106 Port osPort = event.port();
1107 removedOsPortStore.put(osPort.getId(), osPort);
1108 }
Jian Libcc42282018-09-13 20:59:34 +09001109 }
1110
Jian Li34220ea2018-11-14 01:30:24 +09001111 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
Jian Libcc42282018-09-13 20:59:34 +09001112
1113 @Override
1114 public boolean isRelevant(OpenstackNetworkEvent event) {
1115 if (event.port() == null || Strings.isNullOrEmpty(event.port().getId())) {
1116 return false;
1117 }
Jian Li2b9838c2018-10-28 17:09:42 +09001118
Jian Li38c82f72020-04-02 11:15:38 +09001119 return getUseSecurityGroupFlag();
Jian Li34220ea2018-11-14 01:30:24 +09001120 }
1121
1122 private boolean isRelevantHelper(OpenstackNetworkEvent event) {
Hyunsun Moonae51e732017-04-25 17:46:21 +09001123 if (event.securityGroupId() == null ||
1124 securityGroupService.securityGroup(event.securityGroupId()) == null) {
1125 return false;
1126 }
Jian Li2b9838c2018-10-28 17:09:42 +09001127
1128 InstancePort instPort = instancePortService.instancePort(event.port().getId());
1129
1130 if (instPort == null) {
Hyunsun Moonae51e732017-04-25 17:46:21 +09001131 return false;
1132 }
Jian Li2b9838c2018-10-28 17:09:42 +09001133
Jian Li34220ea2018-11-14 01:30:24 +09001134 return mastershipService.isLocalMaster(instPort.deviceId());
sangho6a9ff0d2017-03-27 11:23:37 +09001135 }
1136
1137 @Override
1138 public void event(OpenstackNetworkEvent event) {
sanghoshinbbeb31a2018-09-11 17:01:01 +08001139 log.debug("security group event received {}", event);
Hyunsun Moonae51e732017-04-25 17:46:21 +09001140
sangho6a9ff0d2017-03-27 11:23:37 +09001141 switch (event.type()) {
Hyunsun Moonae51e732017-04-25 17:46:21 +09001142 case OPENSTACK_PORT_SECURITY_GROUP_ADDED:
Jian Li4d138702018-11-27 17:25:28 +09001143 eventExecutor.execute(() -> processPortSgAdd(event));
sangho6a9ff0d2017-03-27 11:23:37 +09001144 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +09001145 case OPENSTACK_PORT_SECURITY_GROUP_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +09001146 eventExecutor.execute(() -> processPortSgRemove(event));
sangho6a9ff0d2017-03-27 11:23:37 +09001147 break;
1148 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +09001149 // do nothing for the other events
sangho6a9ff0d2017-03-27 11:23:37 +09001150 break;
1151 }
1152 }
Jian Li4d138702018-11-27 17:25:28 +09001153
1154 private void processPortSgAdd(OpenstackNetworkEvent event) {
1155 if (!isRelevantHelper(event)) {
1156 return;
1157 }
1158
1159 InstancePort instPort = instancePortService.instancePort(event.port().getId());
1160 SecurityGroup osSg = securityGroupService.securityGroup(event.securityGroupId());
1161
1162 osSg.getRules().forEach(sgRule -> {
1163 updateSecurityGroupRule(instPort, event.port(), sgRule, true);
1164 });
1165 log.info("Added security group {} to port {}",
1166 event.securityGroupId(), event.port().getId());
1167 }
1168
1169 private void processPortSgRemove(OpenstackNetworkEvent event) {
1170 if (!isRelevantHelper(event)) {
1171 return;
1172 }
1173
1174 InstancePort instPort = instancePortService.instancePort(event.port().getId());
1175 SecurityGroup osSg = securityGroupService.securityGroup(event.securityGroupId());
1176
1177 osSg.getRules().forEach(sgRule -> {
1178 updateSecurityGroupRule(instPort, event.port(), sgRule, false);
1179 });
1180 log.info("Removed security group {} from port {}",
1181 event.securityGroupId(), event.port().getId());
1182 }
sangho6a9ff0d2017-03-27 11:23:37 +09001183 }
1184
Jian Li34220ea2018-11-14 01:30:24 +09001185 private class InternalSecurityGroupListener implements OpenstackSecurityGroupListener {
sangho6a9ff0d2017-03-27 11:23:37 +09001186
1187 @Override
sangho0248ca22017-05-31 13:22:47 +09001188 public boolean isRelevant(OpenstackSecurityGroupEvent event) {
Jian Li38c82f72020-04-02 11:15:38 +09001189 return getUseSecurityGroupFlag();
sangho0248ca22017-05-31 13:22:47 +09001190 }
1191
Jian Li34220ea2018-11-14 01:30:24 +09001192 private boolean isRelevantHelper() {
1193 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1194 }
1195
sangho0248ca22017-05-31 13:22:47 +09001196 @Override
sangho6a9ff0d2017-03-27 11:23:37 +09001197 public void event(OpenstackSecurityGroupEvent event) {
1198 switch (event.type()) {
sangho6a9ff0d2017-03-27 11:23:37 +09001199 case OPENSTACK_SECURITY_GROUP_RULE_CREATED:
Jian Li4d138702018-11-27 17:25:28 +09001200 eventExecutor.execute(() -> processSgRuleCreate(event));
sangho6a9ff0d2017-03-27 11:23:37 +09001201 break;
sangho6a9ff0d2017-03-27 11:23:37 +09001202 case OPENSTACK_SECURITY_GROUP_RULE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +09001203 eventExecutor.execute(() -> processSgRuleRemove(event));
sangho6a9ff0d2017-03-27 11:23:37 +09001204 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +09001205 case OPENSTACK_SECURITY_GROUP_REMOVED:
Jian Li9d35bd62018-10-13 01:43:24 +09001206 case OPENSTACK_SECURITY_GROUP_CREATED:
sangho6a9ff0d2017-03-27 11:23:37 +09001207 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +09001208 // do nothing
1209 break;
sangho6a9ff0d2017-03-27 11:23:37 +09001210 }
1211 }
Jian Li4d138702018-11-27 17:25:28 +09001212
1213 private void processSgRuleCreate(OpenstackSecurityGroupEvent event) {
1214 if (!isRelevantHelper()) {
1215 return;
1216 }
1217
1218 SecurityGroupRule sgRuleToAdd = event.securityGroupRule();
1219 securityGroupRuleAdded(sgRuleToAdd);
1220 log.info("Applied new security group rule {} to ports", sgRuleToAdd.getId());
1221 }
1222
1223 private void processSgRuleRemove(OpenstackSecurityGroupEvent event) {
1224 if (!isRelevantHelper()) {
1225 return;
1226 }
1227
1228 SecurityGroupRule sgRuleToRemove = event.securityGroupRule();
1229 securityGroupRuleRemoved(sgRuleToRemove);
1230 log.info("Removed security group rule {} from ports", sgRuleToRemove.getId());
1231 }
sangho6a9ff0d2017-03-27 11:23:37 +09001232 }
sangho1aaa7882017-05-31 13:22:47 +09001233
1234 private class InternalNodeListener implements OpenstackNodeListener {
1235
1236 @Override
1237 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li2dc37592019-03-14 17:32:15 +09001238 return event.subject().type() == COMPUTE;
sangho1aaa7882017-05-31 13:22:47 +09001239 }
1240
Jian Li34220ea2018-11-14 01:30:24 +09001241 private boolean isRelevantHelper() {
1242 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1243 }
1244
sangho1aaa7882017-05-31 13:22:47 +09001245 @Override
1246 public void event(OpenstackNodeEvent event) {
sangho1aaa7882017-05-31 13:22:47 +09001247 switch (event.type()) {
1248 case OPENSTACK_NODE_COMPLETE:
Jian Li627e0162020-03-12 17:50:36 +09001249 eventExecutor.execute(() -> processNodeComplete(event.subject()));
sangho1aaa7882017-05-31 13:22:47 +09001250 break;
1251 case OPENSTACK_NODE_CREATED:
1252 case OPENSTACK_NODE_REMOVED:
1253 case OPENSTACK_NODE_UPDATED:
1254 case OPENSTACK_NODE_INCOMPLETE:
1255 default:
1256 break;
1257 }
1258 }
Jian Li4d138702018-11-27 17:25:28 +09001259
Jian Li627e0162020-03-12 17:50:36 +09001260 private void processNodeComplete(OpenstackNode node) {
Jian Li4d138702018-11-27 17:25:28 +09001261 if (!isRelevantHelper()) {
1262 return;
1263 }
1264
Jian Li627e0162020-03-12 17:50:36 +09001265 resetSecurityGroupRulesByNode(node);
1266 }
1267
1268 private void resetSecurityGroupRulesByNode(OpenstackNode node) {
1269 if (getUseSecurityGroupFlag()) {
1270 osFlowRuleService.setUpTableMissEntry(node.intgBridge(), ACL_EGRESS_TABLE);
1271 initializeConnTrackTable(node.intgBridge(), true);
1272 initializeAclTable(node.intgBridge(), true);
1273 initializeIngressTable(node.intgBridge(), true);
1274
1275 securityGroupService.securityGroups().forEach(securityGroup ->
1276 securityGroup.getRules().forEach(
1277 OpenstackSecurityGroupHandler.this::securityGroupRuleAdded));
1278 } else {
1279 osFlowRuleService.connectTables(node.intgBridge(), ACL_EGRESS_TABLE, JUMP_TABLE);
1280 initializeConnTrackTable(node.intgBridge(), false);
1281 initializeAclTable(node.intgBridge(), false);
1282 initializeIngressTable(node.intgBridge(), false);
1283
1284 securityGroupService.securityGroups().forEach(securityGroup ->
1285 securityGroup.getRules().forEach(
1286 OpenstackSecurityGroupHandler.this::securityGroupRuleRemoved));
1287 }
1288
1289 log.info("Reset security group info " +
Jian Li38c82f72020-04-02 11:15:38 +09001290 (getUseSecurityGroupFlag() ? " with " : " without") + " Security Group");
Jian Li4d138702018-11-27 17:25:28 +09001291 }
sangho1aaa7882017-05-31 13:22:47 +09001292 }
Jian Li627e0162020-03-12 17:50:36 +09001293}