blob: 5608bce2fc5497bb92376624d1e960d167914a17 [file] [log] [blame]
sanghodbee2332017-05-18 09:59:16 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
sanghodbee2332017-05-18 09:59:16 +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.impl;
18
Daniel Park1099d142019-02-18 17:39:56 +090019import org.onlab.packet.Ethernet;
Jian Lia0778172018-07-16 22:50:19 +090020import org.onosproject.cluster.ClusterService;
21import org.onosproject.cluster.LeadershipService;
22import org.onosproject.cluster.NodeId;
sanghodbee2332017-05-18 09:59:16 +090023import org.onosproject.core.ApplicationId;
24import org.onosproject.core.CoreService;
25import org.onosproject.net.DeviceId;
Daniel Park1099d142019-02-18 17:39:56 +090026import org.onosproject.net.Port;
27import org.onosproject.net.device.DeviceService;
sanghodbee2332017-05-18 09:59:16 +090028import org.onosproject.net.flow.DefaultFlowRule;
29import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.DefaultTrafficTreatment;
31import org.onosproject.net.flow.FlowRule;
32import org.onosproject.net.flow.FlowRuleOperations;
33import org.onosproject.net.flow.FlowRuleOperationsContext;
34import org.onosproject.net.flow.FlowRuleService;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
sanghodbee2332017-05-18 09:59:16 +090037import org.onosproject.openstacknetworking.api.Constants;
38import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090039import org.onosproject.openstacknode.api.OpenstackNode;
40import org.onosproject.openstacknode.api.OpenstackNodeEvent;
41import org.onosproject.openstacknode.api.OpenstackNodeListener;
42import org.onosproject.openstacknode.api.OpenstackNodeService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070043import org.osgi.service.component.annotations.Activate;
44import org.osgi.service.component.annotations.Component;
45import org.osgi.service.component.annotations.Deactivate;
46import org.osgi.service.component.annotations.Reference;
47import org.osgi.service.component.annotations.ReferenceCardinality;
Daniel Park1099d142019-02-18 17:39:56 +090048import org.onosproject.openstacknode.api.OpenstackPhyInterface;
sanghodbee2332017-05-18 09:59:16 +090049import org.slf4j.Logger;
50
Jian Lia0778172018-07-16 22:50:19 +090051import java.util.Objects;
Daniel Park1099d142019-02-18 17:39:56 +090052import java.util.Optional;
sanghodbee2332017-05-18 09:59:16 +090053import java.util.concurrent.ExecutorService;
54import java.util.concurrent.Executors;
55
56import static org.onlab.util.Tools.groupedThreads;
Daniel Park1099d142019-02-18 17:39:56 +090057import static org.onosproject.net.AnnotationKeys.PORT_NAME;
58import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
sanghodbee2332017-05-18 09:59:16 +090059import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Daniel Park1099d142019-02-18 17:39:56 +090060import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
61import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Lia0778172018-07-16 22:50:19 +090062import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
sanghodbee2332017-05-18 09:59:16 +090063import static org.slf4j.LoggerFactory.getLogger;
64
65/**
66 * Sets flow rules directly using FlowRuleService.
67 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068@Component(immediate = true, service = OpenstackFlowRuleService.class)
sanghodbee2332017-05-18 09:59:16 +090069public class OpenstackFlowRuleManager implements OpenstackFlowRuleService {
70
71 private final Logger log = getLogger(getClass());
72
73 private static final int DROP_PRIORITY = 0;
74 private static final int HIGH_PRIORITY = 30000;
sanghodc375372017-06-08 10:41:30 +090075 private static final int TIMEOUT_SNAT_RULE = 60;
sanghodbee2332017-05-18 09:59:16 +090076
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090078 protected FlowRuleService flowRuleService;
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090081 protected CoreService coreService;
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia0778172018-07-16 22:50:19 +090084 protected ClusterService clusterService;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia0778172018-07-16 22:50:19 +090087 protected LeadershipService leadershipService;
88
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090090 protected OpenstackNodeService osNodeService;
91
Daniel Park1099d142019-02-18 17:39:56 +090092 @Reference(cardinality = ReferenceCardinality.MANDATORY)
93 protected DeviceService deviceService;
94
sanghodbee2332017-05-18 09:59:16 +090095 private final ExecutorService deviceEventExecutor =
Jian Lia0778172018-07-16 22:50:19 +090096 Executors.newSingleThreadExecutor(groupedThreads(
97 getClass().getSimpleName(), "device-event"));
98 private final OpenstackNodeListener internalNodeListener =
99 new InternalOpenstackNodeListener();
sanghodbee2332017-05-18 09:59:16 +0900100
101 private ApplicationId appId;
Jian Lia0778172018-07-16 22:50:19 +0900102 private NodeId localNodeId;
sanghodbee2332017-05-18 09:59:16 +0900103
104 @Activate
105 protected void activate() {
106 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
107 coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
108 osNodeService.addListener(internalNodeListener);
Jian Lia0778172018-07-16 22:50:19 +0900109 localNodeId = clusterService.getLocalNode().id();
110 leadershipService.runForLeadership(appId.name());
111 osNodeService.completeNodes(COMPUTE)
sanghoc395d0f2017-07-11 10:05:25 +0900112 .forEach(node -> initializePipeline(node.intgBridge()));
113
sanghodbee2332017-05-18 09:59:16 +0900114 log.info("Started");
115 }
116
117 @Deactivate
118 protected void deactivate() {
119 osNodeService.removeListener(internalNodeListener);
Jian Lia0778172018-07-16 22:50:19 +0900120 leadershipService.withdraw(appId.name());
sanghodbee2332017-05-18 09:59:16 +0900121 deviceEventExecutor.shutdown();
122
123 log.info("Stopped");
124 }
125
126 @Override
sanghodc375372017-06-08 10:41:30 +0900127 public void setRule(ApplicationId appId,
Jian Lia0778172018-07-16 22:50:19 +0900128 DeviceId deviceId,
129 TrafficSelector selector,
130 TrafficTreatment treatment,
131 int priority,
132 int tableType,
133 boolean install) {
sanghodbee2332017-05-18 09:59:16 +0900134
sanghodc375372017-06-08 10:41:30 +0900135 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder()
sanghodbee2332017-05-18 09:59:16 +0900136 .forDevice(deviceId)
sanghodc375372017-06-08 10:41:30 +0900137 .withSelector(selector)
138 .withTreatment(treatment)
139 .withPriority(priority)
140 .fromApp(appId)
sanghodbee2332017-05-18 09:59:16 +0900141 .forTable(tableType);
142
sanghodc375372017-06-08 10:41:30 +0900143 if (priority == Constants.PRIORITY_SNAT_RULE) {
144 flowRuleBuilder.makeTemporary(TIMEOUT_SNAT_RULE);
sanghodbee2332017-05-18 09:59:16 +0900145 } else {
sanghodc375372017-06-08 10:41:30 +0900146 flowRuleBuilder.makePermanent();
sanghodbee2332017-05-18 09:59:16 +0900147 }
148
sanghodc375372017-06-08 10:41:30 +0900149 applyRule(flowRuleBuilder.build(), install);
sanghodbee2332017-05-18 09:59:16 +0900150 }
151
sangho3dd2a8b2017-07-19 15:54:31 +0900152 @Override
153 public void connectTables(DeviceId deviceId, int fromTable, int toTable) {
sanghodbee2332017-05-18 09:59:16 +0900154 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
155 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
156
157 treatment.transition(toTable);
158
159 FlowRule flowRule = DefaultFlowRule.builder()
160 .forDevice(deviceId)
161 .withSelector(selector.build())
162 .withTreatment(treatment.build())
163 .withPriority(DROP_PRIORITY)
164 .fromApp(appId)
165 .makePermanent()
166 .forTable(fromTable)
167 .build();
168
sanghodc375372017-06-08 10:41:30 +0900169 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900170 }
171
sangho3dd2a8b2017-07-19 15:54:31 +0900172 @Override
173 public void setUpTableMissEntry(DeviceId deviceId, int table) {
sanghodbee2332017-05-18 09:59:16 +0900174 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
175 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
176
177 treatment.drop();
178
179 FlowRule flowRule = DefaultFlowRule.builder()
180 .forDevice(deviceId)
181 .withSelector(selector.build())
182 .withTreatment(treatment.build())
183 .withPriority(DROP_PRIORITY)
184 .fromApp(appId)
185 .makePermanent()
186 .forTable(table)
187 .build();
188
sanghodc375372017-06-08 10:41:30 +0900189 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900190 }
191
Jian Lia0778172018-07-16 22:50:19 +0900192 private void applyRule(FlowRule flowRule, boolean install) {
193 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
194
195 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
196
197 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
198 @Override
199 public void onSuccess(FlowRuleOperations ops) {
200 log.debug("Provisioned vni or forwarding table");
201 }
202
203 @Override
204 public void onError(FlowRuleOperations ops) {
205 log.debug("Failed to provision vni or forwarding table");
206 }
207 }));
208 }
209
210 protected void initializePipeline(DeviceId deviceId) {
211 // for inbound table transition
212 connectTables(deviceId, Constants.STAT_INBOUND_TABLE, Constants.VTAP_INBOUND_TABLE);
Jian Li5c09e212018-10-24 18:23:58 +0900213 connectTables(deviceId, Constants.VTAP_INBOUND_TABLE, Constants.DHCP_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900214
Jian Li5c09e212018-10-24 18:23:58 +0900215 // for DHCP and vTag table transition
216 connectTables(deviceId, Constants.DHCP_TABLE, Constants.VTAG_TABLE);
217
218 // for vTag and ARP table transition
219 connectTables(deviceId, Constants.VTAG_TABLE, Constants.ARP_TABLE);
220
221 // for ARP and ACL table transition
Jian Li1e9cb732018-11-25 23:17:21 +0900222 connectTables(deviceId, Constants.ARP_TABLE, Constants.ACL_INGRESS_TABLE);
Jian Li5c09e212018-10-24 18:23:58 +0900223
224 // for ACL and JUMP table transition
Jian Li1e9cb732018-11-25 23:17:21 +0900225 connectTables(deviceId, Constants.ACL_EGRESS_TABLE, Constants.JUMP_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900226
227 // for JUMP table transition
228 // we need JUMP table for bypassing routing table which contains large
229 // amount of flow rules which might cause performance degradation during
230 // table lookup
231 setupJumpTable(deviceId);
232
233 // for outbound table transition
Jian Li5ecfd1a2018-12-10 11:41:03 +0900234 connectTables(deviceId, Constants.STAT_OUTBOUND_TABLE,
235 Constants.VTAP_OUTBOUND_TABLE);
236 connectTables(deviceId, Constants.VTAP_OUTBOUND_TABLE,
237 Constants.FORWARDING_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900238
239 // for FLAT outbound table transition
Jian Li5ecfd1a2018-12-10 11:41:03 +0900240 connectTables(deviceId, Constants.STAT_FLAT_OUTBOUND_TABLE,
241 Constants.VTAP_FLAT_OUTBOUND_TABLE);
242 connectTables(deviceId, Constants.VTAP_FLAT_OUTBOUND_TABLE,
243 Constants.FLAT_TABLE);
Daniel Park1099d142019-02-18 17:39:56 +0900244
245 // for FLAT table drop
246 setUpTableMissEntry(deviceId, Constants.FLAT_TABLE);
247
248 // for FLAT jump rules
249 if (!osNodeService.node(deviceId).phyIntfs().isEmpty()) {
250 setFlatJumpRules(deviceId);
251 }
252 }
253
254 private void setFlatJumpRules(DeviceId deviceId) {
255 osNodeService.node(deviceId)
256 .phyIntfs()
257 .forEach(phyInterface ->
258 setFlatJumpRulesForPhyIntf(deviceId, phyInterface));
259 }
260
261 private void setFlatJumpRulesForPhyIntf(DeviceId deviceId,
262 OpenstackPhyInterface phyInterface) {
263 Optional<Port> phyPort = deviceService.getPorts(deviceId).stream()
264 .filter(port ->
265 Objects.equals(port.annotations().value(PORT_NAME), phyInterface.intf()))
266 .findAny();
267
268 phyPort.ifPresent(port -> {
269 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
270 selector.matchInPort(port.number())
271 .matchEthType(Ethernet.TYPE_IPV4);
272
273 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
274 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
275 FlowRule flowRuleForIp = DefaultFlowRule.builder()
276 .forDevice(deviceId)
277 .withSelector(selector.build())
278 .withTreatment(treatment.build())
279 .withPriority(PRIORITY_FLAT_JUMP_UPSTREAM_RULE)
280 .fromApp(appId)
281 .makePermanent()
282 .forTable(DHCP_TABLE)
283 .build();
284
285 applyRule(flowRuleForIp, true);
286
287 selector = DefaultTrafficSelector.builder();
288 selector.matchInPort(port.number())
289 .matchEthType(Ethernet.TYPE_ARP);
290
291 FlowRule flowRuleForArp = DefaultFlowRule.builder()
292 .forDevice(deviceId)
293 .withSelector(selector.build())
294 .withTreatment(treatment.build())
295 .withPriority(PRIORITY_FLAT_JUMP_UPSTREAM_RULE)
296 .fromApp(appId)
297 .makePermanent()
298 .forTable(DHCP_TABLE)
299 .build();
300
301 applyRule(flowRuleForArp, true);
302 });
Jian Lia0778172018-07-16 22:50:19 +0900303 }
304
sanghodbee2332017-05-18 09:59:16 +0900305 private void setupJumpTable(DeviceId deviceId) {
306 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
307 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
308
309 selector.matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
310 treatment.transition(Constants.ROUTING_TABLE);
311
312 FlowRule flowRule = DefaultFlowRule.builder()
313 .forDevice(deviceId)
314 .withSelector(selector.build())
315 .withTreatment(treatment.build())
316 .withPriority(HIGH_PRIORITY)
317 .fromApp(appId)
318 .makePermanent()
319 .forTable(Constants.JUMP_TABLE)
320 .build();
321
sanghodc375372017-06-08 10:41:30 +0900322 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900323
324 selector = DefaultTrafficSelector.builder();
325 treatment = DefaultTrafficTreatment.builder();
326
Jian Li8abf2fe2018-06-12 18:42:30 +0900327 treatment.transition(Constants.STAT_OUTBOUND_TABLE);
sanghodbee2332017-05-18 09:59:16 +0900328
329 flowRule = DefaultFlowRule.builder()
330 .forDevice(deviceId)
331 .withSelector(selector.build())
332 .withTreatment(treatment.build())
333 .withPriority(DROP_PRIORITY)
334 .fromApp(appId)
335 .makePermanent()
336 .forTable(Constants.JUMP_TABLE)
337 .build();
338
sanghodc375372017-06-08 10:41:30 +0900339 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900340 }
341
342 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
343
344 @Override
Jian Lia0778172018-07-16 22:50:19 +0900345 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Lifb64d882018-11-27 10:57:40 +0900346 return event.subject().type().equals(COMPUTE);
347 }
348
349 private boolean isRelevantHelper() {
350 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lia0778172018-07-16 22:50:19 +0900351 }
352
353 @Override
sanghodbee2332017-05-18 09:59:16 +0900354 public void event(OpenstackNodeEvent event) {
355 OpenstackNode osNode = event.subject();
sanghodbee2332017-05-18 09:59:16 +0900356
357 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900358 case OPENSTACK_NODE_COMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900359 deviceEventExecutor.execute(() -> {
360 log.info("COMPLETE node {} is detected", osNode.hostname());
Jian Lifb64d882018-11-27 10:57:40 +0900361
362 if (!isRelevantHelper()) {
363 return;
364 }
365
Jian Lia0778172018-07-16 22:50:19 +0900366 initializePipeline(osNode.intgBridge());
sanghodbee2332017-05-18 09:59:16 +0900367 });
368 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900369 case OPENSTACK_NODE_CREATED:
370 case OPENSTACK_NODE_UPDATED:
371 case OPENSTACK_NODE_REMOVED:
372 case OPENSTACK_NODE_INCOMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900373 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900374 // do nothing
sanghodbee2332017-05-18 09:59:16 +0900375 break;
376 }
377 }
sanghodbee2332017-05-18 09:59:16 +0900378 }
379}