blob: fd0669a3b9dc672843cdcfb04750d8f945016d00 [file] [log] [blame]
Jian Li43244382021-01-09 00:19:02 +09001/*
2 * Copyright 2021-present Open Networking Foundation
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 */
16package org.onosproject.kubevirtnetworking.impl;
17
Jian Lif89d9602021-04-27 19:05:49 +090018import org.onlab.packet.EthType;
Jian Li43244382021-01-09 00:19:02 +090019import org.onlab.util.Tools;
20import org.onosproject.cfg.ComponentConfigService;
21import org.onosproject.cfg.ConfigProperty;
22import org.onosproject.cluster.ClusterService;
23import org.onosproject.cluster.LeadershipService;
24import org.onosproject.cluster.NodeId;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
28import org.onosproject.kubevirtnode.api.KubevirtNode;
29import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
30import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
31import org.onosproject.kubevirtnode.api.KubevirtNodeService;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.device.DeviceService;
35import org.onosproject.net.flow.DefaultFlowRule;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.FlowRuleOperations;
40import org.onosproject.net.flow.FlowRuleOperationsContext;
41import org.onosproject.net.flow.FlowRuleService;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
44import org.osgi.service.component.ComponentContext;
45import org.osgi.service.component.annotations.Activate;
46import org.osgi.service.component.annotations.Component;
47import org.osgi.service.component.annotations.Deactivate;
48import org.osgi.service.component.annotations.Modified;
49import org.osgi.service.component.annotations.Reference;
50import org.osgi.service.component.annotations.ReferenceCardinality;
51import org.slf4j.Logger;
52
53import java.util.Dictionary;
54import java.util.Objects;
55import java.util.Set;
56import java.util.concurrent.ExecutorService;
57import java.util.concurrent.Executors;
58
59import static org.onlab.util.Tools.groupedThreads;
60import static org.onosproject.kubevirtnetworking.api.Constants.ACL_EGRESS_TABLE;
Jian Li43244382021-01-09 00:19:02 +090061import static org.onosproject.kubevirtnetworking.api.Constants.ARP_TABLE;
Jian Li43244382021-01-09 00:19:02 +090062import static org.onosproject.kubevirtnetworking.api.Constants.DHCP_TABLE;
Jian Li43244382021-01-09 00:19:02 +090063import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
Jian Lif89d9602021-04-27 19:05:49 +090064import static org.onosproject.kubevirtnetworking.api.Constants.GW_DROP_TABLE;
65import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
Jian Li43244382021-01-09 00:19:02 +090066import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Jian Lif89d9602021-04-27 19:05:49 +090067import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_DEFAULT_RULE;
Jian Li43244382021-01-09 00:19:02 +090068import static org.onosproject.kubevirtnetworking.api.Constants.STAT_INBOUND_TABLE;
Jian Li43244382021-01-09 00:19:02 +090069import static org.onosproject.kubevirtnetworking.api.Constants.VTAP_INBOUND_TABLE;
Jian Li43244382021-01-09 00:19:02 +090070import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.PROVIDER_NETWORK_ONLY;
71import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.PROVIDER_NETWORK_ONLY_DEFAULT;
72import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
Daniel Parka8968802021-02-25 09:14:22 +090073import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
Jian Li43244382021-01-09 00:19:02 +090074import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
75import static org.slf4j.LoggerFactory.getLogger;
76
77/**
78 * Sets flow rules directly using FlowRuleService.
79 */
80@Component(
81 immediate = true,
82 service = KubevirtFlowRuleService.class,
83 property = {
84 PROVIDER_NETWORK_ONLY + ":Boolean=" + PROVIDER_NETWORK_ONLY_DEFAULT
85 }
86)
87public class KubevirtFlowRuleManager implements KubevirtFlowRuleService {
88
89 private final Logger log = getLogger(getClass());
90
91 private static final int DROP_PRIORITY = 0;
92 private static final int LOW_PRIORITY = 10000;
Jian Li43244382021-01-09 00:19:02 +090093
94 /** Use provider network only. */
95 private boolean providerNetworkOnly = PROVIDER_NETWORK_ONLY_DEFAULT;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY)
98 protected FlowRuleService flowRuleService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
101 protected CoreService coreService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY)
104 protected ClusterService clusterService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
107 protected LeadershipService leadershipService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
110 protected DeviceService deviceService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
113 protected ComponentConfigService configService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
116 protected KubevirtNodeService nodeService;
117
118 private final ExecutorService deviceEventExecutor = Executors.newSingleThreadExecutor(
119 groupedThreads(getClass().getSimpleName(), "device-event"));
120 private final KubevirtNodeListener internalNodeListener = new InternalKubevirtNodeListener();
121
122 private ApplicationId appId;
123 private NodeId localNodeId;
124
125 @Activate
126 protected void activate() {
127 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
128 coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
129 configService.registerProperties(getClass());
130 nodeService.addListener(internalNodeListener);
131 localNodeId = clusterService.getLocalNode().id();
132 leadershipService.runForLeadership(appId.name());
133 nodeService.completeNodes(WORKER)
Daniel Park2884b232021-03-04 18:58:47 +0900134 .forEach(node -> initializeWorkerNodePipeline(node.intgBridge()));
Jian Li43244382021-01-09 00:19:02 +0900135
136 log.info("Started");
137 }
138
139 @Deactivate
140 protected void deactivate() {
141 nodeService.removeListener(internalNodeListener);
142 configService.unregisterProperties(getClass(), false);
143 leadershipService.withdraw(appId.name());
144 deviceEventExecutor.shutdown();
145
146 log.info("Stopped");
147 }
148
149 @Modified
150 protected void modified(ComponentContext context) {
151 Dictionary<?, ?> properties = context.getProperties();
152 Boolean flag;
153
154 flag = Tools.isPropertyEnabled(properties, PROVIDER_NETWORK_ONLY);
155 if (flag == null) {
156 log.info("providerNetworkOnly is not configured, " +
157 "using current value of {}", providerNetworkOnly);
158 } else {
159 providerNetworkOnly = flag;
160 log.info("Configured. providerNetworkOnly is {}",
161 providerNetworkOnly ? "enabled" : "disabled");
162 }
163 }
164
165 @Override
166 public void setRule(ApplicationId appId, DeviceId deviceId,
167 TrafficSelector selector, TrafficTreatment treatment,
168 int priority, int tableType, boolean install) {
169
170 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder()
171 .forDevice(deviceId)
172 .withSelector(selector)
173 .withTreatment(treatment)
174 .withPriority(priority)
175 .fromApp(appId)
176 .forTable(tableType)
177 .makePermanent();
178
179 applyRule(flowRuleBuilder.build(), install);
180 }
181
182 @Override
183 public void setUpTableMissEntry(DeviceId deviceId, int table) {
184 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
185 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
186
187 treatment.drop();
188
Jian Lif89d9602021-04-27 19:05:49 +0900189 this.setRule(
190 appId,
191 deviceId,
192 selector.build(),
193 treatment.build(),
194 DROP_PRIORITY,
195 table,
196 true);
Jian Li43244382021-01-09 00:19:02 +0900197 }
198
199 @Override
200 public void connectTables(DeviceId deviceId, int fromTable, int toTable) {
201 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
202 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
203
204 treatment.transition(toTable);
205
Jian Lif89d9602021-04-27 19:05:49 +0900206 this.setRule(
207 appId,
208 deviceId,
209 selector.build(),
210 treatment.build(),
211 DROP_PRIORITY,
212 fromTable,
213 true);
Jian Li43244382021-01-09 00:19:02 +0900214 }
215
216 private void applyRule(FlowRule flowRule, boolean install) {
217 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
218
219 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
220
221 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
222 @Override
223 public void onSuccess(FlowRuleOperations ops) {
224 log.debug("Provisioned vni or forwarding table");
225 }
226
227 @Override
228 public void onError(FlowRuleOperations ops) {
229 log.debug("Failed to provision vni or forwarding table");
230 }
231 }));
232 }
233
Daniel Park2884b232021-03-04 18:58:47 +0900234 protected void initializeGatewayNodePipeline(DeviceId deviceId) {
Jian Lif89d9602021-04-27 19:05:49 +0900235 // for inbound to gateway entry table transition
236 connectTables(deviceId, STAT_INBOUND_TABLE, GW_ENTRY_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900237
Jian Lif89d9602021-04-27 19:05:49 +0900238 // for gateway entry to gateway drop table transition
239 connectTables(deviceId, GW_ENTRY_TABLE, GW_DROP_TABLE);
Daniel Park2884b232021-03-04 18:58:47 +0900240
Jian Lif89d9602021-04-27 19:05:49 +0900241 // for setting up default gateway drop table
242 setupGatewayNodeDropTable(deviceId);
Daniel Park2884b232021-03-04 18:58:47 +0900243
244 // for setting up default Forwarding table behavior which is NORMAL
245 setupForwardingTable(deviceId);
246 }
247 protected void initializeWorkerNodePipeline(DeviceId deviceId) {
Jian Li43244382021-01-09 00:19:02 +0900248 // for inbound table transition
249 connectTables(deviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE);
250 connectTables(deviceId, VTAP_INBOUND_TABLE, DHCP_TABLE);
251
Jian Lif89d9602021-04-27 19:05:49 +0900252 // for DHCP and ARP table transition
253 connectTables(deviceId, DHCP_TABLE, ARP_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900254
Jian Lif89d9602021-04-27 19:05:49 +0900255 // for ARP table and ACL egress table transition
256 connectTables(deviceId, ARP_TABLE, ACL_EGRESS_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900257
Jian Lif89d9602021-04-27 19:05:49 +0900258 // for setting up default ARP table behavior
259 setupArpTable(deviceId);
Jian Li43244382021-01-09 00:19:02 +0900260
Daniel Park2884b232021-03-04 18:58:47 +0900261 // for setting up default Forwarding table behavior which is NORMAL
262 setupForwardingTable(deviceId);
Jian Li43244382021-01-09 00:19:02 +0900263 }
264
Jian Lif89d9602021-04-27 19:05:49 +0900265 private void setupArpTable(DeviceId deviceId) {
266 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
267 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort());
Jian Li43244382021-01-09 00:19:02 +0900268
Jian Lif89d9602021-04-27 19:05:49 +0900269 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
270 tBuilder.transition(FORWARDING_TABLE);
Jian Li43244382021-01-09 00:19:02 +0900271
Jian Lif89d9602021-04-27 19:05:49 +0900272 this.setRule(
273 appId,
274 deviceId,
275 sBuilder.build(),
276 tBuilder.build(),
277 PRIORITY_ARP_DEFAULT_RULE,
278 ARP_TABLE,
279 true);
Jian Li43244382021-01-09 00:19:02 +0900280 }
281
Daniel Park2884b232021-03-04 18:58:47 +0900282 private void setupForwardingTable(DeviceId deviceId) {
Jian Li43244382021-01-09 00:19:02 +0900283 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
284 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
285 .setOutput(PortNumber.NORMAL);
286
Jian Lif89d9602021-04-27 19:05:49 +0900287 this.setRule(
288 appId,
289 deviceId,
290 selector.build(),
291 treatment.build(),
292 LOW_PRIORITY,
293 FORWARDING_TABLE,
294 true);
Daniel Park2884b232021-03-04 18:58:47 +0900295 }
296
Jian Lif89d9602021-04-27 19:05:49 +0900297 private void setupGatewayNodeDropTable(DeviceId deviceId) {
Daniel Park2884b232021-03-04 18:58:47 +0900298 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
299 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
300 .drop();
301
Jian Lif89d9602021-04-27 19:05:49 +0900302 this.setRule(
303 appId,
304 deviceId,
305 selector.build(),
306 treatment.build(),
307 DROP_PRIORITY,
308 GW_DROP_TABLE,
309 true);
Jian Li43244382021-01-09 00:19:02 +0900310 }
311
312 private boolean getProviderNetworkOnlyFlag() {
313 Set<ConfigProperty> properties =
314 configService.getProperties(getClass().getName());
315 return getPropertyValueAsBoolean(properties, PROVIDER_NETWORK_ONLY);
316 }
317
318 private class InternalKubevirtNodeListener implements KubevirtNodeListener {
319
320 @Override
321 public boolean isRelevant(KubevirtNodeEvent event) {
Daniel Parka8968802021-02-25 09:14:22 +0900322 return event.subject().type().equals(WORKER) ||
323 event.subject().type().equals(GATEWAY);
Jian Li43244382021-01-09 00:19:02 +0900324 }
325
326 private boolean isRelevantHelper() {
327 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
328 }
329
330 @Override
331 public void event(KubevirtNodeEvent event) {
332 KubevirtNode node = event.subject();
333
334 switch (event.type()) {
335 case KUBEVIRT_NODE_COMPLETE:
336 deviceEventExecutor.execute(() -> {
337 log.info("COMPLETE node {} is detected", node.hostname());
338
339 if (!isRelevantHelper()) {
340 return;
341 }
342
Daniel Park2884b232021-03-04 18:58:47 +0900343 if (event.subject().type().equals(WORKER)) {
344 initializeWorkerNodePipeline(node.intgBridge());
345 } else {
346 initializeGatewayNodePipeline(node.intgBridge());
347 }
Jian Li43244382021-01-09 00:19:02 +0900348 });
349 break;
350 case KUBEVIRT_NODE_CREATED:
351 case KUBEVIRT_NODE_UPDATED:
352 case KUBEVIRT_NODE_REMOVED:
353 default:
354 // do nothing
355 break;
356 }
357 }
358 }
359}