blob: 6a9686b1674c53990e5b7476a2aa0fadd9f945ff [file] [log] [blame]
Jian Li62116942019-09-03 23:10:20 +09001/*
2 * Copyright 2019-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.openstacknetworking.impl;
17
18import org.onlab.packet.Ethernet;
19import org.onosproject.cluster.ClusterService;
20import org.onosproject.cluster.LeadershipService;
21import org.onosproject.core.ApplicationId;
22import org.onosproject.core.CoreService;
23import org.onosproject.mastership.MastershipService;
24import org.onosproject.net.DeviceId;
25import org.onosproject.net.Port;
26import org.onosproject.net.PortNumber;
27import org.onosproject.net.device.DeviceEvent;
28import org.onosproject.net.device.DeviceListener;
29import org.onosproject.net.device.DeviceService;
30import org.onosproject.net.driver.DriverService;
31import org.onosproject.net.flow.DefaultTrafficSelector;
32import org.onosproject.net.flow.DefaultTrafficTreatment;
33import org.onosproject.net.flow.TrafficSelector;
34import org.onosproject.net.flow.TrafficTreatment;
35import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
36import org.onosproject.openstacknode.api.OpenstackNode;
37import org.onosproject.openstacknode.api.OpenstackNodeService;
38import org.osgi.service.component.annotations.Activate;
39import org.osgi.service.component.annotations.Component;
40import org.osgi.service.component.annotations.Deactivate;
41import org.osgi.service.component.annotations.Reference;
42import org.osgi.service.component.annotations.ReferenceCardinality;
43import org.slf4j.Logger;
44
45import java.util.Set;
46import java.util.concurrent.ExecutorService;
47import java.util.stream.Collectors;
48
49import static java.util.concurrent.Executors.newSingleThreadExecutor;
50import static org.onlab.util.Tools.groupedThreads;
51import static org.onosproject.net.AnnotationKeys.PORT_NAME;
52import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
53import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
54import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_JUMP_UPSTREAM_RULE;
55import static org.onosproject.openstacknetworking.api.Constants.STAT_FLAT_OUTBOUND_TABLE;
56import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.structurePortName;
57import static org.onosproject.openstacknode.api.Constants.INTEGRATION_TO_PHYSICAL_PREFIX;
58import static org.slf4j.LoggerFactory.getLogger;
59
60/**
61 * Populates switching flow rules on OVS for the physical interfaces.
62 */
63@Component(immediate = true)
64public class OpenstackSwitchingPhysicalHandler {
65
66 private final Logger log = getLogger(getClass());
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY)
69 protected CoreService coreService;
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY)
72 protected MastershipService mastershipService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY)
75 protected DeviceService deviceService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY)
78 protected DriverService driverService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY)
81 protected ClusterService clusterService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY)
84 protected LeadershipService leadershipService;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY)
87 protected OpenstackFlowRuleService osFlowRuleService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY)
90 protected OpenstackNodeService osNodeService;
91
92 private final ExecutorService eventExecutor = newSingleThreadExecutor(
93 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
94 private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
95
96 private ApplicationId appId;
97
98 @Activate
99 protected void activate() {
100 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
101 deviceService.addListener(internalDeviceListener);
102
103 log.info("Started");
104 }
105
106 @Deactivate
107 protected void deactivate() {
108 eventExecutor.shutdown();
109 deviceService.removeListener(internalDeviceListener);
110
111 log.info("Stopped");
112 }
113
114 /**
115 * An internal device listener which listens the port events generated from
116 * OVS integration bridge.
117 */
118 private class InternalDeviceListener implements DeviceListener {
119
120 @Override
121 public boolean isRelevant(DeviceEvent event) {
122 Port port = event.port();
123 if (port == null) {
124 return false;
125 }
126
127 OpenstackNode osNode = osNodeService.node(event.subject().id());
128 if (osNode == null) {
129 return false;
130 }
131
132 Set<String> intPatchPorts = osNode.phyIntfs().stream()
133 .map(pi -> structurePortName(INTEGRATION_TO_PHYSICAL_PREFIX
134 + pi.network())).collect(Collectors.toSet());
135 String portName = port.annotations().value(PORT_NAME);
136
137 return intPatchPorts.contains(portName);
138 }
139
140 private boolean isRelevantHelper(DeviceEvent event) {
141 return mastershipService.isLocalMaster(event.subject().id());
142 }
143
144 @Override
145 public void event(DeviceEvent event) {
146 log.info("Device event occurred with type {}", event.type());
147
148 switch (event.type()) {
149 case PORT_ADDED:
150 case PORT_UPDATED:
151 eventExecutor.execute(() -> processPortAddition(event));
152 break;
153 case PORT_REMOVED:
154 eventExecutor.execute(() -> processPortRemoval(event));
155 break;
156 default:
157 break;
158 }
159 }
160
161 private void processPortAddition(DeviceEvent event) {
162 if (!isRelevantHelper(event)) {
163 return;
164 }
165
166 setFlatJumpRulesForPatchPort(event.subject().id(),
167 event.port().number(), true);
168 }
169
170 private void processPortRemoval(DeviceEvent event) {
171 if (!isRelevantHelper(event)) {
172 return;
173 }
174
175 setFlatJumpRulesForPatchPort(event.subject().id(),
176 event.port().number(), false);
177 }
178
179 private void setFlatJumpRulesForPatchPort(DeviceId deviceId,
180 PortNumber portNumber,
181 boolean install) {
182 setFlatJumpRuleForPatchPort(deviceId, portNumber,
183 Ethernet.TYPE_IPV4, install);
184 setFlatJumpRuleForPatchPort(deviceId, portNumber,
185 Ethernet.TYPE_ARP, install);
186 }
187
188 private void setFlatJumpRuleForPatchPort(DeviceId deviceId,
189 PortNumber portNumber,
190 short ethType, boolean install) {
191 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
192 selector.matchInPort(portNumber)
193 .matchEthType(ethType);
194
195 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
196 treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
197
198 osFlowRuleService.setRule(
199 appId,
200 deviceId,
201 selector.build(),
202 treatment.build(),
203 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
204 DHCP_TABLE,
205 install);
206 }
207 }
208}