blob: 2ea740075b02e2b6c8b38b2ec85b423aec4d5444 [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);
201 connectTables(deviceId, Constants.VTAP_INBOUND_TABLE, Constants.DHCP_ARP_TABLE);
202
203 // for vTag and ACL table transition
204 connectTables(deviceId, Constants.DHCP_ARP_TABLE, Constants.VTAG_TABLE);
205 connectTables(deviceId, Constants.VTAG_TABLE, Constants.ACL_TABLE);
206 connectTables(deviceId, Constants.ACL_TABLE, Constants.JUMP_TABLE);
207
208 // for JUMP table transition
209 // we need JUMP table for bypassing routing table which contains large
210 // amount of flow rules which might cause performance degradation during
211 // table lookup
212 setupJumpTable(deviceId);
213
214 // for outbound table transition
215 connectTables(deviceId, Constants.STAT_OUTBOUND_TABLE, Constants.VTAP_OUTBOUND_TABLE);
216 connectTables(deviceId, Constants.VTAP_OUTBOUND_TABLE, Constants.FORWARDING_TABLE);
217
218 // for FLAT outbound table transition
219 connectTables(deviceId, Constants.STAT_FLAT_OUTBOUND_TABLE, Constants.VTAP_FLAT_OUTBOUND_TABLE);
220 connectTables(deviceId, Constants.VTAP_FLAT_OUTBOUND_TABLE, Constants.FLAT_TABLE);
221 }
222
sanghodbee2332017-05-18 09:59:16 +0900223 private void setupJumpTable(DeviceId deviceId) {
224 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
225 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
226
227 selector.matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
228 treatment.transition(Constants.ROUTING_TABLE);
229
230 FlowRule flowRule = DefaultFlowRule.builder()
231 .forDevice(deviceId)
232 .withSelector(selector.build())
233 .withTreatment(treatment.build())
234 .withPriority(HIGH_PRIORITY)
235 .fromApp(appId)
236 .makePermanent()
237 .forTable(Constants.JUMP_TABLE)
238 .build();
239
sanghodc375372017-06-08 10:41:30 +0900240 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900241
242 selector = DefaultTrafficSelector.builder();
243 treatment = DefaultTrafficTreatment.builder();
244
Jian Li8abf2fe2018-06-12 18:42:30 +0900245 treatment.transition(Constants.STAT_OUTBOUND_TABLE);
sanghodbee2332017-05-18 09:59:16 +0900246
247 flowRule = DefaultFlowRule.builder()
248 .forDevice(deviceId)
249 .withSelector(selector.build())
250 .withTreatment(treatment.build())
251 .withPriority(DROP_PRIORITY)
252 .fromApp(appId)
253 .makePermanent()
254 .forTable(Constants.JUMP_TABLE)
255 .build();
256
sanghodc375372017-06-08 10:41:30 +0900257 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900258 }
259
260 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
261
262 @Override
Jian Lia0778172018-07-16 22:50:19 +0900263 public boolean isRelevant(OpenstackNodeEvent event) {
264 // do not allow to proceed without leadership
265 NodeId leader = leadershipService.getLeader(appId.name());
266 return Objects.equals(localNodeId, leader) &&
267 event.subject().type().equals(COMPUTE);
268 }
269
270 @Override
sanghodbee2332017-05-18 09:59:16 +0900271 public void event(OpenstackNodeEvent event) {
272 OpenstackNode osNode = event.subject();
sanghodbee2332017-05-18 09:59:16 +0900273
274 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900275 case OPENSTACK_NODE_COMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900276 deviceEventExecutor.execute(() -> {
277 log.info("COMPLETE node {} is detected", osNode.hostname());
Jian Lia0778172018-07-16 22:50:19 +0900278 initializePipeline(osNode.intgBridge());
sanghodbee2332017-05-18 09:59:16 +0900279 });
280 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900281 case OPENSTACK_NODE_CREATED:
282 case OPENSTACK_NODE_UPDATED:
283 case OPENSTACK_NODE_REMOVED:
284 case OPENSTACK_NODE_INCOMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900285 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900286 // do nothing
sanghodbee2332017-05-18 09:59:16 +0900287 break;
288 }
289 }
sanghodbee2332017-05-18 09:59:16 +0900290 }
291}