blob: 6e8e7e09555c4e862aa4cf3b76a56f3d15dc6287 [file] [log] [blame]
sanghodbee2332017-05-18 09:59:16 +09001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
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
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.net.DeviceId;
28import 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;
37import org.onosproject.net.flow.instructions.Instruction;
38import org.onosproject.net.flowobjective.ForwardingObjective;
39import org.onosproject.net.flowobjective.Objective;
40import org.onosproject.openstacknetworking.api.Constants;
41import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
42import org.onosproject.openstacknode.OpenstackNode;
43import org.onosproject.openstacknode.OpenstackNodeEvent;
44import org.onosproject.openstacknode.OpenstackNodeListener;
45import org.onosproject.openstacknode.OpenstackNodeService;
46import org.slf4j.Logger;
47
48import 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;
53import static org.slf4j.LoggerFactory.getLogger;
54
55/**
56 * Sets flow rules directly using FlowRuleService.
57 */
58@Service
59@Component(immediate = true)
60public 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;
66 private static final int FLOW_RULE_TIME_OUT = 60;
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected FlowRuleService flowRuleService;
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected CoreService coreService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected OpenstackNodeService osNodeService;
76
77 private final ExecutorService deviceEventExecutor =
78 Executors.newSingleThreadExecutor(groupedThreads("openstacknetworking", "device-event"));
79 private final InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
80
81 private ApplicationId appId;
82
83 @Activate
84 protected void activate() {
85 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
86 coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
87 osNodeService.addListener(internalNodeListener);
88
89 log.info("Started");
90 }
91
92 @Deactivate
93 protected void deactivate() {
94 osNodeService.removeListener(internalNodeListener);
95 deviceEventExecutor.shutdown();
96
97 log.info("Stopped");
98 }
99
100 @Override
101 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective, int tableType) {
102 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
103
104 forwardingObjective.treatment().allInstructions().stream()
105 .filter(i -> i.type() != Instruction.Type.NOACTION).forEach(treatment::add);
106
107 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
108 .forDevice(deviceId)
109 .withSelector(forwardingObjective.selector())
110 .withTreatment(treatment.build())
111 .withPriority(forwardingObjective.priority())
112 .fromApp(forwardingObjective.appId())
113 .forTable(tableType);
114
115 if (forwardingObjective.permanent()) {
116 ruleBuilder.makePermanent();
117 } else {
118 ruleBuilder.makeTemporary(FLOW_RULE_TIME_OUT);
119 }
120
121 if (forwardingObjective.op().equals(Objective.Operation.ADD)) {
122 applyRules(true, ruleBuilder.build());
123 } else {
124 applyRules(false, ruleBuilder.build());
125 }
126 }
127
128 private void applyRules(boolean install, FlowRule flowRule) {
129 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
130
131 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
132
133 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
134 @Override
135 public void onSuccess(FlowRuleOperations ops) {
136 log.debug("Provisioned vni or forwarding table");
137 }
138
139 @Override
140 public void onError(FlowRuleOperations ops) {
141 log.debug("Failed to privision vni or forwarding table");
142 }
143 }));
144 }
145
146 private void initializePipeline(DeviceId deviceId) {
147 connectTables(deviceId, Constants.SRC_VNI_TABLE, Constants.ACL_TABLE);
148 connectTables(deviceId, Constants.ACL_TABLE, Constants.JUMP_TABLE);
149 setUpTableMissEntry(deviceId, Constants.ACL_TABLE);
150 setupJumpTable(deviceId);
151 }
152
153 private void connectTables(DeviceId deviceId, int fromTable, int toTable) {
154 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
169 applyRules(true, flowRule);
170 }
171
172 private void setUpTableMissEntry(DeviceId deviceId, int table) {
173 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
174 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
175
176 treatment.drop();
177
178 FlowRule flowRule = DefaultFlowRule.builder()
179 .forDevice(deviceId)
180 .withSelector(selector.build())
181 .withTreatment(treatment.build())
182 .withPriority(DROP_PRIORITY)
183 .fromApp(appId)
184 .makePermanent()
185 .forTable(table)
186 .build();
187
188 applyRules(true, flowRule);
189 }
190
191 private void setupJumpTable(DeviceId deviceId) {
192 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
193 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
194
195 selector.matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
196 treatment.transition(Constants.ROUTING_TABLE);
197
198 FlowRule flowRule = DefaultFlowRule.builder()
199 .forDevice(deviceId)
200 .withSelector(selector.build())
201 .withTreatment(treatment.build())
202 .withPriority(HIGH_PRIORITY)
203 .fromApp(appId)
204 .makePermanent()
205 .forTable(Constants.JUMP_TABLE)
206 .build();
207
208 applyRules(true, flowRule);
209
210 selector = DefaultTrafficSelector.builder();
211 treatment = DefaultTrafficTreatment.builder();
212
213 treatment.transition(Constants.FORWARDING_TABLE);
214
215 flowRule = DefaultFlowRule.builder()
216 .forDevice(deviceId)
217 .withSelector(selector.build())
218 .withTreatment(treatment.build())
219 .withPriority(DROP_PRIORITY)
220 .fromApp(appId)
221 .makePermanent()
222 .forTable(Constants.JUMP_TABLE)
223 .build();
224
225 applyRules(true, flowRule);
226 }
227
228 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
229
230 @Override
231 public void event(OpenstackNodeEvent event) {
232 OpenstackNode osNode = event.subject();
233 // TODO check leadership of the node and make only the leader process
234
235 switch (event.type()) {
236 case COMPLETE:
237 deviceEventExecutor.execute(() -> {
238 log.info("COMPLETE node {} is detected", osNode.hostname());
239
240 });
241 break;
242 case INCOMPLETE:
243 log.warn("{} is changed to INCOMPLETE state", osNode);
244 break;
245 case INIT:
246 case DEVICE_CREATED:
247 default:
248 break;
249 }
250 }
251
252 private void processCompleteNode(OpenstackNode osNode) {
253 if (osNode.type().equals(OpenstackNodeService.NodeType.COMPUTE)) {
254 initializePipeline(osNode.intBridge());
255 }
256 }
257 }
258}