blob: 3a28831c2d81780208847eedf0760cb3a11f5abd [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;
sangho1aaa7882017-05-31 13:22:47 +090032import org.onosproject.cluster.ClusterService;
33import org.onosproject.cluster.LeadershipService;
34import org.onosproject.cluster.NodeId;
sangho6a9ff0d2017-03-27 11:23:37 +090035import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.mastership.MastershipService;
sangho1aaa7882017-05-31 13:22:47 +090038import org.onosproject.net.DeviceId;
39import org.onosproject.net.driver.DriverService;
sangho6a9ff0d2017-03-27 11:23:37 +090040import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficSelector;
sangho1aaa7882017-05-31 13:22:47 +090043import org.onosproject.net.flow.TrafficTreatment;
44import org.onosproject.net.flow.criteria.ExtensionSelector;
Jian Li28ec77f2018-10-31 07:07:25 +090045import org.onosproject.net.flow.instructions.ExtensionTreatment;
sangho6a9ff0d2017-03-27 11:23:37 +090046import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li9d35bd62018-10-13 01:43:24 +090047import org.onosproject.openstacknetworking.api.InstancePortAdminService;
sangho6a9ff0d2017-03-27 11:23:37 +090048import org.onosproject.openstacknetworking.api.InstancePortEvent;
49import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090050import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +090051import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
52import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
53import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
54import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupEvent;
55import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupListener;
56import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Jian Li26949762018-03-30 15:46:37 +090057import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
sangho1aaa7882017-05-31 13:22:47 +090058import org.onosproject.openstacknode.api.OpenstackNodeEvent;
59import org.onosproject.openstacknode.api.OpenstackNodeListener;
sangho3dd2a8b2017-07-19 15:54:31 +090060import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Liac30e272018-10-18 23:08:03 +090061import org.onosproject.store.serializers.KryoNamespaces;
62import org.onosproject.store.service.ConsistentMap;
63import org.onosproject.store.service.Serializer;
64import org.onosproject.store.service.StorageService;
Jian Li1e9cb732018-11-25 23:17:21 +090065import org.openstack4j.model.network.Network;
66import org.openstack4j.model.network.NetworkType;
sangho6a9ff0d2017-03-27 11:23:37 +090067import org.openstack4j.model.network.Port;
68import org.openstack4j.model.network.SecurityGroup;
69import org.openstack4j.model.network.SecurityGroupRule;
Jian Liac30e272018-10-18 23:08:03 +090070import org.openstack4j.model.network.State;
71import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
72import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
73import org.openstack4j.openstack.networking.domain.NeutronIP;
74import org.openstack4j.openstack.networking.domain.NeutronPort;
sangho6a9ff0d2017-03-27 11:23:37 +090075import org.openstack4j.openstack.networking.domain.NeutronSecurityGroupRule;
sangho0248ca22017-05-31 13:22:47 +090076import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077import org.osgi.service.component.annotations.Activate;
78import org.osgi.service.component.annotations.Component;
79import org.osgi.service.component.annotations.Deactivate;
80import org.osgi.service.component.annotations.Modified;
81import org.osgi.service.component.annotations.Reference;
82import org.osgi.service.component.annotations.ReferenceCardinality;
sangho6a9ff0d2017-03-27 11:23:37 +090083import org.slf4j.Logger;
84
sangho6a9ff0d2017-03-27 11:23:37 +090085import java.util.Collections;
sangho0248ca22017-05-31 13:22:47 +090086import java.util.Dictionary;
Jian Liac30e272018-10-18 23:08:03 +090087import java.util.HashSet;
88import java.util.LinkedHashMap;
sangho2e97be02017-07-03 18:18:27 +090089import java.util.Map;
sangho6a9ff0d2017-03-27 11:23:37 +090090import java.util.Objects;
91import java.util.Set;
92import java.util.concurrent.ExecutorService;
93import java.util.stream.Collectors;
94
95import static java.util.concurrent.Executors.newSingleThreadExecutor;
96import static org.onlab.util.Tools.groupedThreads;
Jian Li1e9cb732018-11-25 23:17:21 +090097import static org.onosproject.openstacknetworking.api.Constants.ACL_EGRESS_TABLE;
98import static org.onosproject.openstacknetworking.api.Constants.ACL_INGRESS_TABLE;
99import static org.onosproject.openstacknetworking.api.Constants.ACL_RECIRC_TABLE;
sangho1aaa7882017-05-31 13:22:47 +0900100import static org.onosproject.openstacknetworking.api.Constants.CT_TABLE;
101import static org.onosproject.openstacknetworking.api.Constants.ERROR_TABLE;
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700102import static org.onosproject.openstacknetworking.api.Constants.JUMP_TABLE;
sangho6a9ff0d2017-03-27 11:23:37 +0900103import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li1e9cb732018-11-25 23:17:21 +0900104import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_INGRESS_RULE;
sangho6a9ff0d2017-03-27 11:23:37 +0900105import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_RULE;
sangho1aaa7882017-05-31 13:22:47 +0900106import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_DROP_RULE;
107import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
108import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_RULE;
Ray Milkey8e406512018-10-24 15:56:50 -0700109import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP;
110import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP_DEFAULT;
Jian Lib8cdcc12018-10-23 01:53:10 +0900111import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Libcc42282018-09-13 20:59:34 +0900112import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtMaskFlag;
113import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtStateFlag;
114import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
sangho1aaa7882017-05-31 13:22:47 +0900115import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
sangho6a9ff0d2017-03-27 11:23:37 +0900116import static org.slf4j.LoggerFactory.getLogger;
117
118/**
119 * Populates flow rules to handle OpenStack SecurityGroups.
120 */
Ray Milkey8e406512018-10-24 15:56:50 -0700121@Component(
122 immediate = true,
123 property = {
124 USE_SECURITY_GROUP + ":Boolean=" + USE_SECURITY_GROUP_DEFAULT
125 }
126)
sangho6a9ff0d2017-03-27 11:23:37 +0900127public class OpenstackSecurityGroupHandler {
128
129 private final Logger log = getLogger(getClass());
130
Jian Li2b9838c2018-10-28 17:09:42 +0900131 private static final int VM_IP_PREFIX = 32;
132
Ray Milkey8e406512018-10-24 15:56:50 -0700133 /** Apply OpenStack security group rule for VM traffic. */
134 private boolean useSecurityGroup = USE_SECURITY_GROUP_DEFAULT;
sangho0248ca22017-05-31 13:22:47 +0900135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900137 protected CoreService coreService;
138
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d35bd62018-10-13 01:43:24 +0900140 protected InstancePortAdminService instancePortService;
sangho6a9ff0d2017-03-27 11:23:37 +0900141
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900143 protected MastershipService mastershipService;
144
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moonae51e732017-04-25 17:46:21 +0900146 protected OpenstackNetworkService osNetService;
sangho6a9ff0d2017-03-27 11:23:37 +0900147
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900149 protected OpenstackSecurityGroupService securityGroupService;
150
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900152 protected OpenstackFlowRuleService osFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +0900153
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700154 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho0248ca22017-05-31 13:22:47 +0900155 protected ComponentConfigService configService;
156
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700157 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho3dd2a8b2017-07-19 15:54:31 +0900158 protected OpenstackNodeService osNodeService;
159
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900161 protected DriverService driverService;
162
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900164 protected LeadershipService leadershipService;
165
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700166 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900167 protected ClusterService clusterService;
168
Ray Milkey0b18b722018-10-16 13:19:15 -0700169 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liac30e272018-10-18 23:08:03 +0900170 protected StorageService storageService;
171
172 private static final KryoNamespace SERIALIZER_PORT = KryoNamespace.newBuilder()
173 .register(KryoNamespaces.API)
174 .register(Port.class)
175 .register(NeutronPort.class)
176 .register(NeutronIP.class)
177 .register(State.class)
178 .register(NeutronAllowedAddressPair.class)
179 .register(NeutronExtraDhcpOptCreate.class)
180 .register(LinkedHashMap.class)
181 .build();
Jian Li9d35bd62018-10-13 01:43:24 +0900182
Jian Libcc42282018-09-13 20:59:34 +0900183 private final InstancePortListener instancePortListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900184 new InternalInstancePortListener();
Jian Libcc42282018-09-13 20:59:34 +0900185 private final OpenstackNetworkListener osNetworkListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900186 new InternalOpenstackNetworkListener();
Jian Libcc42282018-09-13 20:59:34 +0900187 private final OpenstackNetworkListener osPortListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900188 new InternalOpenstackPortListener();
Jian Libcc42282018-09-13 20:59:34 +0900189 private final OpenstackSecurityGroupListener securityGroupListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900190 new InternalSecurityGroupListener();
sangho1aaa7882017-05-31 13:22:47 +0900191 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Liac30e272018-10-18 23:08:03 +0900192
193 private ConsistentMap<String, Port> removedOsPortStore;
194
sangho6a9ff0d2017-03-27 11:23:37 +0900195 private ApplicationId appId;
sangho1aaa7882017-05-31 13:22:47 +0900196 private NodeId localNodeId;
sangho6a9ff0d2017-03-27 11:23:37 +0900197
198 private final ExecutorService eventExecutor = newSingleThreadExecutor(
199 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
200
201 private static final String PROTO_ICMP = "ICMP";
202 private static final String PROTO_TCP = "TCP";
203 private static final String PROTO_UDP = "UDP";
204 private static final String ETHTYPE_IPV4 = "IPV4";
205 private static final String EGRESS = "EGRESS";
206 private static final String INGRESS = "INGRESS";
207 private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
208
Jian Lie8b28db2018-10-17 14:04:09 +0900209 private static final String VXLAN = "VXLAN";
210 private static final String VLAN = "VLAN";
211
sangho1aaa7882017-05-31 13:22:47 +0900212 // We expose pipeline structure to SONA application considering removing pipeline soon.
sanghoshinbbeb31a2018-09-11 17:01:01 +0800213 private static final int GOTO_CONNTRACK_TABLE = CT_TABLE;
214 private static final int GOTO_JUMP_TABLE = JUMP_TABLE;
sangho1aaa7882017-05-31 13:22:47 +0900215
216 private static final int CT_COMMIT = 0;
217 private static final int CT_NO_COMMIT = 1;
218 private static final short CT_NO_RECIRC = -1;
219
220 private static final int ACTION_NONE = 0;
221 private static final int ACTION_DROP = -1;
222
sangho6a9ff0d2017-03-27 11:23:37 +0900223 @Activate
224 protected void activate() {
225 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
sangho1aaa7882017-05-31 13:22:47 +0900226 localNodeId = clusterService.getLocalNode().id();
sangho6a9ff0d2017-03-27 11:23:37 +0900227 instancePortService.addListener(instancePortListener);
228 securityGroupService.addListener(securityGroupListener);
Jian Libcc42282018-09-13 20:59:34 +0900229 osNetService.addListener(osPortListener);
230 osNetService.addListener(osNetworkListener);
sangho0248ca22017-05-31 13:22:47 +0900231 configService.registerProperties(getClass());
sangho1aaa7882017-05-31 13:22:47 +0900232 osNodeService.addListener(osNodeListener);
sangho6a9ff0d2017-03-27 11:23:37 +0900233
Jian Liac30e272018-10-18 23:08:03 +0900234 removedOsPortStore = storageService.<String, Port>consistentMapBuilder()
235 .withSerializer(Serializer.using(SERIALIZER_PORT))
236 .withName("openstack-removed-portstore")
237 .withApplicationId(appId)
238 .build();
239
sangho6a9ff0d2017-03-27 11:23:37 +0900240 log.info("Started");
241 }
242
243 @Deactivate
244 protected void deactivate() {
245 instancePortService.removeListener(instancePortListener);
246 securityGroupService.removeListener(securityGroupListener);
Jian Libcc42282018-09-13 20:59:34 +0900247 osNetService.removeListener(osNetworkListener);
248 osNetService.removeListener(osPortListener);
sangho0248ca22017-05-31 13:22:47 +0900249 configService.unregisterProperties(getClass(), false);
sangho1aaa7882017-05-31 13:22:47 +0900250 osNodeService.removeListener(osNodeListener);
sangho6a9ff0d2017-03-27 11:23:37 +0900251 eventExecutor.shutdown();
252
253 log.info("Stopped");
254 }
255
sangho0248ca22017-05-31 13:22:47 +0900256 @Modified
257 protected void modified(ComponentContext context) {
258 Dictionary<?, ?> properties = context.getProperties();
259 Boolean flag;
260
Ray Milkey8e406512018-10-24 15:56:50 -0700261 flag = Tools.isPropertyEnabled(properties, USE_SECURITY_GROUP);
sangho0248ca22017-05-31 13:22:47 +0900262 if (flag == null) {
263 log.info("useSecurityGroup is not configured, " +
264 "using current value of {}", useSecurityGroup);
265 } else {
266 useSecurityGroup = flag;
267 log.info("Configured. useSecurityGroup is {}",
268 useSecurityGroup ? "enabled" : "disabled");
269 }
270
sanghoe6457a32017-08-24 14:31:19 +0900271 securityGroupService.setSecurityGroupEnabled(useSecurityGroup);
sangho0248ca22017-05-31 13:22:47 +0900272 resetSecurityGroupRules();
273 }
274
sangho1aaa7882017-05-31 13:22:47 +0900275 private void initializeConnTrackTable(DeviceId deviceId, boolean install) {
276
277 //table=1,ip,ct_state=-trk, actions=ct(table:2)
Jian Libcc42282018-09-13 20:59:34 +0900278 long ctState = computeCtStateFlag(false, false, false);
279 long ctMask = computeCtMaskFlag(true, false, false);
sangho1aaa7882017-05-31 13:22:47 +0900280 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) GOTO_CONNTRACK_TABLE,
281 ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
282
283 //table=2,ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:3
Jian Libcc42282018-09-13 20:59:34 +0900284 ctState = computeCtStateFlag(true, false, true);
285 ctMask = computeCtMaskFlag(true, false, true);
sangho1aaa7882017-05-31 13:22:47 +0900286 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
287 GOTO_JUMP_TABLE, PRIORITY_CT_RULE, install);
288
289 //table=2,ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
Jian Libcc42282018-09-13 20:59:34 +0900290 ctState = computeCtStateFlag(true, true, false);
291 ctMask = computeCtMaskFlag(true, true, false);
sangho1aaa7882017-05-31 13:22:47 +0900292 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
293 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
294 }
295
Jian Li1e9cb732018-11-25 23:17:21 +0900296 private void initializeAclTable(DeviceId deviceId, boolean install) {
297
298 ExtensionTreatment ctTreatment =
299 niciraConnTrackTreatmentBuilder(driverService, deviceId)
300 .commit(true)
301 .build();
302
303 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
304 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
305
306 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
307 tBuilder.extension(ctTreatment, deviceId)
308 .transition(JUMP_TABLE);
309
310 osFlowRuleService.setRule(appId,
311 deviceId,
312 sBuilder.build(),
313 tBuilder.build(),
314 PRIORITY_ACL_INGRESS_RULE,
315 ACL_RECIRC_TABLE,
316 install);
317 }
318
319 private void initializeIngressTable(DeviceId deviceId, boolean install) {
320 if (install) {
321 osFlowRuleService.setUpTableMissEntry(deviceId, ACL_INGRESS_TABLE);
322 } else {
323 osFlowRuleService.connectTables(deviceId, ACL_INGRESS_TABLE, JUMP_TABLE);
324 }
325 }
326
Jian Libcc42282018-09-13 20:59:34 +0900327 private void setSecurityGroupRules(InstancePort instPort,
328 Port port, boolean install) {
Jian Liac30e272018-10-18 23:08:03 +0900329
330 if (!install) {
331 Port rmvPort = removedOsPortStore.asJavaMap().get(instPort.portId());
332 if (port == null && rmvPort == null) {
333 return;
334 }
335
336 if (port == null) {
337 port = rmvPort;
338 }
339 }
340
341 final Port finalPort = port;
342
sangho6a9ff0d2017-03-27 11:23:37 +0900343 port.getSecurityGroups().forEach(sgId -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900344 SecurityGroup sg = securityGroupService.securityGroup(sgId);
345 if (sg == null) {
346 log.error("Security Group Not Found : {}", sgId);
347 return;
348 }
Jian Libcc42282018-09-13 20:59:34 +0900349 sg.getRules().forEach(sgRule ->
Jian Liac30e272018-10-18 23:08:03 +0900350 updateSecurityGroupRule(instPort, finalPort, sgRule, install));
Hyunsun Moonae51e732017-04-25 17:46:21 +0900351 final String action = install ? "Installed " : "Removed ";
352 log.debug(action + "security group rule ID : " + sgId);
sangho6a9ff0d2017-03-27 11:23:37 +0900353 });
354 }
355
Jian Libcc42282018-09-13 20:59:34 +0900356 private void updateSecurityGroupRule(InstancePort instPort, Port port,
357 SecurityGroupRule sgRule, boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900358
Daniel Park3a140592018-06-28 18:33:10 +0900359 if (instPort == null || port == null || sgRule == null) {
360 return;
361 }
362
sangho6a9ff0d2017-03-27 11:23:37 +0900363 if (sgRule.getRemoteGroupId() != null && !sgRule.getRemoteGroupId().isEmpty()) {
Jian Lia70fdb602018-11-05 01:32:22 +0900364 getRemoteInstPorts(port, sgRule.getRemoteGroupId(), install)
Jian Libcc42282018-09-13 20:59:34 +0900365 .forEach(rInstPort -> {
Jian Li1e9cb732018-11-25 23:17:21 +0900366 populateSecurityGroupRule(sgRule, instPort,
Jian Libcc42282018-09-13 20:59:34 +0900367 rInstPort.ipAddress().toIpPrefix(), install);
Jian Li1e9cb732018-11-25 23:17:21 +0900368 populateSecurityGroupRule(sgRule, rInstPort,
Jian Libcc42282018-09-13 20:59:34 +0900369 instPort.ipAddress().toIpPrefix(), install);
sangho6a9ff0d2017-03-27 11:23:37 +0900370
Jian Libcc42282018-09-13 20:59:34 +0900371 SecurityGroupRule rSgRule =
372 new NeutronSecurityGroupRule
373 .SecurityGroupRuleConcreteBuilder()
Jian Li28ec77f2018-10-31 07:07:25 +0900374 .from(sgRule)
375 .direction(sgRule.getDirection().toUpperCase()
376 .equals(EGRESS) ? INGRESS : EGRESS)
377 .build();
Jian Li1e9cb732018-11-25 23:17:21 +0900378 populateSecurityGroupRule(rSgRule, instPort,
Jian Libcc42282018-09-13 20:59:34 +0900379 rInstPort.ipAddress().toIpPrefix(), install);
Jian Li1e9cb732018-11-25 23:17:21 +0900380 populateSecurityGroupRule(rSgRule, rInstPort,
Jian Libcc42282018-09-13 20:59:34 +0900381 instPort.ipAddress().toIpPrefix(), install);
382 });
sangho6a9ff0d2017-03-27 11:23:37 +0900383 } else {
Jian Li1e9cb732018-11-25 23:17:21 +0900384 populateSecurityGroupRule(sgRule, instPort,
Jian Libcc42282018-09-13 20:59:34 +0900385 sgRule.getRemoteIpPrefix() == null ? IP_PREFIX_ANY :
Jian Li28ec77f2018-10-31 07:07:25 +0900386 IpPrefix.valueOf(sgRule.getRemoteIpPrefix()), install);
sangho6a9ff0d2017-03-27 11:23:37 +0900387 }
388 }
389
Jian Libcc42282018-09-13 20:59:34 +0900390 private void populateSecurityGroupRule(SecurityGroupRule sgRule,
391 InstancePort instPort,
Jian Lie8b28db2018-10-17 14:04:09 +0900392 IpPrefix remoteIp,
393 boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900394 Set<TrafficSelector> selectors = buildSelectors(sgRule,
Jian Li1e9cb732018-11-25 23:17:21 +0900395 Ip4Address.valueOf(instPort.ipAddress().toInetAddress()),
396 remoteIp, instPort.networkId());
sangho2e97be02017-07-03 18:18:27 +0900397 if (selectors == null || selectors.isEmpty()) {
sangho6a9ff0d2017-03-27 11:23:37 +0900398 return;
399 }
400
Jian Li28ec77f2018-10-31 07:07:25 +0900401 // XXX All egress traffic needs to go through connection tracking module,
402 // which might hurt its performance.
403 ExtensionTreatment ctTreatment =
404 niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
405 .commit(true)
406 .build();
407
Jian Li1e9cb732018-11-25 23:17:21 +0900408 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li28ec77f2018-10-31 07:07:25 +0900409
Jian Li1e9cb732018-11-25 23:17:21 +0900410 int aclTable;
411 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
412 aclTable = ACL_EGRESS_TABLE;
413 tBuilder.transition(ACL_RECIRC_TABLE);
414 } else {
415 aclTable = ACL_INGRESS_TABLE;
416 tBuilder.extension(ctTreatment, instPort.deviceId())
417 .transition(JUMP_TABLE);
418 }
419
420 int finalAclTable = aclTable;
421 selectors.forEach(selector -> {
422 osFlowRuleService.setRule(appId,
423 instPort.deviceId(),
424 selector, tBuilder.build(),
425 PRIORITY_ACL_RULE,
426 finalAclTable,
427 install);
428 });
sangho6a9ff0d2017-03-27 11:23:37 +0900429 }
430
431 /**
sangho1aaa7882017-05-31 13:22:47 +0900432 * Sets connection tracking rule using OVS extension commands.
Jian Li2b9838c2018-10-28 17:09:42 +0900433 * It is not so graceful, but I don't want to make it more general because
434 * it is going to be used only here.
435 * The following is the usage of the function.
sangho1aaa7882017-05-31 13:22:47 +0900436 *
437 * @param deviceId Device ID
Jian Li2b9838c2018-10-28 17:09:42 +0900438 * @param ctState ctState: please use RulePopulatorUtil.computeCtStateFlag()
439 * to build the value
440 * @param ctMask crMask: please use RulePopulatorUtil.computeCtMaskFlag()
441 * to build the value
sangho1aaa7882017-05-31 13:22:47 +0900442 * @param commit CT_COMMIT for commit action, CT_NO_COMMIT otherwise
Jian Li2b9838c2018-10-28 17:09:42 +0900443 * @param recircTable table number for recirculation after CT actions.
444 * CT_NO_RECIRC with no recirculation
445 * @param action Additional actions. ACTION_DROP, ACTION_NONE,
446 * GOTO_XXX_TABLE are supported.
sangho1aaa7882017-05-31 13:22:47 +0900447 * @param priority priority value for the rule
448 * @param install true for insertion, false for removal
449 */
450 private void setConnTrackRule(DeviceId deviceId, long ctState, long ctMask,
451 int commit, short recircTable,
452 int action, int priority, boolean install) {
453
Jian Libcc42282018-09-13 20:59:34 +0900454 ExtensionSelector esCtSate = RulePopulatorUtil
455 .buildCtExtensionSelector(driverService, deviceId, ctState, ctMask);
sangho1aaa7882017-05-31 13:22:47 +0900456 TrafficSelector selector = DefaultTrafficSelector.builder()
457 .extension(esCtSate, deviceId)
458 .matchEthType(Ethernet.TYPE_IPV4)
459 .build();
460
461 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
462
463 if (commit == CT_COMMIT || recircTable > 0) {
464 RulePopulatorUtil.NiriraConnTrackTreatmentBuilder natTreatmentBuilder =
Jian Libcc42282018-09-13 20:59:34 +0900465 niciraConnTrackTreatmentBuilder(driverService, deviceId);
sangho1aaa7882017-05-31 13:22:47 +0900466 natTreatmentBuilder.natAction(false);
467 if (commit == CT_COMMIT) {
468 natTreatmentBuilder.commit(true);
469 } else {
470 natTreatmentBuilder.commit(false);
471 }
472 if (recircTable > 0) {
473 natTreatmentBuilder.table(recircTable);
474 }
475 tb.extension(natTreatmentBuilder.build(), deviceId);
476 } else if (action == ACTION_DROP) {
477 tb.drop();
478 }
479
sanghoshinbbeb31a2018-09-11 17:01:01 +0800480 if (action != ACTION_NONE && action != ACTION_DROP) {
sangho1aaa7882017-05-31 13:22:47 +0900481 tb.transition(action);
482 }
483
484 int tableType = ERROR_TABLE;
485 if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
486 tableType = CT_TABLE;
487 } else if (priority == PRIORITY_CT_HOOK_RULE) {
Jian Li1e9cb732018-11-25 23:17:21 +0900488 tableType = ACL_INGRESS_TABLE;
sangho1aaa7882017-05-31 13:22:47 +0900489 } else {
490 log.error("Cannot an appropriate table for the conn track rule.");
491 }
492
493 osFlowRuleService.setRule(
494 appId,
495 deviceId,
496 selector,
497 tb.build(),
498 priority,
499 tableType,
500 install);
501 }
502
503 /**
sangho6a9ff0d2017-03-27 11:23:37 +0900504 * Returns a set of host IP addresses engaged with supplied security group ID.
505 * It only searches a VM in the same tenant boundary.
506 *
Jian Lia70fdb602018-11-05 01:32:22 +0900507 * @param srcPort openstack port
sangho6a9ff0d2017-03-27 11:23:37 +0900508 * @param sgId security group id
509 * @return set of ip addresses
510 */
Jian Lia70fdb602018-11-05 01:32:22 +0900511 private Set<InstancePort> getRemoteInstPorts(Port srcPort,
Jian Li2b9838c2018-10-28 17:09:42 +0900512 String sgId, boolean install) {
sangho6a9ff0d2017-03-27 11:23:37 +0900513 Set<InstancePort> remoteInstPorts;
514
Jian Liac30e272018-10-18 23:08:03 +0900515 Set<Port> removedPorts = Sets.newConcurrentHashSet();
516
517 if (!install) {
518 removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
519 }
520
521 remoteInstPorts = Sets.union(osNetService.ports(), removedPorts).stream()
Jian Lia70fdb602018-11-05 01:32:22 +0900522 .filter(port -> !port.getId().equals(srcPort.getId()))
523 .filter(port -> port.getTenantId().equals(srcPort.getTenantId()))
sangho6a9ff0d2017-03-27 11:23:37 +0900524 .filter(port -> port.getSecurityGroups().contains(sgId))
Jian Lia70fdb602018-11-05 01:32:22 +0900525 .filter(port -> port.getNetworkId().equals(srcPort.getNetworkId()))
sangho6a9ff0d2017-03-27 11:23:37 +0900526 .map(port -> instancePortService.instancePort(port.getId()))
527 .filter(instPort -> instPort != null && instPort.ipAddress() != null)
528 .collect(Collectors.toSet());
529
530 return Collections.unmodifiableSet(remoteInstPorts);
531 }
532
sangho2e97be02017-07-03 18:18:27 +0900533 private Set<TrafficSelector> buildSelectors(SecurityGroupRule sgRule,
534 Ip4Address vmIp,
Jian Lie8b28db2018-10-17 14:04:09 +0900535 IpPrefix remoteIp,
Jian Li1e9cb732018-11-25 23:17:21 +0900536 String netId) {
Jian Li2b9838c2018-10-28 17:09:42 +0900537 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
sangho2e97be02017-07-03 18:18:27 +0900538 // do nothing if the remote IP is my IP
539 return null;
540 }
541
542 Set<TrafficSelector> selectorSet = Sets.newHashSet();
543
544 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Li1e9cb732018-11-25 23:17:21 +0900545 buildMatches(sBuilder, sgRule, vmIp, remoteIp, netId);
sangho2e97be02017-07-03 18:18:27 +0900546
547 if (sgRule.getPortRangeMax() != null && sgRule.getPortRangeMin() != null &&
548 sgRule.getPortRangeMin() < sgRule.getPortRangeMax()) {
Jian Libcc42282018-09-13 20:59:34 +0900549 Map<TpPort, TpPort> portRangeMatchMap =
550 buildPortRangeMatches(sgRule.getPortRangeMin(),
Jian Li28ec77f2018-10-31 07:07:25 +0900551 sgRule.getPortRangeMax());
Jian Li2b9838c2018-10-28 17:09:42 +0900552 portRangeMatchMap.forEach((key, value) -> {
sangho2e97be02017-07-03 18:18:27 +0900553
Jian Li2b9838c2018-10-28 17:09:42 +0900554 if (sgRule.getProtocol().toUpperCase().equals(PROTO_TCP)) {
555 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
556 sBuilder.matchTcpSrcMasked(key, value);
557 } else {
558 sBuilder.matchTcpDstMasked(key, value);
Jian Libcc42282018-09-13 20:59:34 +0900559 }
Jian Li2b9838c2018-10-28 17:09:42 +0900560 } else if (sgRule.getProtocol().toUpperCase().equals(PROTO_UDP)) {
561 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
562 sBuilder.matchUdpSrcMasked(key, value);
563 } else {
564 sBuilder.matchUdpDstMasked(key, value);
565 }
566 }
567
568 selectorSet.add(sBuilder.build());
569 });
sangho2e97be02017-07-03 18:18:27 +0900570 } else {
571 selectorSet.add(sBuilder.build());
572 }
573
574 return selectorSet;
575 }
576
Jian Libcc42282018-09-13 20:59:34 +0900577 private void buildMatches(TrafficSelector.Builder sBuilder,
Jian Li1e9cb732018-11-25 23:17:21 +0900578 SecurityGroupRule sgRule, Ip4Address vmIp,
579 IpPrefix remoteIp, String netId) {
580 buildTunnelId(sBuilder, netId);
sangho6a9ff0d2017-03-27 11:23:37 +0900581 buildMatchEthType(sBuilder, sgRule.getEtherType());
582 buildMatchDirection(sBuilder, sgRule.getDirection(), vmIp);
583 buildMatchProto(sBuilder, sgRule.getProtocol());
584 buildMatchPort(sBuilder, sgRule.getProtocol(), sgRule.getDirection(),
sangho2e97be02017-07-03 18:18:27 +0900585 sgRule.getPortRangeMin() == null ? 0 : sgRule.getPortRangeMin(),
586 sgRule.getPortRangeMax() == null ? 0 : sgRule.getPortRangeMax());
sangho6a9ff0d2017-03-27 11:23:37 +0900587 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
sangho6a9ff0d2017-03-27 11:23:37 +0900588 }
589
Jian Li1e9cb732018-11-25 23:17:21 +0900590 private void buildTunnelId(TrafficSelector.Builder sBuilder, String netId) {
591 String segId = osNetService.segmentId(netId);
592 String netType = osNetService.networkType(netId);
Jian Lie8b28db2018-10-17 14:04:09 +0900593
594 if (VLAN.equals(netType)) {
595 sBuilder.matchVlanId(VlanId.vlanId(segId));
596 } else if (VXLAN.equals(netType)) {
597 sBuilder.matchTunnelId(Long.valueOf(segId));
Jian Li28ec77f2018-10-31 07:07:25 +0900598 } else {
599 log.warn("Cannot tag the VID due to lack of support of virtual network type {}", netType);
Jian Lie8b28db2018-10-17 14:04:09 +0900600 }
601 }
602
sangho6a9ff0d2017-03-27 11:23:37 +0900603 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
604 String direction,
605 Ip4Address vmIp) {
606 if (direction.toUpperCase().equals(EGRESS)) {
Jian Li2b9838c2018-10-28 17:09:42 +0900607 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
sangho6a9ff0d2017-03-27 11:23:37 +0900608 } else {
Jian Li2b9838c2018-10-28 17:09:42 +0900609 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
sangho6a9ff0d2017-03-27 11:23:37 +0900610 }
611 }
612
613 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
614 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
615 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
616 if (etherType != null && !Objects.equals(etherType, "null") &&
617 !etherType.toUpperCase().equals(ETHTYPE_IPV4)) {
618 log.debug("EthType {} is not supported yet in Security Group", etherType);
619 }
620 }
621
Jian Libcc42282018-09-13 20:59:34 +0900622 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder,
623 IpPrefix remoteIpPrefix, String direction) {
624 if (remoteIpPrefix != null &&
625 !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
sangho6a9ff0d2017-03-27 11:23:37 +0900626 if (direction.toUpperCase().equals(EGRESS)) {
627 sBuilder.matchIPDst(remoteIpPrefix);
628 } else {
629 sBuilder.matchIPSrc(remoteIpPrefix);
630 }
631 }
632 }
633
634 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
635 if (protocol != null) {
636 switch (protocol.toUpperCase()) {
637 case PROTO_ICMP:
638 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
639 break;
640 case PROTO_TCP:
641 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
642 break;
643 case PROTO_UDP:
644 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
645 break;
646 default:
647 }
648 }
649 }
650
Jian Libcc42282018-09-13 20:59:34 +0900651 private void buildMatchPort(TrafficSelector.Builder sBuilder,
652 String protocol, String direction,
sangho6a9ff0d2017-03-27 11:23:37 +0900653 int portMin, int portMax) {
654 if (portMin > 0 && portMax > 0 && portMin == portMax) {
655 if (protocol.toUpperCase().equals(PROTO_TCP)) {
656 if (direction.toUpperCase().equals(EGRESS)) {
657 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
658 } else {
659 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
660 }
661 } else if (protocol.toUpperCase().equals(PROTO_UDP)) {
662 if (direction.toUpperCase().equals(EGRESS)) {
663 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
664 } else {
665 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
666 }
667 }
668 }
669 }
670
sangho0248ca22017-05-31 13:22:47 +0900671 private void resetSecurityGroupRules() {
672
673 if (useSecurityGroup) {
Jian Lib6969502018-10-30 20:38:07 +0900674 osNodeService.completeNodes(COMPUTE).forEach(node -> {
Jian Li1e9cb732018-11-25 23:17:21 +0900675 osFlowRuleService.setUpTableMissEntry(node.intgBridge(), ACL_EGRESS_TABLE);
Jian Lib6969502018-10-30 20:38:07 +0900676 initializeConnTrackTable(node.intgBridge(), true);
Jian Li1e9cb732018-11-25 23:17:21 +0900677 initializeAclTable(node.intgBridge(), true);
678 initializeIngressTable(node.intgBridge(), true);
Jian Lib6969502018-10-30 20:38:07 +0900679 });
680
sangho0248ca22017-05-31 13:22:47 +0900681 securityGroupService.securityGroups().forEach(securityGroup ->
682 securityGroup.getRules().forEach(this::securityGroupRuleAdded));
683 } else {
Jian Lib6969502018-10-30 20:38:07 +0900684 osNodeService.completeNodes(COMPUTE).forEach(node -> {
Jian Li1e9cb732018-11-25 23:17:21 +0900685 osFlowRuleService.connectTables(node.intgBridge(), ACL_EGRESS_TABLE, JUMP_TABLE);
Jian Lib6969502018-10-30 20:38:07 +0900686 initializeConnTrackTable(node.intgBridge(), false);
Jian Li1e9cb732018-11-25 23:17:21 +0900687 initializeAclTable(node.intgBridge(), false);
688 initializeIngressTable(node.intgBridge(), false);
Jian Lib6969502018-10-30 20:38:07 +0900689 });
690
sangho0248ca22017-05-31 13:22:47 +0900691 securityGroupService.securityGroups().forEach(securityGroup ->
692 securityGroup.getRules().forEach(this::securityGroupRuleRemoved));
693 }
694
Jian Libcc42282018-09-13 20:59:34 +0900695 log.info("Reset security group info " +
Jian Li28ec77f2018-10-31 07:07:25 +0900696 (useSecurityGroup ? " with " : " without") + " Security Group");
sangho0248ca22017-05-31 13:22:47 +0900697 }
698
699 private void securityGroupRuleAdded(SecurityGroupRule sgRule) {
700 osNetService.ports().stream()
Jian Libcc42282018-09-13 20:59:34 +0900701 .filter(port -> port.getSecurityGroups()
Jian Li28ec77f2018-10-31 07:07:25 +0900702 .contains(sgRule.getSecurityGroupId()))
sangho0248ca22017-05-31 13:22:47 +0900703 .forEach(port -> {
704 updateSecurityGroupRule(
705 instancePortService.instancePort(port.getId()),
706 port, sgRule, true);
707 log.debug("Applied security group rule {} to port {}",
708 sgRule.getId(), port.getId());
709 });
710 }
711
712 private void securityGroupRuleRemoved(SecurityGroupRule sgRule) {
Jian Liac30e272018-10-18 23:08:03 +0900713 Set<Port> removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
714
715 Sets.union(osNetService.ports(), removedPorts).stream()
Jian Libcc42282018-09-13 20:59:34 +0900716 .filter(port -> port.getSecurityGroups()
Jian Li28ec77f2018-10-31 07:07:25 +0900717 .contains(sgRule.getSecurityGroupId()))
sangho0248ca22017-05-31 13:22:47 +0900718 .forEach(port -> {
719 updateSecurityGroupRule(
720 instancePortService.instancePort(port.getId()),
721 port, sgRule, false);
722 log.debug("Removed security group rule {} from port {}",
723 sgRule.getId(), port.getId());
724 });
725 }
726
sangho2e97be02017-07-03 18:18:27 +0900727 private int binLower(String binStr, int bits) {
Jian Li2b9838c2018-10-28 17:09:42 +0900728 StringBuilder outBin = new StringBuilder(binStr.substring(0, 16 - bits));
sangho2e97be02017-07-03 18:18:27 +0900729 for (int i = 0; i < bits; i++) {
Jian Li2b9838c2018-10-28 17:09:42 +0900730 outBin.append("0");
sangho2e97be02017-07-03 18:18:27 +0900731 }
732
Jian Li2b9838c2018-10-28 17:09:42 +0900733 return Integer.parseInt(outBin.toString(), 2);
sangho2e97be02017-07-03 18:18:27 +0900734 }
735
736 private int binHigher(String binStr, int bits) {
Jian Li2b9838c2018-10-28 17:09:42 +0900737 StringBuilder outBin = new StringBuilder(binStr.substring(0, 16 - bits));
sangho2e97be02017-07-03 18:18:27 +0900738 for (int i = 0; i < bits; i++) {
Jian Li2b9838c2018-10-28 17:09:42 +0900739 outBin.append("1");
sangho2e97be02017-07-03 18:18:27 +0900740 }
741
Jian Li2b9838c2018-10-28 17:09:42 +0900742 return Integer.parseInt(outBin.toString(), 2);
sangho2e97be02017-07-03 18:18:27 +0900743 }
744
745 private int testMasks(String binStr, int start, int end) {
746 int mask = 0;
747 for (; mask <= 16; mask++) {
748 int maskStart = binLower(binStr, mask);
749 int maskEnd = binHigher(binStr, mask);
750 if (maskStart < start || maskEnd > end) {
751 return mask - 1;
752 }
753 }
754
755 return mask;
756 }
757
758 private String getMask(int bits) {
759 switch (bits) {
760 case 0: return "ffff";
761 case 1: return "fffe";
762 case 2: return "fffc";
763 case 3: return "fff8";
764 case 4: return "fff0";
765 case 5: return "ffe0";
766 case 6: return "ffc0";
767 case 7: return "ff80";
768 case 8: return "ff00";
769 case 9: return "fe00";
770 case 10: return "fc00";
771 case 11: return "f800";
772 case 12: return "f000";
773 case 13: return "e000";
774 case 14: return "c000";
775 case 15: return "8000";
776 case 16: return "0000";
777 default: return null;
778 }
779 }
780
781 private Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
782
783 boolean processing = true;
784 int start = portMin;
785 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
786 while (processing) {
787 String minStr = Integer.toBinaryString(start);
788 String binStrMinPadded = "0000000000000000".substring(minStr.length()) + minStr;
789
790 int mask = testMasks(binStrMinPadded, start, portMax);
791 int maskStart = binLower(binStrMinPadded, mask);
792 int maskEnd = binHigher(binStrMinPadded, mask);
793
794 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
Jian Libcc42282018-09-13 20:59:34 +0900795 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
796 Integer.parseInt(Objects.requireNonNull(getMask(mask)), 16)));
sangho2e97be02017-07-03 18:18:27 +0900797
798 start = maskEnd + 1;
799 if (start > portMax) {
800 processing = false;
801 }
802 }
803
804 return portMaskMap;
805 }
806
sangho6a9ff0d2017-03-27 11:23:37 +0900807 private class InternalInstancePortListener implements InstancePortListener {
808
809 @Override
810 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900811 return useSecurityGroup;
812 }
813
814 private boolean isRelevantHelper(InstancePortEvent event) {
815 return mastershipService.isLocalMaster(event.subject().deviceId());
sangho6a9ff0d2017-03-27 11:23:37 +0900816 }
817
818 @Override
819 public void event(InstancePortEvent event) {
820 InstancePort instPort = event.subject();
821 switch (event.type()) {
Jian Liec5c32b2018-07-13 14:28:58 +0900822 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Lie8b28db2018-10-17 14:04:09 +0900823 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liac30e272018-10-18 23:08:03 +0900824 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li34220ea2018-11-14 01:30:24 +0900825 eventExecutor.execute(() -> {
826
827 if (!isRelevantHelper(event)) {
828 return;
829 }
830
831 installSecurityGroupRules(event, instPort);
Jian Li1e9cb732018-11-25 23:17:21 +0900832 setAclRecircRules(instPort, true);
Jian Li34220ea2018-11-14 01:30:24 +0900833 });
Jian Liac30e272018-10-18 23:08:03 +0900834 break;
835 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li32b03622018-11-06 17:54:24 +0900836 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900837
838 if (!isRelevantHelper(event)) {
839 return;
840 }
841
Jian Li32b03622018-11-06 17:54:24 +0900842 Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
843 setSecurityGroupRules(instPort, osPort, false);
844 removedOsPortStore.remove(instPort.portId());
Jian Li1e9cb732018-11-25 23:17:21 +0900845 setAclRecircRules(instPort, false);
Jian Li32b03622018-11-06 17:54:24 +0900846 });
sangho6a9ff0d2017-03-27 11:23:37 +0900847 break;
Jian Lib8cdcc12018-10-23 01:53:10 +0900848 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li32b03622018-11-06 17:54:24 +0900849 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900850
851 if (!isRelevantHelper(event)) {
852 return;
853 }
854
Jian Li32b03622018-11-06 17:54:24 +0900855 InstancePort revisedInstPort = swapStaleLocation(instPort);
856 Port port = osNetService.port(instPort.portId());
857 setSecurityGroupRules(revisedInstPort, port, false);
Jian Li1e9cb732018-11-25 23:17:21 +0900858 setAclRecircRules(revisedInstPort, false);
Jian Li32b03622018-11-06 17:54:24 +0900859 });
sangho6a9ff0d2017-03-27 11:23:37 +0900860 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900861 default:
862 break;
863 }
864 }
Jian Liac30e272018-10-18 23:08:03 +0900865
866 private void installSecurityGroupRules(InstancePortEvent event,
867 InstancePort instPort) {
868 log.debug("Instance port detected/updated MAC:{} IP:{}",
869 instPort.macAddress(),
870 instPort.ipAddress());
Jian Li2b9838c2018-10-28 17:09:42 +0900871 eventExecutor.execute(() ->
872 setSecurityGroupRules(instPort,
873 osNetService.port(event.subject().portId()), true));
Jian Liac30e272018-10-18 23:08:03 +0900874 }
Jian Li1e9cb732018-11-25 23:17:21 +0900875
876 private void setAclRecircRules(InstancePort instPort, boolean install) {
877 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
878
879 Network net = osNetService.network(instPort.networkId());
880 NetworkType netType = net.getNetworkType();
881 String segId = net.getProviderSegID();
882
883 switch (netType) {
884 case VXLAN:
885 sBuilder.matchTunnelId(Long.valueOf(segId));
886 break;
887 case VLAN:
888 sBuilder.matchVlanId(VlanId.vlanId(segId));
889 break;
890 default:
891 break;
892 }
893
894 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
895 sBuilder.matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_IP_PREFIX));
896
897 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
898 tBuilder.transition(ACL_INGRESS_TABLE);
899
900 osFlowRuleService.setRule(
901 appId,
902 instPort.deviceId(),
903 sBuilder.build(),
904 tBuilder.build(),
905 PRIORITY_ACL_RULE,
906 ACL_RECIRC_TABLE,
907 install);
908 }
sangho6a9ff0d2017-03-27 11:23:37 +0900909 }
910
911 private class InternalOpenstackPortListener implements OpenstackNetworkListener {
912
913 @Override
914 public boolean isRelevant(OpenstackNetworkEvent event) {
sanghoshinbbeb31a2018-09-11 17:01:01 +0800915 if (event.port() == null || Strings.isNullOrEmpty(event.port().getId())) {
sangho6a9ff0d2017-03-27 11:23:37 +0900916 return false;
917 }
Jian Libcc42282018-09-13 20:59:34 +0900918
Jian Li34220ea2018-11-14 01:30:24 +0900919 return useSecurityGroup;
920 }
921
922 private boolean isRelevantHelper(OpenstackNetworkEvent event) {
Jian Libcc42282018-09-13 20:59:34 +0900923 InstancePort instPort = instancePortService.instancePort(event.port().getId());
924
925 if (instPort == null) {
926 return false;
927 }
928
Jian Li34220ea2018-11-14 01:30:24 +0900929 return mastershipService.isLocalMaster(instPort.deviceId());
Jian Libcc42282018-09-13 20:59:34 +0900930 }
931
932 @Override
933 public void event(OpenstackNetworkEvent event) {
934 log.debug("openstack port event received {}", event);
935 Port osPort = event.port();
Jian Libcc42282018-09-13 20:59:34 +0900936
937 switch (event.type()) {
938 case OPENSTACK_PORT_PRE_REMOVE:
Jian Li34220ea2018-11-14 01:30:24 +0900939 eventExecutor.execute(() -> {
940
941 if (!isRelevantHelper(event)) {
942 return;
943 }
944
945 removedOsPortStore.put(osPort.getId(), osPort);
946 });
Jian Libcc42282018-09-13 20:59:34 +0900947 break;
948 default:
949 // do nothing for the other events
950 break;
951 }
952 }
953 }
954
Jian Li34220ea2018-11-14 01:30:24 +0900955 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
Jian Libcc42282018-09-13 20:59:34 +0900956
957 @Override
958 public boolean isRelevant(OpenstackNetworkEvent event) {
959 if (event.port() == null || Strings.isNullOrEmpty(event.port().getId())) {
960 return false;
961 }
Jian Li2b9838c2018-10-28 17:09:42 +0900962
Jian Li34220ea2018-11-14 01:30:24 +0900963 return useSecurityGroup;
964 }
965
966 private boolean isRelevantHelper(OpenstackNetworkEvent event) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900967 if (event.securityGroupId() == null ||
968 securityGroupService.securityGroup(event.securityGroupId()) == null) {
969 return false;
970 }
Jian Li2b9838c2018-10-28 17:09:42 +0900971
972 InstancePort instPort = instancePortService.instancePort(event.port().getId());
973
974 if (instPort == null) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900975 return false;
976 }
Jian Li2b9838c2018-10-28 17:09:42 +0900977
Jian Li34220ea2018-11-14 01:30:24 +0900978 return mastershipService.isLocalMaster(instPort.deviceId());
sangho6a9ff0d2017-03-27 11:23:37 +0900979 }
980
981 @Override
982 public void event(OpenstackNetworkEvent event) {
sanghoshinbbeb31a2018-09-11 17:01:01 +0800983 log.debug("security group event received {}", event);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900984 Port osPort = event.port();
Hyunsun Moonae51e732017-04-25 17:46:21 +0900985
sangho6a9ff0d2017-03-27 11:23:37 +0900986 switch (event.type()) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900987 case OPENSTACK_PORT_SECURITY_GROUP_ADDED:
988 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900989
990 if (!isRelevantHelper(event)) {
991 return;
992 }
993
994 InstancePort instPort = instancePortService.instancePort(osPort.getId());
995 SecurityGroup osSg = securityGroupService.securityGroup(event.securityGroupId());
996
Hyunsun Moonae51e732017-04-25 17:46:21 +0900997 osSg.getRules().forEach(sgRule -> {
998 updateSecurityGroupRule(instPort, osPort, sgRule, true);
999 });
1000 log.info("Added security group {} to port {}",
1001 event.securityGroupId(), event.port().getId());
1002 });
sangho6a9ff0d2017-03-27 11:23:37 +09001003 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +09001004 case OPENSTACK_PORT_SECURITY_GROUP_REMOVED:
1005 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001006
1007 if (!isRelevantHelper(event)) {
1008 return;
1009 }
1010
1011 InstancePort instPort = instancePortService.instancePort(osPort.getId());
1012 SecurityGroup osSg = securityGroupService.securityGroup(event.securityGroupId());
1013
Hyunsun Moonae51e732017-04-25 17:46:21 +09001014 osSg.getRules().forEach(sgRule -> {
1015 updateSecurityGroupRule(instPort, osPort, sgRule, false);
1016 });
1017 log.info("Removed security group {} from port {}",
1018 event.securityGroupId(), event.port().getId());
1019 });
sangho6a9ff0d2017-03-27 11:23:37 +09001020 break;
1021 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +09001022 // do nothing for the other events
sangho6a9ff0d2017-03-27 11:23:37 +09001023 break;
1024 }
1025 }
sangho6a9ff0d2017-03-27 11:23:37 +09001026 }
1027
Jian Li34220ea2018-11-14 01:30:24 +09001028 private class InternalSecurityGroupListener implements OpenstackSecurityGroupListener {
sangho6a9ff0d2017-03-27 11:23:37 +09001029
1030 @Override
sangho0248ca22017-05-31 13:22:47 +09001031 public boolean isRelevant(OpenstackSecurityGroupEvent event) {
Jian Libcc42282018-09-13 20:59:34 +09001032 return useSecurityGroup;
sangho0248ca22017-05-31 13:22:47 +09001033 }
1034
Jian Li34220ea2018-11-14 01:30:24 +09001035 private boolean isRelevantHelper() {
1036 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1037 }
1038
sangho0248ca22017-05-31 13:22:47 +09001039 @Override
sangho6a9ff0d2017-03-27 11:23:37 +09001040 public void event(OpenstackSecurityGroupEvent event) {
1041 switch (event.type()) {
sangho6a9ff0d2017-03-27 11:23:37 +09001042 case OPENSTACK_SECURITY_GROUP_RULE_CREATED:
Jian Li2b9838c2018-10-28 17:09:42 +09001043 SecurityGroupRule sgRuleToAdd = event.securityGroupRule();
sangho6a9ff0d2017-03-27 11:23:37 +09001044 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001045
1046 if (!isRelevantHelper()) {
1047 return;
1048 }
1049
Jian Li2b9838c2018-10-28 17:09:42 +09001050 securityGroupRuleAdded(sgRuleToAdd);
Hyunsun Moonae51e732017-04-25 17:46:21 +09001051 log.info("Applied new security group rule {} to ports",
Jian Li2b9838c2018-10-28 17:09:42 +09001052 sgRuleToAdd.getId());
sangho6a9ff0d2017-03-27 11:23:37 +09001053 });
1054 break;
1055
1056 case OPENSTACK_SECURITY_GROUP_RULE_REMOVED:
Jian Li2b9838c2018-10-28 17:09:42 +09001057 SecurityGroupRule sgRuleToRemove = event.securityGroupRule();
sangho6a9ff0d2017-03-27 11:23:37 +09001058 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001059
1060 if (!isRelevantHelper()) {
1061 return;
1062 }
1063
Jian Li2b9838c2018-10-28 17:09:42 +09001064 securityGroupRuleRemoved(sgRuleToRemove);
Hyunsun Moonae51e732017-04-25 17:46:21 +09001065 log.info("Removed security group rule {} from ports",
Jian Li2b9838c2018-10-28 17:09:42 +09001066 sgRuleToRemove.getId());
sangho6a9ff0d2017-03-27 11:23:37 +09001067 });
1068 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +09001069 case OPENSTACK_SECURITY_GROUP_REMOVED:
Jian Li9d35bd62018-10-13 01:43:24 +09001070 case OPENSTACK_SECURITY_GROUP_CREATED:
sangho6a9ff0d2017-03-27 11:23:37 +09001071 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +09001072 // do nothing
1073 break;
sangho6a9ff0d2017-03-27 11:23:37 +09001074 }
1075 }
sangho6a9ff0d2017-03-27 11:23:37 +09001076 }
sangho1aaa7882017-05-31 13:22:47 +09001077
1078 private class InternalNodeListener implements OpenstackNodeListener {
1079
1080 @Override
1081 public boolean isRelevant(OpenstackNodeEvent event) {
sangho1aaa7882017-05-31 13:22:47 +09001082 return event.subject().type() == COMPUTE;
1083 }
1084
Jian Li34220ea2018-11-14 01:30:24 +09001085 private boolean isRelevantHelper() {
1086 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1087 }
1088
sangho1aaa7882017-05-31 13:22:47 +09001089 @Override
1090 public void event(OpenstackNodeEvent event) {
sangho1aaa7882017-05-31 13:22:47 +09001091 switch (event.type()) {
1092 case OPENSTACK_NODE_COMPLETE:
Jian Li34220ea2018-11-14 01:30:24 +09001093 eventExecutor.execute(() -> {
1094
1095 if (!isRelevantHelper()) {
1096 return;
1097 }
1098
1099 OpenstackSecurityGroupHandler.this.resetSecurityGroupRules();
1100 });
sangho1aaa7882017-05-31 13:22:47 +09001101 break;
1102 case OPENSTACK_NODE_CREATED:
1103 case OPENSTACK_NODE_REMOVED:
1104 case OPENSTACK_NODE_UPDATED:
1105 case OPENSTACK_NODE_INCOMPLETE:
1106 default:
1107 break;
1108 }
1109 }
1110 }
Jian Libcc42282018-09-13 20:59:34 +09001111}