blob: e1f579e672b290215f6424db84f7d4808c8a5738 [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;
Jian Li62116942019-09-03 23:10:20 +090027import org.onosproject.net.PortNumber;
Daniel Park1099d142019-02-18 17:39:56 +090028import org.onosproject.net.device.DeviceService;
sanghodbee2332017-05-18 09:59:16 +090029import org.onosproject.net.flow.DefaultFlowRule;
30import org.onosproject.net.flow.DefaultTrafficSelector;
31import org.onosproject.net.flow.DefaultTrafficTreatment;
32import org.onosproject.net.flow.FlowRule;
33import org.onosproject.net.flow.FlowRuleOperations;
34import org.onosproject.net.flow.FlowRuleOperationsContext;
35import org.onosproject.net.flow.FlowRuleService;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.flow.TrafficTreatment;
sanghodbee2332017-05-18 09:59:16 +090038import org.onosproject.openstacknetworking.api.Constants;
39import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090040import org.onosproject.openstacknode.api.OpenstackNode;
41import org.onosproject.openstacknode.api.OpenstackNodeEvent;
42import org.onosproject.openstacknode.api.OpenstackNodeListener;
43import org.onosproject.openstacknode.api.OpenstackNodeService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070044import org.osgi.service.component.annotations.Activate;
45import org.osgi.service.component.annotations.Component;
46import org.osgi.service.component.annotations.Deactivate;
47import org.osgi.service.component.annotations.Reference;
48import org.osgi.service.component.annotations.ReferenceCardinality;
Daniel Park1099d142019-02-18 17:39:56 +090049import org.onosproject.openstacknode.api.OpenstackPhyInterface;
sanghodbee2332017-05-18 09:59:16 +090050import org.slf4j.Logger;
51
Jian Lia0778172018-07-16 22:50:19 +090052import java.util.Objects;
Daniel Park1099d142019-02-18 17:39:56 +090053import java.util.Optional;
sanghodbee2332017-05-18 09:59:16 +090054import java.util.concurrent.ExecutorService;
55import java.util.concurrent.Executors;
56
57import static org.onlab.util.Tools.groupedThreads;
Daniel Park1099d142019-02-18 17:39:56 +090058import static org.onosproject.net.AnnotationKeys.PORT_NAME;
59import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
sanghodbee2332017-05-18 09:59:16 +090060import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Daniel Park1099d142019-02-18 17:39:56 +090061import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
62import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
Jian Li62116942019-09-03 23:10:20 +090063import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.structurePortName;
64import static org.onosproject.openstacknode.api.Constants.INTEGRATION_TO_PHYSICAL_PREFIX;
Jian Lia0778172018-07-16 22:50:19 +090065import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
sanghodbee2332017-05-18 09:59:16 +090066import static org.slf4j.LoggerFactory.getLogger;
67
68/**
69 * Sets flow rules directly using FlowRuleService.
70 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071@Component(immediate = true, service = OpenstackFlowRuleService.class)
sanghodbee2332017-05-18 09:59:16 +090072public class OpenstackFlowRuleManager implements OpenstackFlowRuleService {
73
74 private final Logger log = getLogger(getClass());
75
76 private static final int DROP_PRIORITY = 0;
77 private static final int HIGH_PRIORITY = 30000;
sanghodc375372017-06-08 10:41:30 +090078 private static final int TIMEOUT_SNAT_RULE = 60;
sanghodbee2332017-05-18 09:59:16 +090079
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090081 protected FlowRuleService flowRuleService;
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090084 protected CoreService coreService;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia0778172018-07-16 22:50:19 +090087 protected ClusterService clusterService;
88
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lia0778172018-07-16 22:50:19 +090090 protected LeadershipService leadershipService;
91
Ray Milkeyd84f89b2018-08-17 14:54:17 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodbee2332017-05-18 09:59:16 +090093 protected OpenstackNodeService osNodeService;
94
Daniel Park1099d142019-02-18 17:39:56 +090095 @Reference(cardinality = ReferenceCardinality.MANDATORY)
96 protected DeviceService deviceService;
97
sanghodbee2332017-05-18 09:59:16 +090098 private final ExecutorService deviceEventExecutor =
Jian Lia0778172018-07-16 22:50:19 +090099 Executors.newSingleThreadExecutor(groupedThreads(
100 getClass().getSimpleName(), "device-event"));
101 private final OpenstackNodeListener internalNodeListener =
102 new InternalOpenstackNodeListener();
sanghodbee2332017-05-18 09:59:16 +0900103
104 private ApplicationId appId;
Jian Lia0778172018-07-16 22:50:19 +0900105 private NodeId localNodeId;
sanghodbee2332017-05-18 09:59:16 +0900106
107 @Activate
108 protected void activate() {
109 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
110 coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
111 osNodeService.addListener(internalNodeListener);
Jian Lia0778172018-07-16 22:50:19 +0900112 localNodeId = clusterService.getLocalNode().id();
113 leadershipService.runForLeadership(appId.name());
114 osNodeService.completeNodes(COMPUTE)
sanghoc395d0f2017-07-11 10:05:25 +0900115 .forEach(node -> initializePipeline(node.intgBridge()));
116
sanghodbee2332017-05-18 09:59:16 +0900117 log.info("Started");
118 }
119
120 @Deactivate
121 protected void deactivate() {
122 osNodeService.removeListener(internalNodeListener);
Jian Lia0778172018-07-16 22:50:19 +0900123 leadershipService.withdraw(appId.name());
sanghodbee2332017-05-18 09:59:16 +0900124 deviceEventExecutor.shutdown();
125
126 log.info("Stopped");
127 }
128
129 @Override
sanghodc375372017-06-08 10:41:30 +0900130 public void setRule(ApplicationId appId,
Jian Lia0778172018-07-16 22:50:19 +0900131 DeviceId deviceId,
132 TrafficSelector selector,
133 TrafficTreatment treatment,
134 int priority,
135 int tableType,
136 boolean install) {
sanghodbee2332017-05-18 09:59:16 +0900137
sanghodc375372017-06-08 10:41:30 +0900138 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder()
sanghodbee2332017-05-18 09:59:16 +0900139 .forDevice(deviceId)
sanghodc375372017-06-08 10:41:30 +0900140 .withSelector(selector)
141 .withTreatment(treatment)
142 .withPriority(priority)
143 .fromApp(appId)
sanghodbee2332017-05-18 09:59:16 +0900144 .forTable(tableType);
145
sanghodc375372017-06-08 10:41:30 +0900146 if (priority == Constants.PRIORITY_SNAT_RULE) {
147 flowRuleBuilder.makeTemporary(TIMEOUT_SNAT_RULE);
sanghodbee2332017-05-18 09:59:16 +0900148 } else {
sanghodc375372017-06-08 10:41:30 +0900149 flowRuleBuilder.makePermanent();
sanghodbee2332017-05-18 09:59:16 +0900150 }
151
sanghodc375372017-06-08 10:41:30 +0900152 applyRule(flowRuleBuilder.build(), install);
sanghodbee2332017-05-18 09:59:16 +0900153 }
154
sangho3dd2a8b2017-07-19 15:54:31 +0900155 @Override
156 public void connectTables(DeviceId deviceId, int fromTable, int toTable) {
sanghodbee2332017-05-18 09:59:16 +0900157 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
158 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
159
160 treatment.transition(toTable);
161
162 FlowRule flowRule = DefaultFlowRule.builder()
163 .forDevice(deviceId)
164 .withSelector(selector.build())
165 .withTreatment(treatment.build())
166 .withPriority(DROP_PRIORITY)
167 .fromApp(appId)
168 .makePermanent()
169 .forTable(fromTable)
170 .build();
171
sanghodc375372017-06-08 10:41:30 +0900172 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900173 }
174
sangho3dd2a8b2017-07-19 15:54:31 +0900175 @Override
176 public void setUpTableMissEntry(DeviceId deviceId, int table) {
sanghodbee2332017-05-18 09:59:16 +0900177 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
178 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
179
180 treatment.drop();
181
182 FlowRule flowRule = DefaultFlowRule.builder()
183 .forDevice(deviceId)
184 .withSelector(selector.build())
185 .withTreatment(treatment.build())
186 .withPriority(DROP_PRIORITY)
187 .fromApp(appId)
188 .makePermanent()
189 .forTable(table)
190 .build();
191
sanghodc375372017-06-08 10:41:30 +0900192 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900193 }
194
Jian Lia0778172018-07-16 22:50:19 +0900195 private void applyRule(FlowRule flowRule, boolean install) {
196 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
197
198 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
199
200 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
201 @Override
202 public void onSuccess(FlowRuleOperations ops) {
203 log.debug("Provisioned vni or forwarding table");
204 }
205
206 @Override
207 public void onError(FlowRuleOperations ops) {
208 log.debug("Failed to provision vni or forwarding table");
209 }
210 }));
211 }
212
213 protected void initializePipeline(DeviceId deviceId) {
214 // for inbound table transition
215 connectTables(deviceId, Constants.STAT_INBOUND_TABLE, Constants.VTAP_INBOUND_TABLE);
Jian Li5c09e212018-10-24 18:23:58 +0900216 connectTables(deviceId, Constants.VTAP_INBOUND_TABLE, Constants.DHCP_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900217
Jian Li5c09e212018-10-24 18:23:58 +0900218 // for DHCP and vTag table transition
219 connectTables(deviceId, Constants.DHCP_TABLE, Constants.VTAG_TABLE);
220
221 // for vTag and ARP table transition
222 connectTables(deviceId, Constants.VTAG_TABLE, Constants.ARP_TABLE);
223
224 // for ARP and ACL table transition
Jian Li1e9cb732018-11-25 23:17:21 +0900225 connectTables(deviceId, Constants.ARP_TABLE, Constants.ACL_INGRESS_TABLE);
Jian Li5c09e212018-10-24 18:23:58 +0900226
227 // for ACL and JUMP table transition
Jian Li1e9cb732018-11-25 23:17:21 +0900228 connectTables(deviceId, Constants.ACL_EGRESS_TABLE, Constants.JUMP_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900229
230 // for JUMP table transition
231 // we need JUMP table for bypassing routing table which contains large
232 // amount of flow rules which might cause performance degradation during
233 // table lookup
234 setupJumpTable(deviceId);
235
236 // for outbound table transition
Jian Li5ecfd1a2018-12-10 11:41:03 +0900237 connectTables(deviceId, Constants.STAT_OUTBOUND_TABLE,
238 Constants.VTAP_OUTBOUND_TABLE);
239 connectTables(deviceId, Constants.VTAP_OUTBOUND_TABLE,
240 Constants.FORWARDING_TABLE);
Jian Lia0778172018-07-16 22:50:19 +0900241
242 // for FLAT outbound table transition
Jian Li5ecfd1a2018-12-10 11:41:03 +0900243 connectTables(deviceId, Constants.STAT_FLAT_OUTBOUND_TABLE,
244 Constants.VTAP_FLAT_OUTBOUND_TABLE);
245 connectTables(deviceId, Constants.VTAP_FLAT_OUTBOUND_TABLE,
246 Constants.FLAT_TABLE);
Daniel Park1099d142019-02-18 17:39:56 +0900247
248 // for FLAT table drop
249 setUpTableMissEntry(deviceId, Constants.FLAT_TABLE);
250
251 // for FLAT jump rules
252 if (!osNodeService.node(deviceId).phyIntfs().isEmpty()) {
253 setFlatJumpRules(deviceId);
254 }
255 }
256
257 private void setFlatJumpRules(DeviceId deviceId) {
258 osNodeService.node(deviceId)
259 .phyIntfs()
260 .forEach(phyInterface ->
Jian Li62116942019-09-03 23:10:20 +0900261 setFlatJumpRulesForPatchPort(deviceId, phyInterface));
Daniel Park1099d142019-02-18 17:39:56 +0900262 }
263
Jian Li62116942019-09-03 23:10:20 +0900264 private void setFlatJumpRuleForPatchPort(DeviceId deviceId,
265 PortNumber portNumber, short ethType) {
266 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
267 selector.matchInPort(portNumber)
268 .matchEthType(ethType);
269
270 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
271 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
272 FlowRule flowRuleForIp = DefaultFlowRule.builder()
273 .forDevice(deviceId)
274 .withSelector(selector.build())
275 .withTreatment(treatment.build())
276 .withPriority(PRIORITY_FLAT_JUMP_UPSTREAM_RULE)
277 .fromApp(appId)
278 .makePermanent()
279 .forTable(DHCP_TABLE)
280 .build();
281
282 applyRule(flowRuleForIp, true);
283 }
284
285 private void setFlatJumpRulesForPatchPort(DeviceId deviceId,
286 OpenstackPhyInterface phyIntf) {
287 Optional<Port> patchPort = deviceService.getPorts(deviceId).stream()
288 .filter(port -> {
289 String annotPortName = port.annotations().value(PORT_NAME);
290 String portName = structurePortName(
291 INTEGRATION_TO_PHYSICAL_PREFIX + phyIntf.network());
292 return Objects.equals(annotPortName, portName);
293 })
Daniel Park1099d142019-02-18 17:39:56 +0900294 .findAny();
295
Jian Li62116942019-09-03 23:10:20 +0900296 patchPort.ifPresent(port -> {
297 setFlatJumpRuleForPatchPort(deviceId, port.number(), Ethernet.TYPE_IPV4);
298 setFlatJumpRuleForPatchPort(deviceId, port.number(), Ethernet.TYPE_ARP);
Daniel Park1099d142019-02-18 17:39:56 +0900299 });
Jian Lia0778172018-07-16 22:50:19 +0900300 }
301
sanghodbee2332017-05-18 09:59:16 +0900302 private void setupJumpTable(DeviceId deviceId) {
303 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
304 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
305
306 selector.matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
307 treatment.transition(Constants.ROUTING_TABLE);
308
309 FlowRule flowRule = DefaultFlowRule.builder()
310 .forDevice(deviceId)
311 .withSelector(selector.build())
312 .withTreatment(treatment.build())
313 .withPriority(HIGH_PRIORITY)
314 .fromApp(appId)
315 .makePermanent()
316 .forTable(Constants.JUMP_TABLE)
317 .build();
318
sanghodc375372017-06-08 10:41:30 +0900319 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900320
321 selector = DefaultTrafficSelector.builder();
322 treatment = DefaultTrafficTreatment.builder();
323
Jian Li8abf2fe2018-06-12 18:42:30 +0900324 treatment.transition(Constants.STAT_OUTBOUND_TABLE);
sanghodbee2332017-05-18 09:59:16 +0900325
326 flowRule = DefaultFlowRule.builder()
327 .forDevice(deviceId)
328 .withSelector(selector.build())
329 .withTreatment(treatment.build())
330 .withPriority(DROP_PRIORITY)
331 .fromApp(appId)
332 .makePermanent()
333 .forTable(Constants.JUMP_TABLE)
334 .build();
335
sanghodc375372017-06-08 10:41:30 +0900336 applyRule(flowRule, true);
sanghodbee2332017-05-18 09:59:16 +0900337 }
338
339 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
340
341 @Override
Jian Lia0778172018-07-16 22:50:19 +0900342 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Lifb64d882018-11-27 10:57:40 +0900343 return event.subject().type().equals(COMPUTE);
344 }
345
346 private boolean isRelevantHelper() {
347 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lia0778172018-07-16 22:50:19 +0900348 }
349
350 @Override
sanghodbee2332017-05-18 09:59:16 +0900351 public void event(OpenstackNodeEvent event) {
352 OpenstackNode osNode = event.subject();
sanghodbee2332017-05-18 09:59:16 +0900353
354 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900355 case OPENSTACK_NODE_COMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900356 deviceEventExecutor.execute(() -> {
357 log.info("COMPLETE node {} is detected", osNode.hostname());
Jian Lifb64d882018-11-27 10:57:40 +0900358
359 if (!isRelevantHelper()) {
360 return;
361 }
362
Jian Lia0778172018-07-16 22:50:19 +0900363 initializePipeline(osNode.intgBridge());
sanghodbee2332017-05-18 09:59:16 +0900364 });
365 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900366 case OPENSTACK_NODE_CREATED:
367 case OPENSTACK_NODE_UPDATED:
368 case OPENSTACK_NODE_REMOVED:
369 case OPENSTACK_NODE_INCOMPLETE:
sanghodbee2332017-05-18 09:59:16 +0900370 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900371 // do nothing
sanghodbee2332017-05-18 09:59:16 +0900372 break;
373 }
374 }
sanghodbee2332017-05-18 09:59:16 +0900375 }
376}