blob: 5b132e83b3220f9c0e99aabbf9569ed2eba9c563 [file] [log] [blame]
sangho90088532016-02-25 18:06:12 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002* Copyright 2016-present Open Networking Laboratory
sangho90088532016-02-25 18:06:12 +09003*
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*/
16
17package org.onosproject.openstacknetworking.switching;
18
19import org.onlab.packet.Ethernet;
20import org.onlab.packet.IPv4;
21import org.onlab.packet.Ip4Address;
22import org.onlab.packet.Ip4Prefix;
23import org.onlab.packet.IpAddress;
24import org.onlab.packet.IpPrefix;
25import org.onlab.packet.TpPort;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.flow.DefaultTrafficSelector;
29import org.onosproject.net.flow.DefaultTrafficTreatment;
30import org.onosproject.net.flow.TrafficSelector;
31import org.onosproject.net.flow.TrafficTreatment;
32import org.onosproject.net.flowobjective.DefaultForwardingObjective;
33import org.onosproject.net.flowobjective.FlowObjectiveService;
34import org.onosproject.net.flowobjective.ForwardingObjective;
35import org.onosproject.openstackinterface.OpenstackInterfaceService;
36import org.onosproject.openstackinterface.OpenstackSecurityGroup;
37import org.onosproject.openstackinterface.OpenstackSecurityGroupRule;
38import org.onosproject.openstacknetworking.OpenstackPortInfo;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import java.util.Map;
43
44/**
45 * Populates flows rules for Security Groups of VMs.
46 *
47 */
48public class OpenstackSecurityGroupRulePopulator {
49
50 private static Logger log = LoggerFactory
51 .getLogger(OpenstackSecurityGroupRulePopulator.class);
52
53 private OpenstackInterfaceService openstackService;
54 private FlowObjectiveService flowObjectiveService;
55
56 private ApplicationId appId;
57
58 private static final String PROTO_ICMP = "ICMP";
59 private static final String PROTO_TCP = "TCP";
60 private static final String PROTO_UDP = "UDP";
61
62 private static final String ETHTYPE_IPV4 = "IPV4";
63
64 private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
65
66 private static final int ACL_RULE_PRIORITY = 30000;
67
68 /**
69 * Constructor.
70 *
Ray Milkey21c3ebe2016-03-08 10:49:16 -080071 * @param appId application ID
72 * @param openstackService OpenStack interface service
73 * @param flowObjectiveService flow objective service
sangho90088532016-02-25 18:06:12 +090074 */
75 public OpenstackSecurityGroupRulePopulator(ApplicationId appId, OpenstackInterfaceService openstackService,
76 FlowObjectiveService flowObjectiveService) {
77 this.appId = appId;
78 this.openstackService = openstackService;
79 this.flowObjectiveService = flowObjectiveService;
80 }
81
82 /**
83 * Populates flow rules for security groups.
84 *
85 * @param id Device ID
86 * @param sgId Security Group ID
87 * @param vmIp VM IP address
88 * @param portInfoMap Port Info map
89 */
90 public void populateSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
91 Map<String, OpenstackPortInfo> portInfoMap) {
92 OpenstackSecurityGroup securityGroup = openstackService.getSecurityGroup(sgId);
93 if (securityGroup != null) {
94 securityGroup.rules().stream().forEach(sgRule -> {
95 if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
96 openstackService.ports().stream()
97 .filter(port -> port.securityGroups().contains(sgRule.remoteGroupId()))
98 .flatMap(port -> port.fixedIps().values().stream())
99 .forEach(remoteIp -> setSecurityGroupRule(id, sgRule,
100 vmIp, IpPrefix.valueOf((IpAddress) remoteIp, 32)));
101 } else {
102 setSecurityGroupRule(id, sgRule, vmIp, sgRule.remoteIpPrefix());
103 }
104 });
105
106 openstackService.ports().stream().forEach(osPort ->
107 osPort.securityGroups().stream().forEach(remoteVmSgId -> {
108 OpenstackSecurityGroup remoteVmSg = openstackService.getSecurityGroup(remoteVmSgId);
109 remoteVmSg.rules().stream()
110 .filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
111 .forEach(remoteVmSgRule -> {
112 Ip4Address remoteVmIp =
113 (Ip4Address) osPort.fixedIps().values().stream().findAny().orElse(null);
114 OpenstackPortInfo osPortInfo = portInfoMap.get(OpenstackSwitchingManager.PORTNAME_PREFIX_VM
115 + osPort.id().substring(0, 11));
116 if (osPortInfo != null && remoteVmIp != null) {
117 setSecurityGroupRule(osPortInfo.deviceId(), remoteVmSgRule, remoteVmIp,
118 IpPrefix.valueOf(vmIp, 32));
119 }
120 });
121 }));
122 }
123 }
124
125 /**
126 * Removes flow rules for security groups.
127 *
128 * @param id Device ID
129 * @param sgId Security Group ID to remove
130 * @param vmIp VM IP address
131 * @param portInfoMap port info map
132 * @param securityGroupMap security group info map
133 */
134 public void removeSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
135 Map<String, OpenstackPortInfo> portInfoMap,
136 Map<String, OpenstackSecurityGroup> securityGroupMap) {
137 OpenstackSecurityGroup securityGroup = securityGroupMap.get(sgId);
138 if (securityGroup != null) {
139 securityGroup.rules().stream().forEach(sgRule -> {
140 if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
141 portInfoMap.values().stream()
142 .filter(portInfo -> portInfo.securityGroups().contains(sgRule.remoteGroupId()))
143 .map(OpenstackPortInfo::ip)
144 .forEach(remoteIp -> {
145 removeSecurityGroupRule(id, sgRule, vmIp, IpPrefix.valueOf(remoteIp, 32));
146 });
147 } else {
148 removeSecurityGroupRule(id, sgRule, vmIp, sgRule.remoteIpPrefix());
149 }
150 });
151
152 portInfoMap.values().stream()
153 .forEach(portInfo -> portInfo.securityGroups()
154 .forEach(remoteVmSgId -> {
155 OpenstackSecurityGroup remoteVmSg = securityGroupMap.get(remoteVmSgId);
156 remoteVmSg.rules().stream()
157 .filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
158 .forEach(remoteVmSgRule -> removeSecurityGroupRule(portInfo.deviceId(),
159 remoteVmSgRule, portInfo.ip(), IpPrefix.valueOf(vmIp, 32)));
160 }));
161 }
162 }
163
164 private void setSecurityGroupRule(DeviceId id, OpenstackSecurityGroupRule sgRule,
165 Ip4Address vmIp, IpPrefix remoteIp) {
166 ForwardingObjective.Builder foBuilder = buildFlowObjective(id, sgRule, vmIp, remoteIp);
167 if (foBuilder != null) {
168 flowObjectiveService.forward(id, foBuilder.add());
169 }
170 }
171
172 private void removeSecurityGroupRule(DeviceId id, OpenstackSecurityGroupRule sgRule,
173 Ip4Address vmIp, IpPrefix remoteIp) {
174 ForwardingObjective.Builder foBuilder = buildFlowObjective(id, sgRule, vmIp, remoteIp);
175 if (foBuilder != null) {
176 flowObjectiveService.forward(id, foBuilder.remove());
177 }
178 }
179
180 ForwardingObjective.Builder buildFlowObjective(DeviceId id, OpenstackSecurityGroupRule sgRule,
181 Ip4Address vmIp, IpPrefix remoteIp) {
182 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, 32))) {
183 return null;
184 }
185 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
186 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
187
188 buildMatchs(sBuilder, sgRule, vmIp, remoteIp);
189
190 ForwardingObjective.Builder foBuilder = DefaultForwardingObjective.builder()
191 .withSelector(sBuilder.build())
192 .withTreatment(tBuilder.build())
193 .withPriority(ACL_RULE_PRIORITY)
194 .withFlag(ForwardingObjective.Flag.SPECIFIC)
195 .fromApp(appId);
196
197 return foBuilder;
198 }
199
200 private void buildMatchs(TrafficSelector.Builder sBuilder, OpenstackSecurityGroupRule sgRule,
201 Ip4Address vmIp, IpPrefix remoteIp) {
202 buildMatchEthType(sBuilder, sgRule.ethertype());
203 buildMatchDirection(sBuilder, sgRule.direction(), vmIp);
204 buildMatchProto(sBuilder, sgRule.protocol());
205 buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(), sgRule.portRangeMax(), sgRule.portRangeMin());
206 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
207 }
208
209 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
210 OpenstackSecurityGroupRule.Direction direction, Ip4Address vmIp) {
211 if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
212 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, 32));
213 } else {
214 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, 32));
215 }
216 }
217
218 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String ethertype) {
219 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
220 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
221 if (ethertype != null && ethertype != "null" &&
222 !ethertype.toUpperCase().equals(ETHTYPE_IPV4)) {
223 log.error("EthType {} is not supported yet in Security Group", ethertype);
224 }
225 }
226
227 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder, IpPrefix remoteIpPrefix,
228 OpenstackSecurityGroupRule.Direction direction) {
229 if (remoteIpPrefix != null && !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
230 if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
231 sBuilder.matchIPDst(remoteIpPrefix);
232 } else {
233 sBuilder.matchIPSrc(remoteIpPrefix);
234 }
235 }
236 }
237
238 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
239 if (protocol != null) {
240 switch (protocol.toUpperCase()) {
241 case PROTO_ICMP:
242 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
243 break;
244 case PROTO_TCP:
245 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
246 break;
247 case PROTO_UDP:
248 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
249 break;
250 default:
251 }
252 }
253 }
254
255 private void buildMatchPort(TrafficSelector.Builder sBuilder, String protocol,
256 OpenstackSecurityGroupRule.Direction direction,
257 int portMin, int portMax) {
258 if (portMin > 0 && portMax > 0 && portMin == portMax) {
259 if (protocol.toUpperCase().equals(PROTO_TCP)) {
260 if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
261 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
262 } else {
263 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
264 }
265 } else if (protocol.toUpperCase().equals(PROTO_UDP)) {
266 if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
267 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
268 } else {
269 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
270 }
271 }
272 }
273 }
274}