blob: bd8473cf3577d19739e37ffc97adf3828aa89aee [file] [log] [blame]
Daniel Parkc4d06402018-05-28 15:57:37 +09001/*
2 * Copyright 2018-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.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Modified;
22import org.apache.felix.scr.annotations.Property;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.util.Tools;
26import org.onosproject.cfg.ComponentConfigService;
27import org.onosproject.cluster.ClusterService;
28import org.onosproject.cluster.LeadershipService;
29import org.onosproject.cluster.NodeId;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.mastership.MastershipService;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.device.DeviceService;
35import org.onosproject.openstacknetworking.api.InstancePort;
36import org.onosproject.openstacknetworking.api.InstancePortService;
37import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
38import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
39import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
40import org.onosproject.openstacknode.api.OpenstackNode;
41import org.onosproject.openstacknode.api.OpenstackNodeService;
42import org.onosproject.ovsdb.controller.OvsdbController;
43import org.openstack4j.model.network.Port;
44import org.openstack4j.model.network.State;
45import org.osgi.service.component.ComponentContext;
46import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
49import java.util.Dictionary;
50import java.util.Objects;
51import java.util.Optional;
52
53import static org.onosproject.openstacknetworking.api.Constants.DIRECT;
54import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
55import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getIntfNameFromPciAddress;
56import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
57
58@Component(immediate = true)
59public final class OpenStackSwitchingDirectPortProvider {
60 private final Logger log = LoggerFactory.getLogger(getClass());
61
62 private static final String OVSDB_PORT = "ovsdbPortNum";
63 private static final int DEFAULT_OVSDB_PORT = 6640;
64 private static final String UNBOUND = "unbound";
65 private static final String PORT_NAME = "portName";
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected CoreService coreService;
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected OpenstackNetworkService osNetworkService;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected OpenstackNodeService osNodeService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected LeadershipService leadershipService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected ClusterService clusterService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected OvsdbController ovsdbController;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected DeviceService deviceService;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected InstancePortService instancePortService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected ComponentConfigService componentConfigService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected MastershipService mastershipService;
96
97 @Property(name = OVSDB_PORT, intValue = DEFAULT_OVSDB_PORT,
98 label = "OVSDB server listen port")
99 private int ovsdbPort = DEFAULT_OVSDB_PORT;
100
101 private final OpenstackNetworkListener openstackNetworkListener = new InternalOpenstackNetworkListener();
102
103 private NodeId localNodeId;
104 private ApplicationId appId;
105
106 @Activate
107 void activate() {
108 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
109 localNodeId = clusterService.getLocalNode().id();
110 leadershipService.runForLeadership(appId.name());
111 osNetworkService.addListener(openstackNetworkListener);
112 componentConfigService.registerProperties(getClass());
113
114 log.info("Started");
115 }
116
117 @Deactivate
118 void deactivate() {
119 leadershipService.withdraw(appId.name());
120 osNetworkService.removeListener(openstackNetworkListener);
121 componentConfigService.unregisterProperties(getClass(), false);
122
123 log.info("Stopped");
124 }
125
126
127 @Modified
128 protected void modified(ComponentContext context) {
129 Dictionary<?, ?> properties = context.getProperties();
130 int updatedOvsdbPort = Tools.getIntegerProperty(properties, OVSDB_PORT);
131 if (!Objects.equals(updatedOvsdbPort, ovsdbPort)) {
132 ovsdbPort = updatedOvsdbPort;
133 }
134
135 log.info("Modified");
136 }
137 private void processPortAdded(Port port) {
138 if (!port.getvNicType().equals(DIRECT)) {
139 log.trace("processPortAdded skipped because of unsupported vNicType: {}", port.getvNicType());
140 return;
141 } else if (!port.isAdminStateUp() || port.getVifType().equals(UNBOUND)) {
142 log.trace("processPortAdded skipped because of status: {}, adminStateUp: {}, vifType: {}",
143 port.getState(), port.isAdminStateUp(), port.getVifType());
144 return;
145 } else {
146 InstancePort instancePort = instancePortService.instancePort(port.getId());
147 //Skip this if the instance port for the port id is already created.
148 if (instancePort != null) {
149 return;
150 }
151
152 Optional<OpenstackNode> osNode = osNodeService.completeNodes(COMPUTE).stream()
153 .filter(node -> node.hostname().equals(port.getHostId()))
154 .findAny();
155 if (!osNode.isPresent()) {
156 log.error("processPortAdded failed because openstackNode doesn't exist that matches hostname {}",
157 port.getHostId());
158 return;
159 }
160 log.trace("Retrieved openstackNode: {}", osNode.get().toString());
161
162 String intfName = getIntfNameFromPciAddress(port);
163 if (intfName == null) {
164 log.error("Failed to execute processPortAdded because of null interface name");
165 return;
166 }
167
168 log.trace("Retrieved interface name: {}", intfName);
169
170 osNodeService.addVfPort(osNode.get(), intfName);
171 }
172 }
173
174 private void processPortRemoved(Port port) {
175 if (!port.getvNicType().equals(DIRECT)) {
176 log.trace("processPortRemoved skipped because of unsupported vNicType: {}", port.getvNicType());
177 return;
178 } else if (instancePortService.instancePort(port.getId()) == null) {
179 log.trace("processPortRemoved skipped because no instance port exist for portId: {}", port.getId());
180 return;
181 } else {
182 InstancePort instancePort = instancePortService.instancePort(port.getId());
183 if (instancePort == null) {
184 return;
185 }
186 DeviceId deviceId = instancePort.deviceId();
187 if (deviceId == null) {
188 return;
189 }
190 OpenstackNode osNode = osNodeService.node(deviceId);
191 if (osNode == null) {
192 return;
193 }
194
195 Optional<org.onosproject.net.Port> removedPort = deviceService.getPorts(deviceId).stream()
196 .filter(p -> Objects.equals(p.number(), instancePort.portNumber()))
197 .findAny();
198
199 if (!removedPort.isPresent()) {
200 log.error("Failed to execute processPortAdded because port number doesn't exist");
201 return;
202 }
203
204 String intfName = removedPort.get().annotations().value(PORT_NAME);
205
206 if (intfName == null) {
207 log.error("Failed to execute processPortAdded because of null interface name");
208 return;
209 }
210 log.trace("Retrieved interface name: {}", intfName);
211
212 osNodeService.removeVfPort(osNode, intfName);
213 }
214 }
215
216 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
217 @Override
218 public boolean isRelevant(OpenstackNetworkEvent event) {
219 // do not allow to proceed without leadership
220 NodeId leader = leadershipService.getLeader(appId.name());
221 if (!Objects.equals(localNodeId, leader)) {
222 return false;
223 }
224 return true;
225 }
226
227 @Override
228 public void event(OpenstackNetworkEvent event) {
229 switch (event.type()) {
230 case OPENSTACK_PORT_UPDATED:
231 if (event.port().getState() == State.DOWN) {
232 processPortRemoved(event.port());
233 } else {
234 processPortAdded(event.port());
235 }
236 break;
237 case OPENSTACK_PORT_REMOVED:
238 processPortRemoved(event.port());
239 break;
240 default:
241 break;
242
243 }
244 }
245 }
246}