blob: 1858ab97a7d2a1212c87f020c0b9ebc770d21005 [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
Jian Lia0778172018-07-16 22:50:19 +090019import org.onosproject.cluster.ClusterService;
20import org.onosproject.cluster.LeadershipService;
21import org.onosproject.cluster.NodeId;
sanghodbee2332017-05-18 09:59:16 +090022import org.onosproject.core.ApplicationId;
23import org.onosproject.core.CoreService;
24import org.onosproject.net.DeviceId;
25import org.onosproject.net.flow.DefaultFlowRule;
26import org.onosproject.net.flow.DefaultTrafficSelector;
27import org.onosproject.net.flow.DefaultTrafficTreatment;
28import org.onosproject.net.flow.FlowRule;
29import org.onosproject.net.flow.FlowRuleOperations;
30import org.onosproject.net.flow.FlowRuleOperationsContext;
31import org.onosproject.net.flow.FlowRuleService;
32import org.onosproject.net.flow.TrafficSelector;
33import org.onosproject.net.flow.TrafficTreatment;
sanghodbee2332017-05-18 09:59:16 +090034import org.onosproject.openstacknetworking.api.Constants;
35import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090036import org.onosproject.openstacknode.api.OpenstackNode;
37import org.onosproject.openstacknode.api.OpenstackNodeEvent;
38import org.onosproject.openstacknode.api.OpenstackNodeListener;
39import org.onosproject.openstacknode.api.OpenstackNodeService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070040import org.osgi.service.component.annotations.Activate;
41import org.osgi.service.component.annotations.Component;
42import org.osgi.service.component.annotations.Deactivate;
43import org.osgi.service.component.annotations.Reference;
44import org.osgi.service.component.annotations.ReferenceCardinality;
sanghodbee2332017-05-18 09:59:16 +090045import org.slf4j.Logger;
46
Jian Lia0778172018-07-16 22:50:19 +090047import java.util.Objects;
sanghodbee2332017-05-18 09:59:16 +090048import java.util.concurrent.ExecutorService;
49import java.util.concurrent.Executors;
50
51import static org.onlab.util.Tools.groupedThreads;
52import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lia0778172018-07-16 22:50:19 +090053import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
sanghodbee2332017-05-18 09:59:16 +090054import static org.slf4j.LoggerFactory.getLogger;
55
56/**
57 * Sets flow rules directly using FlowRuleService.
58 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070059@Component(immediate = true, service = OpenstackFlowRuleService.class)
sanghodbee2332017-05-18 09:59:16 +090060public class OpenstackFlowRuleManager implements OpenstackFlowRuleService {
61
62 private final Logger log = getLogger(getClass());
63
64 private static final int DROP_PRIORITY = 0;
65 private static final int HIGH_PRIORITY = 30000;
sanghodc375372017-06-08 10:41:30 +090066 private static final int TIMEOUT_SNAT_RULE = 60;
sanghodbee2332017-05-18 09:59:16 +090067
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090069 protected FlowRuleService flowRuleService;
70
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090072 protected CoreService coreService;
73
Ray Milkeyd84f89b2018-08-17 14:54:17 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia0778172018-07-16 22:50:19 +090075 protected ClusterService clusterService;
76
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia0778172018-07-16 22:50:19 +090078 protected LeadershipService leadershipService;
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090081 protected OpenstackNodeService osNodeService;
82
83 private final ExecutorService deviceEventExecutor =
Jian Lia0778172018-07-16 22:50:19 +090084 Executors.newSingleThreadExecutor(groupedThreads(
85 getClass().getSimpleName(), "device-event"));
86 private final OpenstackNodeListener internalNodeListener =
87 new InternalOpenstackNodeListener();
sanghodbee2332017-05-18 09:59:16 +090088
89 private ApplicationId appId;
Jian Lia0778172018-07-16 22:50:19 +090090 private NodeId localNodeId;
sanghodbee2332017-05-18 09:59:16 +090091
92 @Activate
93 protected void activate() {
94 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
95 coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
96 osNodeService.addListener(internalNodeListener);
Jian Lia0778172018-07-16 22:50:19 +090097 localNodeId = clusterService.getLocalNode().id();
98 leadershipService.runForLeadership(appId.name());
99 osNodeService.completeNodes(COMPUTE)
sanghoc395d0f2017-07-11 10:05:25 +0900100 .forEach(node -> initializePipeline(node.intgBridge()));
101
sanghodbee2332017-05-18 09:59:16 +0900102 log.info("Started");
103 }
104
105 @Deactivate
106 protected void deactivate() {
107 osNodeService.removeListener(internalNodeListener);
Jian Lia0778172018-07-16 22:50:19 +0900108 leadershipService.withdraw(appId.name());
sanghodbee2332017-05-18 09:59:16 +0900109 deviceEventExecutor.shutdown();
110
111 log.info("Stopped");
112 }
113
114 @Override
sanghodc375372017-06-08 10:41:30 +0900115 public void setRule(ApplicationId appId,
Jian Lia0778172018-07-16 22:50:19 +0900116 DeviceId deviceId,
117 TrafficSelector selector,
118 TrafficTreatment treatment,
119 int priority,
120 int tableType,
121 boolean install) {
sanghodbee2332017-05-18 09:59:16 +0900122
sanghodc375372017-06-08 10:41:30 +0900123 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder()
sanghodbee2332017-05-18 09:59:16 +0900124 .forDevice(deviceId)
sanghodc375372017-06-08 10:41:30 +0900125 .withSelector(selector)
126 .withTreatment(treatment)
127 .withPriority(priority)
128 .fromApp(appId)
sanghodbee2332017-05-18 09:59:16 +0900129 .forTable(tableType);
130
sanghodc375372017-06-08 10:41:30 +0900131 if (priority == Constants.PRIORITY_SNAT_RULE) {
132 flowRuleBuilder.makeTemporary(TIMEOUT_SNAT_RULE);
sanghodbee2332017-05-18 09:59:16 +0900133 } else {
sanghodc375372017-06-08 10:41:30 +0900134 flowRuleBuilder.makePermanent();
sanghodbee2332017-05-18 09:59:16 +0900135 }
136
sanghodc375372017-06-08 10:41:30 +0900137 applyRule(flowRuleBuilder.build(), install);
sanghodbee2332017-05-18 09:59:16 +0900138 }
139
sangho3dd2a8b2017-07-19 15:54:31 +0900140 @Override
141 public void connectTables(DeviceId deviceId, int fromTable, int toTable) {
sanghodbee2332017-05-18 09:59:16 +0900142 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
143 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
144
145 treatment.transition(toTable);
146
147 FlowRule flowRule = DefaultFlowRule.builder()
148 .forDevice(deviceId)
149 .withSelector(selector.build())
150 .withTreatment(treatment.build())
151 .withPriority(DROP_PRIORITY)
152 .fromApp(appId)
153 .makePermanent()
154 .forTable(fromTable)
155 .build();
156
sanghodc375372017-06-08 10:41:30 +0900157 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900158 }
159
sangho3dd2a8b2017-07-19 15:54:31 +0900160 @Override
161 public void setUpTableMissEntry(DeviceId deviceId, int table) {
sanghodbee2332017-05-18 09:59:16 +0900162 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
163 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
164
165 treatment.drop();
166
167 FlowRule flowRule = DefaultFlowRule.builder()
168 .forDevice(deviceId)
169 .withSelector(selector.build())
170 .withTreatment(treatment.build())
171 .withPriority(DROP_PRIORITY)
172 .fromApp(appId)
173 .makePermanent()
174 .forTable(table)
175 .build();
176
sanghodc375372017-06-08 10:41:30 +0900177 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900178 }
179
Jian Lia0778172018-07-16 22:50:19 +0900180 private void applyRule(FlowRule flowRule, boolean install) {
181 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
182
183 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
184
185 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
186 @Override
187 public void onSuccess(FlowRuleOperations ops) {
188 log.debug("Provisioned vni or forwarding table");
189 }
190
191 @Override
192 public void onError(FlowRuleOperations ops) {
193 log.debug("Failed to provision vni or forwarding table");
194 }
195 }));
196 }
197
198 protected void initializePipeline(DeviceId deviceId) {
199 // for inbound table transition
200 connectTables(deviceId, Constants.STAT_INBOUND_TABLE, Constants.VTAP_INBOUND_TABLE);
Jian Li5c09e212018-10-24 18:23:58 +0900201 connectTables(deviceId, Constants.VTAP_INBOUND_TABLE, Constants.DHCP_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900202
Jian Li5c09e212018-10-24 18:23:58 +0900203 // for DHCP and vTag table transition
204 connectTables(deviceId, Constants.DHCP_TABLE, Constants.VTAG_TABLE);
205
206 // for vTag and ARP table transition
207 connectTables(deviceId, Constants.VTAG_TABLE, Constants.ARP_TABLE);
208
209 // for ARP and ACL table transition
Jian Li1e9cb732018-11-25 23:17:21 +0900210 connectTables(deviceId, Constants.ARP_TABLE, Constants.ACL_INGRESS_TABLE);
Jian Li5c09e212018-10-24 18:23:58 +0900211
212 // for ACL and JUMP table transition
Jian Li1e9cb732018-11-25 23:17:21 +0900213 connectTables(deviceId, Constants.ACL_EGRESS_TABLE, Constants.JUMP_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900214
215 // for JUMP table transition
216 // we need JUMP table for bypassing routing table which contains large
217 // amount of flow rules which might cause performance degradation during
218 // table lookup
219 setupJumpTable(deviceId);
220
221 // for outbound table transition
Jian Li5ecfd1a2018-12-10 11:41:03 +0900222 connectTables(deviceId, Constants.STAT_OUTBOUND_TABLE,
223 Constants.VTAP_OUTBOUND_TABLE);
224 connectTables(deviceId, Constants.VTAP_OUTBOUND_TABLE,
225 Constants.FORWARDING_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900226
227 // for FLAT outbound table transition
Jian Li5ecfd1a2018-12-10 11:41:03 +0900228 connectTables(deviceId, Constants.STAT_FLAT_OUTBOUND_TABLE,
229 Constants.VTAP_FLAT_OUTBOUND_TABLE);
230 connectTables(deviceId, Constants.VTAP_FLAT_OUTBOUND_TABLE,
231 Constants.FLAT_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900232 }
233
sanghodbee2332017-05-18 09:59:16 +0900234 private void setupJumpTable(DeviceId deviceId) {
235 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
236 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
237
238 selector.matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
239 treatment.transition(Constants.ROUTING_TABLE);
240
241 FlowRule flowRule = DefaultFlowRule.builder()
242 .forDevice(deviceId)
243 .withSelector(selector.build())
244 .withTreatment(treatment.build())
245 .withPriority(HIGH_PRIORITY)
246 .fromApp(appId)
247 .makePermanent()
248 .forTable(Constants.JUMP_TABLE)
249 .build();
250
sanghodc375372017-06-08 10:41:30 +0900251 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900252
253 selector = DefaultTrafficSelector.builder();
254 treatment = DefaultTrafficTreatment.builder();
255
Jian Li8abf2fe2018-06-12 18:42:30 +0900256 treatment.transition(Constants.STAT_OUTBOUND_TABLE);
sanghodbee2332017-05-18 09:59:16 +0900257
258 flowRule = DefaultFlowRule.builder()
259 .forDevice(deviceId)
260 .withSelector(selector.build())
261 .withTreatment(treatment.build())
262 .withPriority(DROP_PRIORITY)
263 .fromApp(appId)
264 .makePermanent()
265 .forTable(Constants.JUMP_TABLE)
266 .build();
267
sanghodc375372017-06-08 10:41:30 +0900268 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900269 }
270
271 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
272
273 @Override
Jian Lia0778172018-07-16 22:50:19 +0900274 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Lifb64d882018-11-27 10:57:40 +0900275 return event.subject().type().equals(COMPUTE);
276 }
277
278 private boolean isRelevantHelper() {
279 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lia0778172018-07-16 22:50:19 +0900280 }
281
282 @Override
sanghodbee2332017-05-18 09:59:16 +0900283 public void event(OpenstackNodeEvent event) {
284 OpenstackNode osNode = event.subject();
sanghodbee2332017-05-18 09:59:16 +0900285
286 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900287 case OPENSTACK_NODE_COMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900288 deviceEventExecutor.execute(() -> {
289 log.info("COMPLETE node {} is detected", osNode.hostname());
Jian Lifb64d882018-11-27 10:57:40 +0900290
291 if (!isRelevantHelper()) {
292 return;
293 }
294
Jian Lia0778172018-07-16 22:50:19 +0900295 initializePipeline(osNode.intgBridge());
sanghodbee2332017-05-18 09:59:16 +0900296 });
297 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900298 case OPENSTACK_NODE_CREATED:
299 case OPENSTACK_NODE_UPDATED:
300 case OPENSTACK_NODE_REMOVED:
301 case OPENSTACK_NODE_INCOMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900302 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900303 // do nothing
sanghodbee2332017-05-18 09:59:16 +0900304 break;
305 }
306 }
sanghodbee2332017-05-18 09:59:16 +0900307 }
308}