blob: 9def76fde6da5809ffdc6104567d4fb60292d5c4 [file] [log] [blame]
Jian Lib5ab63c2021-02-03 17:54:28 +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
18import com.google.common.collect.Lists;
Jian Li543fe852021-02-04 17:25:01 +090019import org.onlab.packet.ARP;
20import org.onlab.packet.EthType;
Jian Lib5ab63c2021-02-03 17:54:28 +090021import org.onlab.packet.Ethernet;
22import org.onlab.packet.IPv4;
Jian Li543fe852021-02-04 17:25:01 +090023import org.onlab.packet.Ip4Address;
Jian Lib5ab63c2021-02-03 17:54:28 +090024import org.onlab.packet.IpAddress;
Jian Li543fe852021-02-04 17:25:01 +090025import org.onlab.packet.IpPrefix;
Jian Lib5ab63c2021-02-03 17:54:28 +090026import org.onlab.packet.TpPort;
27import org.onlab.packet.UDP;
28import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
34import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
35import org.onosproject.kubevirtnetworking.api.KubevirtNetworkEvent;
36import org.onosproject.kubevirtnetworking.api.KubevirtNetworkListener;
37import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
38import org.onosproject.kubevirtnode.api.KubevirtApiConfigService;
39import org.onosproject.kubevirtnode.api.KubevirtNode;
40import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
41import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
42import org.onosproject.kubevirtnode.api.KubevirtNodeService;
43import org.onosproject.net.Device;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.PortNumber;
46import org.onosproject.net.behaviour.BridgeConfig;
47import org.onosproject.net.behaviour.BridgeDescription;
48import org.onosproject.net.behaviour.BridgeName;
49import org.onosproject.net.behaviour.ControllerInfo;
50import org.onosproject.net.behaviour.DefaultBridgeDescription;
51import org.onosproject.net.behaviour.DefaultPatchDescription;
52import org.onosproject.net.behaviour.InterfaceConfig;
53import org.onosproject.net.behaviour.PatchDescription;
54import org.onosproject.net.device.DeviceAdminService;
55import org.onosproject.net.flow.DefaultTrafficSelector;
56import org.onosproject.net.flow.DefaultTrafficTreatment;
57import org.onosproject.net.flow.TrafficSelector;
58import org.onosproject.net.flow.TrafficTreatment;
59import org.osgi.service.component.annotations.Activate;
60import org.osgi.service.component.annotations.Component;
61import org.osgi.service.component.annotations.Deactivate;
62import org.osgi.service.component.annotations.Reference;
63import org.osgi.service.component.annotations.ReferenceCardinality;
64import org.slf4j.Logger;
65
66import java.util.List;
67import java.util.Objects;
68import java.util.concurrent.ExecutorService;
69
70import static java.lang.Thread.sleep;
71import static java.util.concurrent.Executors.newSingleThreadExecutor;
Jian Li543fe852021-02-04 17:25:01 +090072import static org.onlab.packet.ICMP.CODE_ECHO_REQEUST;
73import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
74import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
Jian Lib5ab63c2021-02-03 17:54:28 +090075import static org.onlab.util.Tools.groupedThreads;
Jian Li543fe852021-02-04 17:25:01 +090076import static org.onosproject.kubevirtnetworking.api.Constants.DEFAULT_GATEWAY_MAC;
Jian Lib5ab63c2021-02-03 17:54:28 +090077import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
Jian Li543fe852021-02-04 17:25:01 +090078import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Lib5ab63c2021-02-03 17:54:28 +090079import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_DHCP_RULE;
Jian Li543fe852021-02-04 17:25:01 +090080import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
81import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ICMP_RULE;
82import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ARP_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +090083import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_DHCP_TABLE;
84import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
Jian Li543fe852021-02-04 17:25:01 +090085import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ICMP_TABLE;
Jian Lib5ab63c2021-02-03 17:54:28 +090086import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_INBOUND_TABLE;
Jian Li543fe852021-02-04 17:25:01 +090087import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_TO_TUNNEL_PREFIX;
88import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_TO_TENANT_PREFIX;
Jian Lib5ab63c2021-02-03 17:54:28 +090089import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.segmentIdHex;
Jian Li543fe852021-02-04 17:25:01 +090090import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_NX_IP_TTL;
91import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.NXM_OF_ICMP_TYPE;
92import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildLoadExtension;
93import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
94import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
95import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
96import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildMoveIpSrcToDstExtension;
Jian Lib5ab63c2021-02-03 17:54:28 +090097import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_BRIDGE;
98import static org.slf4j.LoggerFactory.getLogger;
99
100/**
101 * Handles kubevirt network events.
102 */
103@Component(immediate = true)
104public class KubevirtNetworkHandler {
105 protected final Logger log = getLogger(getClass());
106 private static final String DEFAULT_OF_PROTO = "tcp";
107 private static final int DEFAULT_OFPORT = 6653;
108 private static final int DPID_BEGIN = 3;
109 private static final long SLEEP_MS = 3000; // we wait 3s for init each node
Jian Li543fe852021-02-04 17:25:01 +0900110 private static final int DEFAULT_TTL = 0xff;
Jian Lib5ab63c2021-02-03 17:54:28 +0900111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
113 protected CoreService coreService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
116 protected ClusterService clusterService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
119 protected LeadershipService leadershipService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
122 protected DeviceAdminService deviceService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
125 protected KubevirtApiConfigService apiConfigService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
128 protected KubevirtNodeService nodeService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
131 protected KubevirtNetworkService networkService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
134 protected KubevirtFlowRuleService flowService;
135
136 private final KubevirtNetworkListener networkListener = new InternalNetworkEventListener();
137 private final KubevirtNodeListener nodeListener = new InternalNodeEventListener();
138
139 private final ExecutorService eventExecutor = newSingleThreadExecutor(
140 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
141
142 private ApplicationId appId;
143 private NodeId localNodeId;
144
145 @Activate
146 protected void activate() {
147 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
148 localNodeId = clusterService.getLocalNode().id();
149 networkService.addListener(networkListener);
150 nodeService.addListener(nodeListener);
151 leadershipService.runForLeadership(appId.name());
152
153 log.info("Started");
154 }
155
156 @Deactivate
157 protected void deactivate() {
158 networkService.removeListener(networkListener);
159 nodeService.removeListener(nodeListener);
160 leadershipService.withdraw(appId.name());
161 eventExecutor.shutdown();
162
163 log.info("Stopped");
164 }
165
166 private void createBridge(KubevirtNode node, KubevirtNetwork network) {
167
168 Device tunBridge = deviceService.getDevice(network.tenantDeviceId(node.hostname()));
169 if (tunBridge != null) {
170 log.warn("The tunnel bridge {} already exists at node {}",
171 network.tenantBridgeName(), node.hostname());
172 setDefaultRules(node, network);
173 return;
174 }
175
176 Device device = deviceService.getDevice(node.ovsdb());
177
178 IpAddress serverIp = apiConfigService.apiConfig().ipAddress();
179 ControllerInfo controlInfo =
180 new ControllerInfo(serverIp, DEFAULT_OFPORT, DEFAULT_OF_PROTO);
181 List<ControllerInfo> controllers = Lists.newArrayList(controlInfo);
182
183 String dpid = network.tenantDeviceId(
184 node.hostname()).toString().substring(DPID_BEGIN);
185
186 BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
187 .name(network.tenantBridgeName())
188 .failMode(BridgeDescription.FailMode.SECURE)
189 .datapathId(dpid)
190 .disableInBand()
191 .controllers(controllers);
192
193 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
194 bridgeConfig.addBridge(builder.build());
195 }
196
197 private void removeBridge(KubevirtNode node, KubevirtNetwork network) {
198 Device device = deviceService.getDevice(node.ovsdb());
199
200 BridgeName bridgeName = BridgeName.bridgeName(network.tenantBridgeName());
201
202 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
203 bridgeConfig.deleteBridge(bridgeName);
204 deviceService.removeDevice(network.tenantDeviceId(node.hostname()));
205 }
206
207 private void createPatchInterface(KubevirtNode node, KubevirtNetwork network) {
208 Device device = deviceService.getDevice(node.ovsdb());
209
210 if (device == null || !device.is(InterfaceConfig.class)) {
211 log.error("Failed to create patch interface on {}", node.ovsdb());
212 return;
213 }
214
215 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
216
Jian Li543fe852021-02-04 17:25:01 +0900217 String tenantToTunIntf =
218 TENANT_TO_TUNNEL_PREFIX + segmentIdHex(network.segmentId());
219 String tunToTenantIntf =
220 TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900221
Jian Li543fe852021-02-04 17:25:01 +0900222 // tenant bridge -> tunnel bridge
223 PatchDescription brTenantTunPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900224 DefaultPatchDescription.builder()
225 .deviceId(network.tenantBridgeName())
Jian Li543fe852021-02-04 17:25:01 +0900226 .ifaceName(tenantToTunIntf)
227 .peer(tunToTenantIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900228 .build();
229
Jian Li543fe852021-02-04 17:25:01 +0900230 ifaceConfig.addPatchMode(tenantToTunIntf, brTenantTunPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900231
Jian Li543fe852021-02-04 17:25:01 +0900232 // tunnel bridge -> tenant bridge
233 PatchDescription brTunTenantPatchDesc =
Jian Lib5ab63c2021-02-03 17:54:28 +0900234 DefaultPatchDescription.builder()
235 .deviceId(TUNNEL_BRIDGE)
Jian Li543fe852021-02-04 17:25:01 +0900236 .ifaceName(tunToTenantIntf)
237 .peer(tenantToTunIntf)
Jian Lib5ab63c2021-02-03 17:54:28 +0900238 .build();
Jian Li543fe852021-02-04 17:25:01 +0900239 ifaceConfig.addPatchMode(tunToTenantIntf, brTunTenantPatchDesc);
Jian Lib5ab63c2021-02-03 17:54:28 +0900240 }
241
242 private void removePatchInterface(KubevirtNode node, KubevirtNetwork network) {
243 Device device = deviceService.getDevice(node.ovsdb());
244
245 if (device == null || !device.is(InterfaceConfig.class)) {
246 log.error("Failed to create patch interface on {}", node.ovsdb());
247 return;
248 }
249
250 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
251
Jian Li543fe852021-02-04 17:25:01 +0900252 String tunToIntIntf = TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
Jian Lib5ab63c2021-02-03 17:54:28 +0900253
254 ifaceConfig.removePatchMode(tunToIntIntf);
255 }
256
257 private void setDefaultRules(KubevirtNode node, KubevirtNetwork network) {
258 DeviceId deviceId = network.tenantDeviceId(node.hostname());
259
260 while (!deviceService.isAvailable(deviceId)) {
261 log.warn("Device {} is not ready for installing rules", deviceId);
262
263 try {
264 sleep(SLEEP_MS);
265 } catch (InterruptedException e) {
266 log.error("Failed to check device availability", e);
267 }
268 }
269
270 flowService.connectTables(deviceId, TENANT_INBOUND_TABLE, TENANT_DHCP_TABLE);
Jian Li543fe852021-02-04 17:25:01 +0900271 flowService.connectTables(deviceId, TENANT_DHCP_TABLE, TENANT_ARP_TABLE);
272 flowService.connectTables(deviceId, TENANT_ARP_TABLE, TENANT_ICMP_TABLE);
273 flowService.connectTables(deviceId, TENANT_ICMP_TABLE, TENANT_FORWARDING_TABLE);
Jian Lib5ab63c2021-02-03 17:54:28 +0900274
275 setDhcpRule(deviceId, true);
276 setForwardingRule(deviceId, true);
Jian Li543fe852021-02-04 17:25:01 +0900277 setGatewayArpRule(node, network, true);
278 setGatewayIcmpRule(node, network, true);
Jian Lib5ab63c2021-02-03 17:54:28 +0900279
280 log.info("Install default flow rules for tenant bridge {}", network.tenantBridgeName());
281 }
282
283 private void setDhcpRule(DeviceId deviceId, boolean install) {
284 TrafficSelector selector = DefaultTrafficSelector.builder()
285 .matchEthType(Ethernet.TYPE_IPV4)
286 .matchIPProtocol(IPv4.PROTOCOL_UDP)
287 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
288 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
289 .build();
290
291 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
292 .punt()
293 .build();
294
295 flowService.setRule(
296 appId,
297 deviceId,
298 selector,
299 treatment,
300 PRIORITY_DHCP_RULE,
301 TENANT_DHCP_TABLE,
302 install);
303 }
304
Jian Li543fe852021-02-04 17:25:01 +0900305 private void setForwardingRule(DeviceId deviceId, boolean install) {
Jian Lib5ab63c2021-02-03 17:54:28 +0900306 TrafficSelector selector = DefaultTrafficSelector.builder().build();
307 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
308 .setOutput(PortNumber.NORMAL)
309 .build();
310
311 flowService.setRule(
312 appId,
313 deviceId,
314 selector,
315 treatment,
Jian Li543fe852021-02-04 17:25:01 +0900316 PRIORITY_FORWARDING_RULE,
Jian Lib5ab63c2021-02-03 17:54:28 +0900317 TENANT_FORWARDING_TABLE,
318 install);
319 }
320
Jian Li543fe852021-02-04 17:25:01 +0900321 private void setGatewayArpRule(KubevirtNode node, KubevirtNetwork network, boolean install) {
322 Device device = deviceService.getDevice(network.tenantDeviceId(node.hostname()));
323
324 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
325 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
326 .matchArpOp(ARP.OP_REQUEST)
327 .matchArpTpa(Ip4Address.valueOf(network.gatewayIp().toString()));
328
329 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
330 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
331 .extension(buildMoveArpShaToThaExtension(device), device.id())
332 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
333 .setArpOp(ARP.OP_REPLY)
334 .setArpSha(DEFAULT_GATEWAY_MAC)
335 .setArpSpa(Ip4Address.valueOf(network.gatewayIp().toString()))
336 .setEthSrc(DEFAULT_GATEWAY_MAC)
337 .setOutput(PortNumber.IN_PORT);
338
339 flowService.setRule(
340 appId,
341 device.id(),
342 sBuilder.build(),
343 tBuilder.build(),
344 PRIORITY_ARP_GATEWAY_RULE,
345 TENANT_ARP_TABLE,
346 install
347 );
348 }
349
350 private void setGatewayIcmpRule(KubevirtNode node, KubevirtNetwork network, boolean install) {
351 DeviceId deviceId = network.tenantDeviceId(node.hostname());
352 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
353 .matchEthType(Ethernet.TYPE_IPV4)
354 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
355 .matchIcmpType(TYPE_ECHO_REQUEST)
356 .matchIcmpCode(CODE_ECHO_REQEUST)
357 .matchIPDst(IpPrefix.valueOf(network.gatewayIp(), 32));
358
359 Device device = deviceService.getDevice(deviceId);
360 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
361 .extension(buildMoveEthSrcToDstExtension(device), device.id())
362 .extension(buildMoveIpSrcToDstExtension(device), device.id())
363 .extension(buildLoadExtension(device,
364 NXM_NX_IP_TTL, DEFAULT_TTL), device.id())
365 .extension(buildLoadExtension(device,
366 NXM_OF_ICMP_TYPE, TYPE_ECHO_REPLY), device.id())
367 .setIpSrc(network.gatewayIp())
368 .setEthSrc(DEFAULT_GATEWAY_MAC)
369 .setOutput(PortNumber.IN_PORT);
370
371 flowService.setRule(
372 appId,
373 deviceId,
374 sBuilder.build(),
375 tBuilder.build(),
376 PRIORITY_ICMP_RULE,
377 TENANT_ICMP_TABLE,
378 install);
379 }
380
Jian Lib5ab63c2021-02-03 17:54:28 +0900381 private class InternalNetworkEventListener implements KubevirtNetworkListener {
382
383 private boolean isRelevantHelper() {
384 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
385 }
386
387 @Override
388 public void event(KubevirtNetworkEvent event) {
389 switch (event.type()) {
390 case KUBEVIRT_NETWORK_CREATED:
391 eventExecutor.execute(() -> processNetworkCreation(event.subject()));
392 break;
393 case KUBEVIRT_NETWORK_REMOVED:
394 eventExecutor.execute(() -> processNetworkRemoval(event.subject()));
395 break;
396 case KUBEVIRT_NETWORK_UPDATED:
397 default:
398 // do nothing
399 break;
400 }
401 }
402
403 private void processNetworkCreation(KubevirtNetwork network) {
404 if (!isRelevantHelper()) {
405 return;
406 }
407
408 switch (network.type()) {
409 case VXLAN:
410 case GRE:
411 case GENEVE:
412 initIntegrationTunnelBridge(network);
413 break;
414 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +0900415 case VLAN:
Jian Lib5ab63c2021-02-03 17:54:28 +0900416 default:
417 // do nothing
418 break;
419 }
420 }
421
422 private void processNetworkRemoval(KubevirtNetwork network) {
423 if (!isRelevantHelper()) {
424 return;
425 }
426
427 switch (network.type()) {
428 case VXLAN:
429 case GRE:
430 case GENEVE:
431 purgeIntegrationTunnelBridge(network);
432 break;
433 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +0900434 case VLAN:
Jian Lib5ab63c2021-02-03 17:54:28 +0900435 default:
436 // do nothing
437 break;
438 }
439 }
440
441 private void initIntegrationTunnelBridge(KubevirtNetwork network) {
442 if (network.segmentId() == null) {
443 return;
444 }
445
446 nodeService.completeNodes().forEach(n -> {
447 createBridge(n, network);
448 createPatchInterface(n, network);
449 setDefaultRules(n, network);
450 });
451 }
452
453 private void purgeIntegrationTunnelBridge(KubevirtNetwork network) {
454 if (network.segmentId() == null) {
455 return;
456 }
457
458 nodeService.completeNodes().forEach(n -> {
459 removePatchInterface(n, network);
460 removeBridge(n, network);
461 });
462 }
463 }
464
465 private class InternalNodeEventListener implements KubevirtNodeListener {
466
467 private boolean isRelevantHelper() {
468 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
469 }
470
471 @Override
472 public void event(KubevirtNodeEvent event) {
473 switch (event.type()) {
474 case KUBEVIRT_NODE_COMPLETE:
475 eventExecutor.execute(() -> processNodeCompletion(event.subject()));
476 break;
477 case KUBEVIRT_NODE_INCOMPLETE:
478 case KUBEVIRT_NODE_UPDATED:
479 default:
480 // do nothing
481 break;
482 }
483 }
484
485 private void processNodeCompletion(KubevirtNode node) {
486 if (!isRelevantHelper()) {
487 return;
488 }
489
490 for (KubevirtNetwork network : networkService.networks()) {
491 switch (network.type()) {
492 case VXLAN:
493 case GRE:
494 case GENEVE:
495 if (network.segmentId() == null) {
496 continue;
497 }
498 createBridge(node, network);
499 createPatchInterface(node, network);
500 setDefaultRules(node, network);
501 break;
502 case FLAT:
Jian Li81b1aab2021-02-17 20:42:15 +0900503 case VLAN:
Jian Lib5ab63c2021-02-03 17:54:28 +0900504 default:
505 // do nothing
506 break;
507 }
508 }
509 }
510 }
511}