blob: b2d83cd55230b0992ac1011c6536d313f8859291 [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;
Jian Li62116942019-09-03 23:10:20 +090025import org.onosproject.net.PortNumber;
Daniel Park1099d142019-02-18 17:39:56 +090026import org.onosproject.net.device.DeviceService;
sanghodbee2332017-05-18 09:59:16 +090027import org.onosproject.net.flow.DefaultFlowRule;
28import org.onosproject.net.flow.DefaultTrafficSelector;
29import org.onosproject.net.flow.DefaultTrafficTreatment;
30import org.onosproject.net.flow.FlowRule;
31import org.onosproject.net.flow.FlowRuleOperations;
32import org.onosproject.net.flow.FlowRuleOperationsContext;
33import org.onosproject.net.flow.FlowRuleService;
34import org.onosproject.net.flow.TrafficSelector;
35import org.onosproject.net.flow.TrafficTreatment;
sanghodbee2332017-05-18 09:59:16 +090036import org.onosproject.openstacknetworking.api.Constants;
37import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090038import org.onosproject.openstacknode.api.OpenstackNode;
39import org.onosproject.openstacknode.api.OpenstackNodeEvent;
40import org.onosproject.openstacknode.api.OpenstackNodeListener;
41import org.onosproject.openstacknode.api.OpenstackNodeService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070042import org.osgi.service.component.annotations.Activate;
43import org.osgi.service.component.annotations.Component;
44import org.osgi.service.component.annotations.Deactivate;
45import org.osgi.service.component.annotations.Reference;
46import org.osgi.service.component.annotations.ReferenceCardinality;
sanghodbee2332017-05-18 09:59:16 +090047import org.slf4j.Logger;
48
Jian Lia0778172018-07-16 22:50:19 +090049import java.util.Objects;
sanghodbee2332017-05-18 09:59:16 +090050import java.util.concurrent.ExecutorService;
51import java.util.concurrent.Executors;
52
53import static org.onlab.util.Tools.groupedThreads;
54import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lia0778172018-07-16 22:50:19 +090055import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
sanghodbee2332017-05-18 09:59:16 +090056import static org.slf4j.LoggerFactory.getLogger;
57
58/**
59 * Sets flow rules directly using FlowRuleService.
60 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061@Component(immediate = true, service = OpenstackFlowRuleService.class)
sanghodbee2332017-05-18 09:59:16 +090062public class OpenstackFlowRuleManager implements OpenstackFlowRuleService {
63
64 private final Logger log = getLogger(getClass());
65
66 private static final int DROP_PRIORITY = 0;
Jian Li1cfad062020-12-11 21:34:41 +090067 private static final int LOW_PRIORITY = 10000;
68 private static final int MID_PRIORITY = 20000;
sanghodbee2332017-05-18 09:59:16 +090069 private static final int HIGH_PRIORITY = 30000;
sanghodc375372017-06-08 10:41:30 +090070 private static final int TIMEOUT_SNAT_RULE = 60;
sanghodbee2332017-05-18 09:59:16 +090071
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090073 protected FlowRuleService flowRuleService;
74
Ray Milkeyd84f89b2018-08-17 14:54:17 -070075 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090076 protected CoreService coreService;
77
Ray Milkeyd84f89b2018-08-17 14:54:17 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia0778172018-07-16 22:50:19 +090079 protected ClusterService clusterService;
80
Ray Milkeyd84f89b2018-08-17 14:54:17 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia0778172018-07-16 22:50:19 +090082 protected LeadershipService leadershipService;
83
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090085 protected OpenstackNodeService osNodeService;
86
Daniel Park1099d142019-02-18 17:39:56 +090087 @Reference(cardinality = ReferenceCardinality.MANDATORY)
88 protected DeviceService deviceService;
89
sanghodbee2332017-05-18 09:59:16 +090090 private final ExecutorService deviceEventExecutor =
Jian Lia0778172018-07-16 22:50:19 +090091 Executors.newSingleThreadExecutor(groupedThreads(
92 getClass().getSimpleName(), "device-event"));
93 private final OpenstackNodeListener internalNodeListener =
94 new InternalOpenstackNodeListener();
sanghodbee2332017-05-18 09:59:16 +090095
96 private ApplicationId appId;
Jian Lia0778172018-07-16 22:50:19 +090097 private NodeId localNodeId;
sanghodbee2332017-05-18 09:59:16 +090098
99 @Activate
100 protected void activate() {
101 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
102 coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
103 osNodeService.addListener(internalNodeListener);
Jian Lia0778172018-07-16 22:50:19 +0900104 localNodeId = clusterService.getLocalNode().id();
105 leadershipService.runForLeadership(appId.name());
106 osNodeService.completeNodes(COMPUTE)
sanghoc395d0f2017-07-11 10:05:25 +0900107 .forEach(node -> initializePipeline(node.intgBridge()));
108
sanghodbee2332017-05-18 09:59:16 +0900109 log.info("Started");
110 }
111
112 @Deactivate
113 protected void deactivate() {
114 osNodeService.removeListener(internalNodeListener);
Jian Lia0778172018-07-16 22:50:19 +0900115 leadershipService.withdraw(appId.name());
sanghodbee2332017-05-18 09:59:16 +0900116 deviceEventExecutor.shutdown();
117
118 log.info("Stopped");
119 }
120
121 @Override
sanghodc375372017-06-08 10:41:30 +0900122 public void setRule(ApplicationId appId,
Jian Lia0778172018-07-16 22:50:19 +0900123 DeviceId deviceId,
124 TrafficSelector selector,
125 TrafficTreatment treatment,
126 int priority,
127 int tableType,
128 boolean install) {
sanghodbee2332017-05-18 09:59:16 +0900129
sanghodc375372017-06-08 10:41:30 +0900130 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder()
sanghodbee2332017-05-18 09:59:16 +0900131 .forDevice(deviceId)
sanghodc375372017-06-08 10:41:30 +0900132 .withSelector(selector)
133 .withTreatment(treatment)
134 .withPriority(priority)
135 .fromApp(appId)
sanghodbee2332017-05-18 09:59:16 +0900136 .forTable(tableType);
137
sanghodc375372017-06-08 10:41:30 +0900138 if (priority == Constants.PRIORITY_SNAT_RULE) {
139 flowRuleBuilder.makeTemporary(TIMEOUT_SNAT_RULE);
sanghodbee2332017-05-18 09:59:16 +0900140 } else {
sanghodc375372017-06-08 10:41:30 +0900141 flowRuleBuilder.makePermanent();
sanghodbee2332017-05-18 09:59:16 +0900142 }
143
sanghodc375372017-06-08 10:41:30 +0900144 applyRule(flowRuleBuilder.build(), install);
sanghodbee2332017-05-18 09:59:16 +0900145 }
146
sangho3dd2a8b2017-07-19 15:54:31 +0900147 @Override
148 public void connectTables(DeviceId deviceId, int fromTable, int toTable) {
sanghodbee2332017-05-18 09:59:16 +0900149 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
150 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
151
152 treatment.transition(toTable);
153
154 FlowRule flowRule = DefaultFlowRule.builder()
155 .forDevice(deviceId)
156 .withSelector(selector.build())
157 .withTreatment(treatment.build())
158 .withPriority(DROP_PRIORITY)
159 .fromApp(appId)
160 .makePermanent()
161 .forTable(fromTable)
162 .build();
163
sanghodc375372017-06-08 10:41:30 +0900164 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900165 }
166
sangho3dd2a8b2017-07-19 15:54:31 +0900167 @Override
168 public void setUpTableMissEntry(DeviceId deviceId, int table) {
sanghodbee2332017-05-18 09:59:16 +0900169 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
170 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
171
172 treatment.drop();
173
174 FlowRule flowRule = DefaultFlowRule.builder()
175 .forDevice(deviceId)
176 .withSelector(selector.build())
177 .withTreatment(treatment.build())
178 .withPriority(DROP_PRIORITY)
179 .fromApp(appId)
180 .makePermanent()
181 .forTable(table)
182 .build();
183
sanghodc375372017-06-08 10:41:30 +0900184 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900185 }
186
Jian Lia0778172018-07-16 22:50:19 +0900187 private void applyRule(FlowRule flowRule, boolean install) {
188 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
189
190 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
191
192 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
193 @Override
194 public void onSuccess(FlowRuleOperations ops) {
195 log.debug("Provisioned vni or forwarding table");
196 }
197
198 @Override
199 public void onError(FlowRuleOperations ops) {
200 log.debug("Failed to provision vni or forwarding table");
201 }
202 }));
203 }
204
205 protected void initializePipeline(DeviceId deviceId) {
206 // for inbound table transition
207 connectTables(deviceId, Constants.STAT_INBOUND_TABLE, Constants.VTAP_INBOUND_TABLE);
Jian Li5c09e212018-10-24 18:23:58 +0900208 connectTables(deviceId, Constants.VTAP_INBOUND_TABLE, Constants.DHCP_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900209
Jian Li5c09e212018-10-24 18:23:58 +0900210 // for DHCP and vTag table transition
211 connectTables(deviceId, Constants.DHCP_TABLE, Constants.VTAG_TABLE);
212
213 // for vTag and ARP table transition
214 connectTables(deviceId, Constants.VTAG_TABLE, Constants.ARP_TABLE);
215
216 // for ARP and ACL table transition
Jian Li1e9cb732018-11-25 23:17:21 +0900217 connectTables(deviceId, Constants.ARP_TABLE, Constants.ACL_INGRESS_TABLE);
Jian Li5c09e212018-10-24 18:23:58 +0900218
219 // for ACL and JUMP table transition
Jian Li1e9cb732018-11-25 23:17:21 +0900220 connectTables(deviceId, Constants.ACL_EGRESS_TABLE, Constants.JUMP_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900221
222 // for JUMP table transition
223 // we need JUMP table for bypassing routing table which contains large
224 // amount of flow rules which might cause performance degradation during
225 // table lookup
226 setupJumpTable(deviceId);
227
Jian Li1cfad062020-12-11 21:34:41 +0900228 // for setting up default FLAT table behavior which is NORMAL
229 setupFlatTable(deviceId);
230
Jian Lia0778172018-07-16 22:50:19 +0900231 // for outbound table transition
Jian Li5ecfd1a2018-12-10 11:41:03 +0900232 connectTables(deviceId, Constants.STAT_OUTBOUND_TABLE,
233 Constants.VTAP_OUTBOUND_TABLE);
234 connectTables(deviceId, Constants.VTAP_OUTBOUND_TABLE,
235 Constants.FORWARDING_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900236
Jian Li1cfad062020-12-11 21:34:41 +0900237 // for PRE_FLAT and FLAT table transition
238 connectTables(deviceId, Constants.PRE_FLAT_TABLE, Constants.FLAT_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900239 }
240
sanghodbee2332017-05-18 09:59:16 +0900241 private void setupJumpTable(DeviceId deviceId) {
242 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
243 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
244
245 selector.matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
246 treatment.transition(Constants.ROUTING_TABLE);
247
248 FlowRule flowRule = DefaultFlowRule.builder()
249 .forDevice(deviceId)
250 .withSelector(selector.build())
251 .withTreatment(treatment.build())
252 .withPriority(HIGH_PRIORITY)
253 .fromApp(appId)
254 .makePermanent()
255 .forTable(Constants.JUMP_TABLE)
256 .build();
257
sanghodc375372017-06-08 10:41:30 +0900258 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900259
260 selector = DefaultTrafficSelector.builder();
261 treatment = DefaultTrafficTreatment.builder();
262
Jian Li8abf2fe2018-06-12 18:42:30 +0900263 treatment.transition(Constants.STAT_OUTBOUND_TABLE);
sanghodbee2332017-05-18 09:59:16 +0900264
265 flowRule = DefaultFlowRule.builder()
266 .forDevice(deviceId)
267 .withSelector(selector.build())
268 .withTreatment(treatment.build())
269 .withPriority(DROP_PRIORITY)
270 .fromApp(appId)
271 .makePermanent()
272 .forTable(Constants.JUMP_TABLE)
273 .build();
274
sanghodc375372017-06-08 10:41:30 +0900275 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900276 }
277
Jian Li1cfad062020-12-11 21:34:41 +0900278 private void setupFlatTable(DeviceId deviceId) {
279 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
280 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
281 .setOutput(PortNumber.NORMAL);
282
283 FlowRule flowRule = DefaultFlowRule.builder()
284 .forDevice(deviceId)
285 .withSelector(selector.build())
286 .withTreatment(treatment.build())
287 .withPriority(LOW_PRIORITY)
288 .fromApp(appId)
289 .makePermanent()
290 .forTable(Constants.FLAT_TABLE)
291 .build();
292
293 applyRule(flowRule, true);
294 }
295
sanghodbee2332017-05-18 09:59:16 +0900296 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
297
298 @Override
Jian Lia0778172018-07-16 22:50:19 +0900299 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Lifb64d882018-11-27 10:57:40 +0900300 return event.subject().type().equals(COMPUTE);
301 }
302
303 private boolean isRelevantHelper() {
304 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lia0778172018-07-16 22:50:19 +0900305 }
306
307 @Override
sanghodbee2332017-05-18 09:59:16 +0900308 public void event(OpenstackNodeEvent event) {
309 OpenstackNode osNode = event.subject();
sanghodbee2332017-05-18 09:59:16 +0900310
311 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900312 case OPENSTACK_NODE_COMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900313 deviceEventExecutor.execute(() -> {
314 log.info("COMPLETE node {} is detected", osNode.hostname());
Jian Lifb64d882018-11-27 10:57:40 +0900315
316 if (!isRelevantHelper()) {
317 return;
318 }
319
Jian Lia0778172018-07-16 22:50:19 +0900320 initializePipeline(osNode.intgBridge());
sanghodbee2332017-05-18 09:59:16 +0900321 });
322 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900323 case OPENSTACK_NODE_CREATED:
324 case OPENSTACK_NODE_UPDATED:
325 case OPENSTACK_NODE_REMOVED:
326 case OPENSTACK_NODE_INCOMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900327 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900328 // do nothing
sanghodbee2332017-05-18 09:59:16 +0900329 break;
330 }
331 }
sanghodbee2332017-05-18 09:59:16 +0900332 }
333}