Committed by
Gerrit Code Review
CORD-380 Added host provider for cordvtn service
- Renamed CordVtnConfigManager to CordVtnNodeManager - Moved all node bootstrap logic to CordVtnNodeManager - CordVtnService now provides VM add/remove and service dependency create/remove - Made CordVtn implement HostProvider so that it can inject/eject VM to the system Change-Id: I0011ac692ecea240d2d7fe48b3e7a1db4973b76e
Showing
10 changed files
with
1025 additions
and
941 deletions
... | @@ -15,7 +15,6 @@ | ... | @@ -15,7 +15,6 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.cordvtn; | 16 | package org.onosproject.cordvtn; |
17 | 17 | ||
18 | -import com.google.common.collect.Maps; | ||
19 | import com.google.common.collect.Sets; | 18 | import com.google.common.collect.Sets; |
20 | import org.apache.felix.scr.annotations.Activate; | 19 | import org.apache.felix.scr.annotations.Activate; |
21 | import org.apache.felix.scr.annotations.Component; | 20 | import org.apache.felix.scr.annotations.Component; |
... | @@ -24,59 +23,43 @@ import org.apache.felix.scr.annotations.Reference; | ... | @@ -24,59 +23,43 @@ import org.apache.felix.scr.annotations.Reference; |
24 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 23 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
25 | import org.apache.felix.scr.annotations.Service; | 24 | import org.apache.felix.scr.annotations.Service; |
26 | import org.onlab.packet.Ethernet; | 25 | import org.onlab.packet.Ethernet; |
27 | -import org.onlab.packet.Ip4Address; | ||
28 | -import org.onlab.util.ItemNotFoundException; | ||
29 | import org.onlab.packet.IpAddress; | 26 | import org.onlab.packet.IpAddress; |
30 | -import org.onlab.util.KryoNamespace; | 27 | +import org.onlab.packet.MacAddress; |
31 | -import org.onosproject.cluster.ClusterService; | 28 | +import org.onlab.packet.VlanId; |
32 | import org.onosproject.core.ApplicationId; | 29 | import org.onosproject.core.ApplicationId; |
33 | import org.onosproject.core.CoreService; | 30 | import org.onosproject.core.CoreService; |
34 | import org.onosproject.mastership.MastershipService; | 31 | import org.onosproject.mastership.MastershipService; |
32 | +import org.onosproject.net.ConnectPoint; | ||
35 | import org.onosproject.net.DefaultAnnotations; | 33 | import org.onosproject.net.DefaultAnnotations; |
36 | -import org.onosproject.net.Device; | ||
37 | -import org.onosproject.net.DeviceId; | ||
38 | import org.onosproject.net.Host; | 34 | import org.onosproject.net.Host; |
39 | import org.onosproject.net.HostId; | 35 | import org.onosproject.net.HostId; |
36 | +import org.onosproject.net.HostLocation; | ||
40 | import org.onosproject.net.Port; | 37 | import org.onosproject.net.Port; |
41 | -import org.onosproject.net.behaviour.BridgeConfig; | 38 | +import org.onosproject.net.SparseAnnotations; |
42 | -import org.onosproject.net.behaviour.BridgeName; | ||
43 | -import org.onosproject.net.behaviour.ControllerInfo; | ||
44 | -import org.onosproject.net.behaviour.DefaultTunnelDescription; | ||
45 | -import org.onosproject.net.behaviour.TunnelConfig; | ||
46 | -import org.onosproject.net.behaviour.TunnelDescription; | ||
47 | -import org.onosproject.net.behaviour.TunnelName; | ||
48 | -import org.onosproject.net.device.DeviceAdminService; | ||
49 | -import org.onosproject.net.device.DeviceEvent; | ||
50 | -import org.onosproject.net.device.DeviceListener; | ||
51 | import org.onosproject.net.device.DeviceService; | 39 | import org.onosproject.net.device.DeviceService; |
52 | -import org.onosproject.net.driver.DriverHandler; | ||
53 | import org.onosproject.net.driver.DriverService; | 40 | import org.onosproject.net.driver.DriverService; |
54 | import org.onosproject.net.flow.FlowRuleService; | 41 | import org.onosproject.net.flow.FlowRuleService; |
55 | import org.onosproject.net.group.GroupService; | 42 | import org.onosproject.net.group.GroupService; |
43 | +import org.onosproject.net.host.DefaultHostDescription; | ||
44 | +import org.onosproject.net.host.HostDescription; | ||
56 | import org.onosproject.net.host.HostEvent; | 45 | import org.onosproject.net.host.HostEvent; |
57 | import org.onosproject.net.host.HostListener; | 46 | import org.onosproject.net.host.HostListener; |
47 | +import org.onosproject.net.host.HostProvider; | ||
48 | +import org.onosproject.net.host.HostProviderRegistry; | ||
49 | +import org.onosproject.net.host.HostProviderService; | ||
58 | import org.onosproject.net.host.HostService; | 50 | import org.onosproject.net.host.HostService; |
59 | import org.onosproject.net.packet.PacketContext; | 51 | import org.onosproject.net.packet.PacketContext; |
60 | import org.onosproject.net.packet.PacketProcessor; | 52 | import org.onosproject.net.packet.PacketProcessor; |
61 | import org.onosproject.net.packet.PacketService; | 53 | import org.onosproject.net.packet.PacketService; |
54 | +import org.onosproject.net.provider.AbstractProvider; | ||
55 | +import org.onosproject.net.provider.ProviderId; | ||
62 | import org.onosproject.openstackswitching.OpenstackNetwork; | 56 | import org.onosproject.openstackswitching.OpenstackNetwork; |
63 | import org.onosproject.openstackswitching.OpenstackPort; | 57 | import org.onosproject.openstackswitching.OpenstackPort; |
64 | import org.onosproject.openstackswitching.OpenstackSubnet; | 58 | import org.onosproject.openstackswitching.OpenstackSubnet; |
65 | import org.onosproject.openstackswitching.OpenstackSwitchingService; | 59 | import org.onosproject.openstackswitching.OpenstackSwitchingService; |
66 | -import org.onosproject.ovsdb.controller.OvsdbClientService; | ||
67 | -import org.onosproject.ovsdb.controller.OvsdbController; | ||
68 | -import org.onosproject.ovsdb.controller.OvsdbNodeId; | ||
69 | -import org.onosproject.store.serializers.KryoNamespaces; | ||
70 | -import org.onosproject.store.service.ConsistentMap; | ||
71 | -import org.onosproject.store.service.Serializer; | ||
72 | -import org.onosproject.store.service.StorageService; | ||
73 | import org.slf4j.Logger; | 60 | import org.slf4j.Logger; |
74 | 61 | ||
75 | -import java.util.ArrayList; | ||
76 | -import java.util.HashMap; | ||
77 | -import java.util.List; | ||
78 | import java.util.Map; | 62 | import java.util.Map; |
79 | -import java.util.Objects; | ||
80 | import java.util.Set; | 63 | import java.util.Set; |
81 | import java.util.concurrent.ExecutorService; | 64 | import java.util.concurrent.ExecutorService; |
82 | import java.util.concurrent.Executors; | 65 | import java.util.concurrent.Executors; |
... | @@ -84,8 +67,6 @@ import java.util.stream.Collectors; | ... | @@ -84,8 +67,6 @@ import java.util.stream.Collectors; |
84 | 67 | ||
85 | import static com.google.common.base.Preconditions.checkNotNull; | 68 | import static com.google.common.base.Preconditions.checkNotNull; |
86 | import static org.onlab.util.Tools.groupedThreads; | 69 | import static org.onlab.util.Tools.groupedThreads; |
87 | -import static org.onosproject.net.Device.Type.SWITCH; | ||
88 | -import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN; | ||
89 | import static org.slf4j.LoggerFactory.getLogger; | 70 | import static org.slf4j.LoggerFactory.getLogger; |
90 | 71 | ||
91 | /** | 72 | /** |
... | @@ -94,36 +75,15 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -94,36 +75,15 @@ import static org.slf4j.LoggerFactory.getLogger; |
94 | */ | 75 | */ |
95 | @Component(immediate = true) | 76 | @Component(immediate = true) |
96 | @Service | 77 | @Service |
97 | -public class CordVtn implements CordVtnService { | 78 | +public class CordVtn extends AbstractProvider implements CordVtnService, HostProvider { |
98 | 79 | ||
99 | protected final Logger log = getLogger(getClass()); | 80 | protected final Logger log = getLogger(getClass()); |
100 | 81 | ||
101 | - private static final int NUM_THREADS = 1; | ||
102 | - private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder() | ||
103 | - .register(KryoNamespaces.API) | ||
104 | - .register(CordVtnNode.class) | ||
105 | - .register(NodeState.class); | ||
106 | - | ||
107 | - private static final String DEFAULT_BRIDGE = "br-int"; | ||
108 | - private static final String VPORT_PREFIX = "tap"; | ||
109 | - private static final String DEFAULT_TUNNEL = "vxlan"; | ||
110 | - private static final String OK = "OK"; | ||
111 | - private static final String NO = "NO"; | ||
112 | - | ||
113 | - private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() { | ||
114 | - { | ||
115 | - put("key", "flow"); | ||
116 | - put("remote_ip", "flow"); | ||
117 | - } | ||
118 | - }; | ||
119 | - private static final int DPID_BEGIN = 3; | ||
120 | - private static final int OFPORT = 6653; | ||
121 | - | ||
122 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 82 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
123 | protected CoreService coreService; | 83 | protected CoreService coreService; |
124 | 84 | ||
125 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 85 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
126 | - protected StorageService storageService; | 86 | + protected HostProviderRegistry hostProviderRegistry; |
127 | 87 | ||
128 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 88 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
129 | protected DeviceService deviceService; | 89 | protected DeviceService deviceService; |
... | @@ -135,21 +95,12 @@ public class CordVtn implements CordVtnService { | ... | @@ -135,21 +95,12 @@ public class CordVtn implements CordVtnService { |
135 | protected DriverService driverService; | 95 | protected DriverService driverService; |
136 | 96 | ||
137 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 97 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
138 | - protected DeviceAdminService adminService; | ||
139 | - | ||
140 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
141 | protected FlowRuleService flowRuleService; | 98 | protected FlowRuleService flowRuleService; |
142 | 99 | ||
143 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 100 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
144 | protected PacketService packetService; | 101 | protected PacketService packetService; |
145 | 102 | ||
146 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 103 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
147 | - protected OvsdbController controller; | ||
148 | - | ||
149 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
150 | - protected ClusterService clusterService; | ||
151 | - | ||
152 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
153 | protected MastershipService mastershipService; | 104 | protected MastershipService mastershipService; |
154 | 105 | ||
155 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 106 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
... | @@ -158,76 +109,32 @@ public class CordVtn implements CordVtnService { | ... | @@ -158,76 +109,32 @@ public class CordVtn implements CordVtnService { |
158 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 109 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
159 | protected OpenstackSwitchingService openstackService; | 110 | protected OpenstackSwitchingService openstackService; |
160 | 111 | ||
112 | + private static final int NUM_THREADS = 1; | ||
113 | + private static final String DEFAULT_TUNNEL = "vxlan"; | ||
114 | + private static final String SERVICE_ID = "serviceId"; | ||
115 | + private static final String LOCATION_IP = "locationIp"; | ||
116 | + private static final String OPENSTACK_VM_ID = "openstackVmId"; | ||
117 | + | ||
161 | private final ExecutorService eventExecutor = Executors | 118 | private final ExecutorService eventExecutor = Executors |
162 | .newFixedThreadPool(NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler")); | 119 | .newFixedThreadPool(NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler")); |
163 | 120 | ||
164 | - private final DeviceListener deviceListener = new InternalDeviceListener(); | ||
165 | - private final HostListener hostListener = new InternalHostListener(); | ||
166 | private final PacketProcessor packetProcessor = new InternalPacketProcessor(); | 121 | private final PacketProcessor packetProcessor = new InternalPacketProcessor(); |
122 | + private final HostListener hostListener = new InternalHostListener(); | ||
167 | 123 | ||
168 | - private final OvsdbHandler ovsdbHandler = new OvsdbHandler(); | 124 | + private HostProviderService hostProvider; |
169 | - private final BridgeHandler bridgeHandler = new BridgeHandler(); | ||
170 | - private final VmHandler vmHandler = new VmHandler(); | ||
171 | - | ||
172 | - private ApplicationId appId; | ||
173 | - private ConsistentMap<CordVtnNode, NodeState> nodeStore; | ||
174 | - private Map<HostId, OpenstackNetwork> hostNetMap = Maps.newHashMap(); | ||
175 | private CordVtnRuleInstaller ruleInstaller; | 125 | private CordVtnRuleInstaller ruleInstaller; |
176 | private CordVtnArpProxy arpProxy; | 126 | private CordVtnArpProxy arpProxy; |
177 | 127 | ||
178 | - private enum NodeState { | 128 | + /** |
179 | - | 129 | + * Creates an cordvtn host location provider. |
180 | - INIT { | 130 | + */ |
181 | - @Override | 131 | + public CordVtn() { |
182 | - public void process(CordVtn cordVtn, CordVtnNode node) { | 132 | + super(new ProviderId("host", CORDVTN_APP_ID)); |
183 | - cordVtn.connect(node); | ||
184 | - } | ||
185 | - }, | ||
186 | - OVSDB_CONNECTED { | ||
187 | - @Override | ||
188 | - public void process(CordVtn cordVtn, CordVtnNode node) { | ||
189 | - if (!cordVtn.getOvsdbConnectionState(node)) { | ||
190 | - cordVtn.connect(node); | ||
191 | - } else { | ||
192 | - cordVtn.createIntegrationBridge(node); | ||
193 | - } | ||
194 | - } | ||
195 | - }, | ||
196 | - BRIDGE_CREATED { | ||
197 | - @Override | ||
198 | - public void process(CordVtn cordVtn, CordVtnNode node) { | ||
199 | - if (!cordVtn.getOvsdbConnectionState(node)) { | ||
200 | - cordVtn.connect(node); | ||
201 | - } else { | ||
202 | - cordVtn.createTunnelInterface(node); | ||
203 | - } | ||
204 | - } | ||
205 | - }, | ||
206 | - COMPLETE { | ||
207 | - @Override | ||
208 | - public void process(CordVtn cordVtn, CordVtnNode node) { | ||
209 | - cordVtn.postInit(node); | ||
210 | - } | ||
211 | - }, | ||
212 | - INCOMPLETE { | ||
213 | - @Override | ||
214 | - public void process(CordVtn cordVtn, CordVtnNode node) { | ||
215 | - } | ||
216 | - }; | ||
217 | - | ||
218 | - // TODO Add physical port add state | ||
219 | - | ||
220 | - public abstract void process(CordVtn cordVtn, CordVtnNode node); | ||
221 | } | 133 | } |
222 | 134 | ||
223 | @Activate | 135 | @Activate |
224 | protected void activate() { | 136 | protected void activate() { |
225 | - appId = coreService.registerApplication("org.onosproject.cordvtn"); | 137 | + ApplicationId appId = coreService.registerApplication("org.onosproject.cordvtn"); |
226 | - nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder() | ||
227 | - .withSerializer(Serializer.using(NODE_SERIALIZER.build())) | ||
228 | - .withName("cordvtn-nodestore") | ||
229 | - .withApplicationId(appId) | ||
230 | - .build(); | ||
231 | 138 | ||
232 | ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService, | 139 | ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService, |
233 | deviceService, | 140 | deviceService, |
... | @@ -240,95 +147,29 @@ public class CordVtn implements CordVtnService { | ... | @@ -240,95 +147,29 @@ public class CordVtn implements CordVtnService { |
240 | packetService.addProcessor(packetProcessor, PacketProcessor.director(0)); | 147 | packetService.addProcessor(packetProcessor, PacketProcessor.director(0)); |
241 | arpProxy.requestPacket(); | 148 | arpProxy.requestPacket(); |
242 | 149 | ||
243 | - deviceService.addListener(deviceListener); | ||
244 | hostService.addListener(hostListener); | 150 | hostService.addListener(hostListener); |
151 | + hostProvider = hostProviderRegistry.register(this); | ||
245 | 152 | ||
246 | log.info("Started"); | 153 | log.info("Started"); |
247 | } | 154 | } |
248 | 155 | ||
249 | @Deactivate | 156 | @Deactivate |
250 | protected void deactivate() { | 157 | protected void deactivate() { |
251 | - deviceService.removeListener(deviceListener); | ||
252 | hostService.removeListener(hostListener); | 158 | hostService.removeListener(hostListener); |
253 | packetService.removeProcessor(packetProcessor); | 159 | packetService.removeProcessor(packetProcessor); |
254 | 160 | ||
255 | eventExecutor.shutdown(); | 161 | eventExecutor.shutdown(); |
256 | - nodeStore.clear(); | 162 | + hostProviderRegistry.unregister(this); |
257 | 163 | ||
258 | log.info("Stopped"); | 164 | log.info("Stopped"); |
259 | } | 165 | } |
260 | 166 | ||
261 | @Override | 167 | @Override |
262 | - public void addNode(CordVtnNode node) { | 168 | + public void triggerProbe(Host host) { |
263 | - checkNotNull(node); | 169 | + /* |
264 | - | 170 | + * Note: In CORD deployment, we assume that all hosts are configured. |
265 | - nodeStore.putIfAbsent(node, checkNodeState(node)); | 171 | + * Therefore no probe is required. |
266 | - initNode(node); | 172 | + */ |
267 | - } | ||
268 | - | ||
269 | - @Override | ||
270 | - public void deleteNode(CordVtnNode node) { | ||
271 | - checkNotNull(node); | ||
272 | - | ||
273 | - if (getOvsdbConnectionState(node)) { | ||
274 | - disconnect(node); | ||
275 | - } | ||
276 | - | ||
277 | - nodeStore.remove(node); | ||
278 | - } | ||
279 | - | ||
280 | - @Override | ||
281 | - public int getNodeCount() { | ||
282 | - return nodeStore.size(); | ||
283 | - } | ||
284 | - | ||
285 | - @Override | ||
286 | - public List<CordVtnNode> getNodes() { | ||
287 | - List<CordVtnNode> nodes = new ArrayList<>(); | ||
288 | - nodes.addAll(nodeStore.keySet()); | ||
289 | - return nodes; | ||
290 | - } | ||
291 | - | ||
292 | - @Override | ||
293 | - public void initNode(CordVtnNode node) { | ||
294 | - checkNotNull(node); | ||
295 | - | ||
296 | - if (!nodeStore.containsKey(node)) { | ||
297 | - log.warn("Node {} does not exist, add node first", node.hostname()); | ||
298 | - return; | ||
299 | - } | ||
300 | - | ||
301 | - NodeState state = checkNodeState(node); | ||
302 | - state.process(this, node); | ||
303 | - } | ||
304 | - | ||
305 | - @Override | ||
306 | - public boolean getNodeInitState(CordVtnNode node) { | ||
307 | - checkNotNull(node); | ||
308 | - | ||
309 | - NodeState state = getNodeState(node); | ||
310 | - return state != null && state.equals(NodeState.COMPLETE); | ||
311 | - } | ||
312 | - | ||
313 | - @Override | ||
314 | - public String checkNodeInitState(CordVtnNode node) { | ||
315 | - checkNotNull(node); | ||
316 | - | ||
317 | - NodeState state = getNodeState(node); | ||
318 | - if (state == null) { | ||
319 | - log.warn("Failed to get init state of {}", node.hostname()); | ||
320 | - return null; | ||
321 | - } | ||
322 | - | ||
323 | - String result = String.format( | ||
324 | - "Integration bridge created/connected : %s (%s)%n" + | ||
325 | - "VXLAN interface created : %s%n" + | ||
326 | - "Physical interface added : %s (%s)", | ||
327 | - checkIntegrationBridge(node) ? OK : NO, DEFAULT_BRIDGE, | ||
328 | - checkTunnelInterface(node) ? OK : NO, | ||
329 | - checkPhyInterface(node) ? OK : NO, node.phyPortName()); | ||
330 | - | ||
331 | - return result; | ||
332 | } | 173 | } |
333 | 174 | ||
334 | @Override | 175 | @Override |
... | @@ -341,6 +182,7 @@ public class CordVtn implements CordVtnService { | ... | @@ -341,6 +182,7 @@ public class CordVtn implements CordVtnService { |
341 | return; | 182 | return; |
342 | } | 183 | } |
343 | 184 | ||
185 | + log.info("Service dependency from {} to {} created.", tService.id().id(), pService.id().id()); | ||
344 | ruleInstaller.populateServiceDependencyRules(tService, pService); | 186 | ruleInstaller.populateServiceDependencyRules(tService, pService); |
345 | } | 187 | } |
346 | 188 | ||
... | @@ -354,390 +196,61 @@ public class CordVtn implements CordVtnService { | ... | @@ -354,390 +196,61 @@ public class CordVtn implements CordVtnService { |
354 | return; | 196 | return; |
355 | } | 197 | } |
356 | 198 | ||
199 | + log.info("Service dependency from {} to {} removed.", tService.id().id(), pService.id().id()); | ||
357 | ruleInstaller.removeServiceDependencyRules(tService, pService); | 200 | ruleInstaller.removeServiceDependencyRules(tService, pService); |
358 | } | 201 | } |
359 | 202 | ||
360 | - /** | 203 | + @Override |
361 | - * Returns state of a given cordvtn node. | 204 | + public void addServiceVm(CordVtnNode node, ConnectPoint connectPoint) { |
362 | - * | 205 | + Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port()); |
363 | - * @param node cordvtn node | 206 | + OpenstackPort vPort = openstackService.port(port); |
364 | - * @return node state, or null if no such node exists | 207 | + if (vPort == null) { |
365 | - */ | 208 | + log.warn("Failed to get OpenstackPort for {}", getPortName(port)); |
366 | - private NodeState getNodeState(CordVtnNode node) { | ||
367 | - checkNotNull(node); | ||
368 | - | ||
369 | - try { | ||
370 | - return nodeStore.get(node).value(); | ||
371 | - } catch (NullPointerException e) { | ||
372 | - log.error("Failed to get state of {}", node.hostname()); | ||
373 | - return null; | ||
374 | - } | ||
375 | - } | ||
376 | - | ||
377 | - /** | ||
378 | - * Sets a new state for a given cordvtn node. | ||
379 | - * | ||
380 | - * @param node cordvtn node | ||
381 | - * @param newState new node state | ||
382 | - */ | ||
383 | - private void setNodeState(CordVtnNode node, NodeState newState) { | ||
384 | - checkNotNull(node); | ||
385 | - | ||
386 | - log.info("Changed {} state: {}", node.hostname(), newState.toString()); | ||
387 | - | ||
388 | - nodeStore.put(node, newState); | ||
389 | - newState.process(this, node); | ||
390 | - } | ||
391 | - | ||
392 | - /** | ||
393 | - * Checks current state of a given cordvtn node and returns it. | ||
394 | - * | ||
395 | - * @param node cordvtn node | ||
396 | - * @return node state | ||
397 | - */ | ||
398 | - private NodeState checkNodeState(CordVtnNode node) { | ||
399 | - checkNotNull(node); | ||
400 | - | ||
401 | - if (checkIntegrationBridge(node) && checkTunnelInterface(node)) { | ||
402 | - // TODO add physical port add state | ||
403 | - if (checkPhyInterface(node)) { | ||
404 | - return NodeState.COMPLETE; | ||
405 | - } else { | ||
406 | - return NodeState.INCOMPLETE; | ||
407 | - } | ||
408 | - } else if (checkIntegrationBridge(node)) { | ||
409 | - return NodeState.BRIDGE_CREATED; | ||
410 | - } else if (getOvsdbConnectionState(node)) { | ||
411 | - return NodeState.OVSDB_CONNECTED; | ||
412 | - } else { | ||
413 | - return NodeState.INIT; | ||
414 | - } | ||
415 | - } | ||
416 | - | ||
417 | - /** | ||
418 | - * Performs tasks after node initialization. | ||
419 | - * First disconnect unnecessary OVSDB connection and then installs flow rules | ||
420 | - * for existing VMs if there are any. | ||
421 | - * | ||
422 | - * @param node cordvtn node | ||
423 | - */ | ||
424 | - private void postInit(CordVtnNode node) { | ||
425 | - disconnect(node); | ||
426 | - | ||
427 | - ruleInstaller.init(node.intBrId(), node.phyPortName(), node.localIp()); | ||
428 | - hostService.getConnectedHosts(node.intBrId()) | ||
429 | - .stream() | ||
430 | - .forEach(vmHandler::connected); | ||
431 | - | ||
432 | - log.info("Finished initializing {}", node.hostname()); | ||
433 | - } | ||
434 | - | ||
435 | - /** | ||
436 | - * Returns connection state of OVSDB server for a given node. | ||
437 | - * | ||
438 | - * @param node cordvtn node | ||
439 | - * @return true if it is connected, false otherwise | ||
440 | - */ | ||
441 | - private boolean getOvsdbConnectionState(CordVtnNode node) { | ||
442 | - checkNotNull(node); | ||
443 | - | ||
444 | - OvsdbClientService ovsdbClient = getOvsdbClient(node); | ||
445 | - return deviceService.isAvailable(node.ovsdbId()) && | ||
446 | - ovsdbClient != null && ovsdbClient.isConnected(); | ||
447 | - } | ||
448 | - | ||
449 | - /** | ||
450 | - * Connects to OVSDB server for a given node. | ||
451 | - * | ||
452 | - * @param node cordvtn node | ||
453 | - */ | ||
454 | - private void connect(CordVtnNode node) { | ||
455 | - checkNotNull(node); | ||
456 | - | ||
457 | - if (!nodeStore.containsKey(node)) { | ||
458 | - log.warn("Node {} does not exist", node.hostname()); | ||
459 | - return; | ||
460 | - } | ||
461 | - | ||
462 | - if (!getOvsdbConnectionState(node)) { | ||
463 | - controller.connect(node.ovsdbIp(), node.ovsdbPort()); | ||
464 | - } | ||
465 | - } | ||
466 | - | ||
467 | - /** | ||
468 | - * Disconnects OVSDB server for a given node. | ||
469 | - * | ||
470 | - * @param node cordvtn node | ||
471 | - */ | ||
472 | - private void disconnect(CordVtnNode node) { | ||
473 | - checkNotNull(node); | ||
474 | - | ||
475 | - if (!nodeStore.containsKey(node)) { | ||
476 | - log.warn("Node {} does not exist", node.hostname()); | ||
477 | - return; | ||
478 | - } | ||
479 | - | ||
480 | - if (getOvsdbConnectionState(node)) { | ||
481 | - OvsdbClientService ovsdbClient = getOvsdbClient(node); | ||
482 | - ovsdbClient.disconnect(); | ||
483 | - } | ||
484 | - } | ||
485 | - | ||
486 | - /** | ||
487 | - * Returns cordvtn node associated with a given OVSDB device. | ||
488 | - * | ||
489 | - * @param ovsdbId OVSDB device id | ||
490 | - * @return cordvtn node, null if it fails to find the node | ||
491 | - */ | ||
492 | - private CordVtnNode getNodeByOvsdbId(DeviceId ovsdbId) { | ||
493 | - return getNodes().stream() | ||
494 | - .filter(node -> node.ovsdbId().equals(ovsdbId)) | ||
495 | - .findFirst().orElse(null); | ||
496 | - } | ||
497 | - | ||
498 | - /** | ||
499 | - * Returns cordvtn node associated with a given integration bridge. | ||
500 | - * | ||
501 | - * @param bridgeId device id of integration bridge | ||
502 | - * @return cordvtn node, null if it fails to find the node | ||
503 | - */ | ||
504 | - private CordVtnNode getNodeByBridgeId(DeviceId bridgeId) { | ||
505 | - return getNodes().stream() | ||
506 | - .filter(node -> node.intBrId().equals(bridgeId)) | ||
507 | - .findFirst().orElse(null); | ||
508 | - } | ||
509 | - | ||
510 | - /** | ||
511 | - * Returns port name. | ||
512 | - * | ||
513 | - * @param port port | ||
514 | - * @return port name | ||
515 | - */ | ||
516 | - private String getPortName(Port port) { | ||
517 | - return port.annotations().value("portName"); | ||
518 | - } | ||
519 | - | ||
520 | - /** | ||
521 | - * Returns OVSDB client for a given node. | ||
522 | - * | ||
523 | - * @param node cordvtn node | ||
524 | - * @return OVSDB client, or null if it fails to get OVSDB client | ||
525 | - */ | ||
526 | - private OvsdbClientService getOvsdbClient(CordVtnNode node) { | ||
527 | - checkNotNull(node); | ||
528 | - | ||
529 | - OvsdbClientService ovsdbClient = controller.getOvsdbClient( | ||
530 | - new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt())); | ||
531 | - if (ovsdbClient == null) { | ||
532 | - log.debug("Couldn't find OVSDB client for {}", node.hostname()); | ||
533 | - } | ||
534 | - return ovsdbClient; | ||
535 | - } | ||
536 | - | ||
537 | - /** | ||
538 | - * Creates an integration bridge for a given node. | ||
539 | - * | ||
540 | - * @param node cordvtn node | ||
541 | - */ | ||
542 | - private void createIntegrationBridge(CordVtnNode node) { | ||
543 | - if (checkIntegrationBridge(node)) { | ||
544 | return; | 209 | return; |
545 | } | 210 | } |
546 | 211 | ||
547 | - List<ControllerInfo> controllers = new ArrayList<>(); | 212 | + MacAddress mac = vPort.macAddress(); |
548 | - Sets.newHashSet(clusterService.getNodes()).stream() | 213 | + HostId hostId = HostId.hostId(mac); |
549 | - .forEach(controller -> { | ||
550 | - ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp"); | ||
551 | - controllers.add(ctrlInfo); | ||
552 | - }); | ||
553 | - | ||
554 | - String dpid = node.intBrId().toString().substring(DPID_BEGIN); | ||
555 | - | ||
556 | - try { | ||
557 | - DriverHandler handler = driverService.createHandler(node.ovsdbId()); | ||
558 | - BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class); | ||
559 | - bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE), dpid, controllers); | ||
560 | - } catch (ItemNotFoundException e) { | ||
561 | - log.warn("Failed to create integration bridge on {}", node.ovsdbId()); | ||
562 | - } | ||
563 | - } | ||
564 | 214 | ||
565 | - /** | 215 | + Host host = hostService.getHost(hostId); |
566 | - * Creates tunnel interface to the integration bridge for a given node. | 216 | + if (host != null) { |
567 | - * | 217 | + // Host is already known to the system, no HOST_ADDED event is triggered in this case. |
568 | - * @param node cordvtn node | 218 | + // It happens when the application is restarted. |
569 | - */ | 219 | + // TODO check host description if it has all the information |
570 | - private void createTunnelInterface(CordVtnNode node) { | 220 | + serviceVmAdded(host); |
571 | - if (checkTunnelInterface(node)) { | ||
572 | return; | 221 | return; |
573 | } | 222 | } |
574 | 223 | ||
575 | - DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder(); | 224 | + Set<IpAddress> ip = Sets.newHashSet(vPort.fixedIps().values()); |
576 | - for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) { | 225 | + SparseAnnotations annotations = DefaultAnnotations.builder() |
577 | - optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key)); | 226 | + .set(OPENSTACK_VM_ID, vPort.deviceId()) |
578 | - } | 227 | + .set(SERVICE_ID, vPort.networkId()) |
579 | - | 228 | + .set(LOCATION_IP, node.localIp().toString()) |
580 | - TunnelDescription description = new DefaultTunnelDescription( | 229 | + .build(); |
581 | - null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL), | ||
582 | - optionBuilder.build()); | ||
583 | - | ||
584 | - try { | ||
585 | - DriverHandler handler = driverService.createHandler(node.ovsdbId()); | ||
586 | - TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class); | ||
587 | - tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE), description); | ||
588 | - } catch (ItemNotFoundException e) { | ||
589 | - log.warn("Failed to create tunnel interface on {}", node.ovsdbId()); | ||
590 | - } | ||
591 | - } | ||
592 | - | ||
593 | - /** | ||
594 | - * Checks if integration bridge exists and available. | ||
595 | - * | ||
596 | - * @param node cordvtn node | ||
597 | - * @return true if the bridge is available, false otherwise | ||
598 | - */ | ||
599 | - private boolean checkIntegrationBridge(CordVtnNode node) { | ||
600 | - return (deviceService.getDevice(node.intBrId()) != null | ||
601 | - && deviceService.isAvailable(node.intBrId())); | ||
602 | - } | ||
603 | - | ||
604 | - /** | ||
605 | - * Checks if tunnel interface exists. | ||
606 | - * | ||
607 | - * @param node cordvtn node | ||
608 | - * @return true if the interface exists, false otherwise | ||
609 | - */ | ||
610 | - private boolean checkTunnelInterface(CordVtnNode node) { | ||
611 | - return deviceService.getPorts(node.intBrId()) | ||
612 | - .stream() | ||
613 | - .filter(p -> getPortName(p).contains(DEFAULT_TUNNEL) | ||
614 | - && p.isEnabled()) | ||
615 | - .findAny().isPresent(); | ||
616 | - } | ||
617 | - | ||
618 | - /** | ||
619 | - * Checks if physical interface exists. | ||
620 | - * | ||
621 | - * @param node cordvtn node | ||
622 | - * @return true if the interface exists, false otherwise | ||
623 | - */ | ||
624 | - private boolean checkPhyInterface(CordVtnNode node) { | ||
625 | - return deviceService.getPorts(node.intBrId()) | ||
626 | - .stream() | ||
627 | - .filter(p -> getPortName(p).contains(node.phyPortName()) | ||
628 | - && p.isEnabled()) | ||
629 | - .findAny().isPresent(); | ||
630 | - } | ||
631 | - | ||
632 | - /** | ||
633 | - * Returns remote ip address for tunneling. | ||
634 | - * | ||
635 | - * @param bridgeId device id | ||
636 | - * @return ip address, null if no such device exists | ||
637 | - */ | ||
638 | - private Ip4Address getRemoteIp(DeviceId bridgeId) { | ||
639 | - CordVtnNode node = getNodeByBridgeId(bridgeId); | ||
640 | - if (node != null) { | ||
641 | - return node.localIp().getIp4Address(); | ||
642 | - } else { | ||
643 | - log.debug("Couldn't find node information for {}", bridgeId); | ||
644 | - return null; | ||
645 | - } | ||
646 | - } | ||
647 | - | ||
648 | - /** | ||
649 | - * Returns OpenStack port associated with a given host. | ||
650 | - * | ||
651 | - * @param host host | ||
652 | - * @return OpenStack port, or null if no port has been found | ||
653 | - */ | ||
654 | - private OpenstackPort getOpenstackPortByHost(Host host) { | ||
655 | - Port port = deviceService.getPort(host.location().deviceId(), | ||
656 | - host.location().port()); | ||
657 | - if (port == null) { | ||
658 | - log.debug("Failed to get port for {}", host.id()); | ||
659 | - return null; | ||
660 | - } | ||
661 | - return openstackService.port(port); | ||
662 | - } | ||
663 | - | ||
664 | - /** | ||
665 | - * Returns OpenStack network associated with a given host. | ||
666 | - * | ||
667 | - * @param host host | ||
668 | - * @return OpenStack network, or null if no network has been found | ||
669 | - */ | ||
670 | - private OpenstackNetwork getOpenstackNetworkByHost(Host host) { | ||
671 | - OpenstackPort vPort = getOpenstackPortByHost(host); | ||
672 | - if (vPort != null) { | ||
673 | - return openstackService.network(vPort.networkId()); | ||
674 | - } else { | ||
675 | - return null; | ||
676 | - } | ||
677 | - } | ||
678 | - | ||
679 | - /** | ||
680 | - * Returns hosts associated with a given OpenStack network. | ||
681 | - * | ||
682 | - * @param vNet openstack network | ||
683 | - * @return set of hosts | ||
684 | - */ | ||
685 | - private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) { | ||
686 | - checkNotNull(vNet); | ||
687 | 230 | ||
688 | - Set<Host> hosts = openstackService.ports(vNet.id()).stream() | 231 | + HostDescription hostDesc = new DefaultHostDescription( |
689 | - .filter(port -> port.deviceOwner().contains("compute")) | 232 | + mac, |
690 | - .map(port -> hostService.getHostsByMac(port.macAddress()) | 233 | + VlanId.NONE, |
691 | - .stream() | 234 | + new HostLocation(connectPoint, System.currentTimeMillis()), |
692 | - .findFirst() | 235 | + ip, |
693 | - .orElse(null)) | 236 | + annotations); |
694 | - .collect(Collectors.toSet()); | ||
695 | 237 | ||
696 | - hosts.remove(null); | 238 | + hostProvider.hostDetected(hostId, hostDesc, false); |
697 | - return hosts; | ||
698 | } | 239 | } |
699 | 240 | ||
700 | - /** | 241 | + @Override |
701 | - * Returns host IP assigned by OpenStack. | 242 | + public void removeServiceVm(ConnectPoint connectPoint) { |
702 | - * | 243 | + Host host = hostService.getConnectedHosts(connectPoint) |
703 | - * @param host host | ||
704 | - * @return IPv4 prefix, or null if it fails to get IP from OpenStack | ||
705 | - */ | ||
706 | - private IpAddress getHostIpFromOpenstack(Host host) { | ||
707 | - OpenstackPort vPort = getOpenstackPortByHost(host); | ||
708 | - | ||
709 | - if (vPort == null || vPort.fixedIps().isEmpty()) { | ||
710 | - log.error("Failed to get VM IP for {}", host.id()); | ||
711 | - return null; | ||
712 | - } | ||
713 | - // Assumes there's only one fixed IP is assigned to a port | ||
714 | - return (Ip4Address) vPort.fixedIps().values() | ||
715 | .stream() | 244 | .stream() |
716 | .findFirst() | 245 | .findFirst() |
717 | .orElse(null); | 246 | .orElse(null); |
718 | - } | ||
719 | 247 | ||
720 | - /** | 248 | + if (host == null) { |
721 | - * Returns port name with OpenStack port information. | 249 | + log.debug("No host is connected on {}", connectPoint.toString()); |
722 | - * | 250 | + return; |
723 | - * @param vPort OpenStack port | ||
724 | - * @return port name | ||
725 | - */ | ||
726 | - private String getPortName(OpenstackPort vPort) { | ||
727 | - checkNotNull(vPort); | ||
728 | - return VPORT_PREFIX + vPort.id().substring(0, 10); | ||
729 | } | 251 | } |
730 | 252 | ||
731 | - /** | 253 | + hostProvider.hostVanished(host.id()); |
732 | - * Returns if the host is VM or not. | ||
733 | - * | ||
734 | - * @param host host | ||
735 | - * @return true if the host is a VM. | ||
736 | - */ | ||
737 | - private boolean isVm(Host host) { | ||
738 | - Port port = deviceService.getPort(host.location().deviceId(), | ||
739 | - host.location().port()); | ||
740 | - return getPortName(port).contains(VPORT_PREFIX); | ||
741 | } | 254 | } |
742 | 255 | ||
743 | /** | 256 | /** |
... | @@ -766,8 +279,7 @@ public class CordVtn implements CordVtnService { | ... | @@ -766,8 +279,7 @@ public class CordVtn implements CordVtnService { |
766 | 279 | ||
767 | Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet) | 280 | Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet) |
768 | .stream() | 281 | .stream() |
769 | - .collect(Collectors.toMap(host -> host, | 282 | + .collect(Collectors.toMap(host -> host, this::getTunnelIp)); |
770 | - host -> getRemoteIp(host.location().deviceId()))); | ||
771 | 283 | ||
772 | return new CordService(vNet, subnet, hosts, tServices); | 284 | return new CordService(vNet, subnet, hosts, tServices); |
773 | } | 285 | } |
... | @@ -795,184 +307,72 @@ public class CordVtn implements CordVtnService { | ... | @@ -795,184 +307,72 @@ public class CordVtn implements CordVtnService { |
795 | 307 | ||
796 | Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet) | 308 | Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet) |
797 | .stream() | 309 | .stream() |
798 | - .collect(Collectors.toMap(host -> host, | 310 | + .collect(Collectors.toMap(host -> host, this::getTunnelIp)); |
799 | - host -> getRemoteIp(host.location().deviceId()))); | ||
800 | 311 | ||
801 | return new CordService(vNet, subnet, hosts, tServices); | 312 | return new CordService(vNet, subnet, hosts, tServices); |
802 | } | 313 | } |
803 | 314 | ||
804 | - private class InternalDeviceListener implements DeviceListener { | ||
805 | - | ||
806 | - @Override | ||
807 | - public void event(DeviceEvent event) { | ||
808 | - | ||
809 | - Device device = event.subject(); | ||
810 | - ConnectionHandler<Device> handler = | ||
811 | - (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler); | ||
812 | - | ||
813 | - switch (event.type()) { | ||
814 | - case PORT_ADDED: | ||
815 | - eventExecutor.submit(() -> bridgeHandler.portAdded(event.port())); | ||
816 | - break; | ||
817 | - case PORT_UPDATED: | ||
818 | - if (!event.port().isEnabled()) { | ||
819 | - eventExecutor.submit(() -> bridgeHandler.portRemoved(event.port())); | ||
820 | - } | ||
821 | - break; | ||
822 | - case DEVICE_ADDED: | ||
823 | - case DEVICE_AVAILABILITY_CHANGED: | ||
824 | - if (deviceService.isAvailable(device.id())) { | ||
825 | - eventExecutor.submit(() -> handler.connected(device)); | ||
826 | - } else { | ||
827 | - eventExecutor.submit(() -> handler.disconnected(device)); | ||
828 | - } | ||
829 | - break; | ||
830 | - default: | ||
831 | - break; | ||
832 | - } | ||
833 | - } | ||
834 | - } | ||
835 | - | ||
836 | - private class InternalHostListener implements HostListener { | ||
837 | - | ||
838 | - @Override | ||
839 | - public void event(HostEvent event) { | ||
840 | - Host vm = event.subject(); | ||
841 | - | ||
842 | - switch (event.type()) { | ||
843 | - case HOST_ADDED: | ||
844 | - eventExecutor.submit(() -> vmHandler.connected(vm)); | ||
845 | - break; | ||
846 | - case HOST_REMOVED: | ||
847 | - eventExecutor.submit(() -> vmHandler.disconnected(vm)); | ||
848 | - break; | ||
849 | - default: | ||
850 | - break; | ||
851 | - } | ||
852 | - } | ||
853 | - } | ||
854 | - | ||
855 | - private class OvsdbHandler implements ConnectionHandler<Device> { | ||
856 | - | ||
857 | - @Override | ||
858 | - public void connected(Device device) { | ||
859 | - CordVtnNode node = getNodeByOvsdbId(device.id()); | ||
860 | - if (node != null) { | ||
861 | - setNodeState(node, checkNodeState(node)); | ||
862 | - } else { | ||
863 | - log.debug("Unregistered device {} connected, ignore it.", device.id()); | ||
864 | - } | ||
865 | - } | ||
866 | - | ||
867 | - @Override | ||
868 | - public void disconnected(Device device) { | ||
869 | - if (!deviceService.isAvailable(device.id())) { | ||
870 | - adminService.removeDevice(device.id()); | ||
871 | - } | ||
872 | - } | ||
873 | - } | ||
874 | - | ||
875 | - private class BridgeHandler implements ConnectionHandler<Device> { | ||
876 | - | ||
877 | - @Override | ||
878 | - public void connected(Device device) { | ||
879 | - CordVtnNode node = getNodeByBridgeId(device.id()); | ||
880 | - if (node != null) { | ||
881 | - setNodeState(node, checkNodeState(node)); | ||
882 | - } else { | ||
883 | - log.debug("Unregistered device {} connected, ignore it.", device.id()); | ||
884 | - } | ||
885 | - } | ||
886 | - | ||
887 | - @Override | ||
888 | - public void disconnected(Device device) { | ||
889 | - CordVtnNode node = getNodeByBridgeId(device.id()); | ||
890 | - if (node != null) { | ||
891 | - log.info("Integration Bridge is disconnected from {}", node.hostname()); | ||
892 | - setNodeState(node, NodeState.INCOMPLETE); | ||
893 | - } | ||
894 | - } | ||
895 | - | ||
896 | /** | 315 | /** |
897 | - * Handles port added situation. | 316 | + * Returns IP address for tunneling for a given host. |
898 | - * If the added port is tunnel or physical port, proceed remaining node | ||
899 | - * initialization. Otherwise, do nothing. | ||
900 | * | 317 | * |
901 | - * @param port port | 318 | + * @param host host |
319 | + * @return ip address | ||
902 | */ | 320 | */ |
903 | - public void portAdded(Port port) { | 321 | + private IpAddress getTunnelIp(Host host) { |
904 | - CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id()); | 322 | + return IpAddress.valueOf(host.annotations().value(LOCATION_IP)); |
905 | - if (node == null) { | ||
906 | - return; | ||
907 | - } else { | ||
908 | - log.debug("Port {} added to unregistered device, ignore it.", getPortName(port)); | ||
909 | - } | ||
910 | - | ||
911 | - // TODO add host by updating network config | ||
912 | - String portName = getPortName(port); | ||
913 | - if (!portName.contains(DEFAULT_TUNNEL) && !portName.equals(node.phyPortName())) { | ||
914 | - return; | ||
915 | - } | ||
916 | - | ||
917 | - log.info("Port {} is added to {}", portName, node.hostname()); | ||
918 | - setNodeState(node, checkNodeState(node)); | ||
919 | } | 323 | } |
920 | 324 | ||
921 | /** | 325 | /** |
922 | - * Handles port removed situation. | 326 | + * Returns port name. |
923 | - * If the removed port is tunnel or physical port, proceed remaining node | ||
924 | - * initialization.Others, do nothing. | ||
925 | * | 327 | * |
926 | * @param port port | 328 | * @param port port |
329 | + * @return port name | ||
927 | */ | 330 | */ |
928 | - public void portRemoved(Port port) { | 331 | + private String getPortName(Port port) { |
929 | - CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id()); | 332 | + return port.annotations().value("portName"); |
930 | - if (node == null) { | ||
931 | - return; | ||
932 | - } | ||
933 | - | ||
934 | - // TODO remove host by updating network config | ||
935 | - String portName = getPortName(port); | ||
936 | - if (!portName.contains(DEFAULT_TUNNEL) && !portName.equals(node.phyPortName())) { | ||
937 | - return; | ||
938 | - } | ||
939 | - | ||
940 | - log.info("Port {} is removed from {}", portName, node.hostname()); | ||
941 | - setNodeState(node, NodeState.INCOMPLETE); | ||
942 | - } | ||
943 | } | 333 | } |
944 | 334 | ||
945 | - private class VmHandler implements ConnectionHandler<Host> { | 335 | + /** |
336 | + * Returns hosts associated with a given OpenStack network. | ||
337 | + * | ||
338 | + * @param vNet openstack network | ||
339 | + * @return set of hosts | ||
340 | + */ | ||
341 | + private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) { | ||
342 | + checkNotNull(vNet); | ||
946 | 343 | ||
947 | - @Override | 344 | + Set<Host> hosts = openstackService.ports(vNet.id()).stream() |
948 | - public void connected(Host host) { | 345 | + .filter(port -> port.deviceOwner().contains("compute")) |
949 | - // TODO remove check VM here after applying network config host provider | 346 | + .map(port -> hostService.getHostsByMac(port.macAddress()) |
950 | - if (!isVm(host)) { | 347 | + .stream() |
951 | - log.debug("Host {} is not a VM, ignore it.", host.id()); | 348 | + .findFirst() |
952 | - return; | 349 | + .orElse(null)) |
953 | - } | 350 | + .collect(Collectors.toSet()); |
954 | 351 | ||
955 | - CordVtnNode node = getNodeByBridgeId(host.location().deviceId()); | 352 | + hosts.remove(null); |
956 | - if (node == null || !Objects.equals(getNodeState(node), NodeState.COMPLETE)) { | 353 | + return hosts; |
957 | - log.debug("VM {} is detected unknown or incomplete device, ignore it.", host.id()); | ||
958 | - return; | ||
959 | } | 354 | } |
960 | 355 | ||
961 | - OpenstackNetwork vNet = getOpenstackNetworkByHost(host); | 356 | + /** |
357 | + * Handles VM detected situation. | ||
358 | + * | ||
359 | + * @param host host | ||
360 | + */ | ||
361 | + private void serviceVmAdded(Host host) { | ||
362 | + String vNetId = host.annotations().value(SERVICE_ID); | ||
363 | + OpenstackNetwork vNet = openstackService.network(vNetId); | ||
962 | if (vNet == null) { | 364 | if (vNet == null) { |
963 | - log.debug("Failed to get OpenStack network for VM {}, ignore it.", host.id()); | 365 | + log.warn("Failed to get OpenStack network {} for VM {}({}).", |
366 | + vNetId, | ||
367 | + host.id(), | ||
368 | + host.annotations().value(OPENSTACK_VM_ID)); | ||
964 | return; | 369 | return; |
965 | } | 370 | } |
966 | 371 | ||
967 | - // TODO host ip should be set in host information after applying network config host provider | 372 | + log.info("VM {} is detected, MAC: {} IP: {}", |
968 | - IpAddress hostIp = getHostIpFromOpenstack(host); | 373 | + host.annotations().value(OPENSTACK_VM_ID), |
969 | - if (hostIp == null) { | 374 | + host.mac(), |
970 | - log.debug("Failed to get host IP of {}, ignore it.", host.id()); | 375 | + host.ipAddresses().stream().findFirst().get()); |
971 | - return; | ||
972 | - } | ||
973 | - | ||
974 | - log.info("VM {} is detected", host.id()); | ||
975 | - hostNetMap.put(host.id(), vNet); | ||
976 | 376 | ||
977 | CordService service = getCordService(vNet); | 377 | CordService service = getCordService(vNet); |
978 | if (service != null) { | 378 | if (service != null) { |
... | @@ -981,27 +381,30 @@ public class CordVtn implements CordVtnService { | ... | @@ -981,27 +381,30 @@ public class CordVtn implements CordVtnService { |
981 | arpProxy.addServiceIp(service.serviceIp()); | 381 | arpProxy.addServiceIp(service.serviceIp()); |
982 | } | 382 | } |
983 | 383 | ||
984 | - ruleInstaller.populateBasicConnectionRules( | 384 | + ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet); |
985 | - host, | ||
986 | - hostIp, | ||
987 | - checkNotNull(getRemoteIp(host.location().deviceId())).getIp4Address(), | ||
988 | - vNet); | ||
989 | } | 385 | } |
990 | 386 | ||
991 | - @Override | 387 | + /** |
992 | - public void disconnected(Host host) { | 388 | + * Handles VM removed situation. |
993 | - CordVtnNode node = getNodeByBridgeId(host.location().deviceId()); | 389 | + * |
994 | - if (node == null || !Objects.equals(getNodeState(node), NodeState.COMPLETE)) { | 390 | + * @param host host |
995 | - // do nothing for the host on unregistered or unprepared device | 391 | + */ |
996 | - return; | 392 | + private void serviceVmRemoved(Host host) { |
997 | - } | 393 | + String vNetId = host.annotations().value(SERVICE_ID); |
998 | - | 394 | + OpenstackNetwork vNet = openstackService.network(host.annotations().value(SERVICE_ID)); |
999 | - OpenstackNetwork vNet = hostNetMap.get(host.id()); | ||
1000 | if (vNet == null) { | 395 | if (vNet == null) { |
396 | + log.warn("Failed to get OpenStack network {} for VM {}({}).", | ||
397 | + vNetId, | ||
398 | + host.id(), | ||
399 | + host.annotations().value(OPENSTACK_VM_ID)); | ||
1001 | return; | 400 | return; |
1002 | } | 401 | } |
1003 | 402 | ||
1004 | - log.info("VM {} is vanished", host.id()); | 403 | + log.info("VM {} is vanished, MAC: {} IP: {}", |
404 | + host.annotations().value(OPENSTACK_VM_ID), | ||
405 | + host.mac(), | ||
406 | + host.ipAddresses().stream().findFirst().get()); | ||
407 | + | ||
1005 | ruleInstaller.removeBasicConnectionRules(host); | 408 | ruleInstaller.removeBasicConnectionRules(host); |
1006 | 409 | ||
1007 | CordService service = getCordService(vNet); | 410 | CordService service = getCordService(vNet); |
... | @@ -1013,8 +416,24 @@ public class CordVtn implements CordVtnService { | ... | @@ -1013,8 +416,24 @@ public class CordVtn implements CordVtnService { |
1013 | arpProxy.removeServiceIp(service.serviceIp()); | 416 | arpProxy.removeServiceIp(service.serviceIp()); |
1014 | } | 417 | } |
1015 | } | 418 | } |
419 | + } | ||
420 | + | ||
421 | + private class InternalHostListener implements HostListener { | ||
1016 | 422 | ||
1017 | - hostNetMap.remove(host.id()); | 423 | + @Override |
424 | + public void event(HostEvent event) { | ||
425 | + Host host = event.subject(); | ||
426 | + | ||
427 | + switch (event.type()) { | ||
428 | + case HOST_ADDED: | ||
429 | + eventExecutor.submit(() -> serviceVmAdded(host)); | ||
430 | + break; | ||
431 | + case HOST_REMOVED: | ||
432 | + eventExecutor.submit(() -> serviceVmRemoved(host)); | ||
433 | + break; | ||
434 | + default: | ||
435 | + break; | ||
436 | + } | ||
1018 | } | 437 | } |
1019 | } | 438 | } |
1020 | 439 | ... | ... |
1 | -/* | ||
2 | - * Copyright 2014-2015 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 | -package org.onosproject.cordvtn; | ||
17 | - | ||
18 | -import org.apache.felix.scr.annotations.Activate; | ||
19 | -import org.apache.felix.scr.annotations.Component; | ||
20 | -import org.apache.felix.scr.annotations.Deactivate; | ||
21 | -import org.apache.felix.scr.annotations.Reference; | ||
22 | -import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
23 | -import org.onosproject.core.ApplicationId; | ||
24 | -import org.onosproject.core.CoreService; | ||
25 | -import org.onosproject.net.config.ConfigFactory; | ||
26 | -import org.onosproject.net.config.NetworkConfigEvent; | ||
27 | -import org.onosproject.net.config.NetworkConfigListener; | ||
28 | -import org.onosproject.net.config.NetworkConfigRegistry; | ||
29 | -import org.onosproject.net.config.NetworkConfigService; | ||
30 | -import org.onosproject.net.config.basics.SubjectFactories; | ||
31 | -import org.slf4j.Logger; | ||
32 | - | ||
33 | -import java.util.concurrent.ExecutorService; | ||
34 | - | ||
35 | -import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; | ||
36 | -import static org.onlab.util.Tools.groupedThreads; | ||
37 | -import static org.slf4j.LoggerFactory.getLogger; | ||
38 | - | ||
39 | -/** | ||
40 | - * Reads node information from the network config file and handles the config | ||
41 | - * update events. | ||
42 | - * Only a leader controller performs the node addition or deletion. | ||
43 | - */ | ||
44 | -@Component(immediate = true) | ||
45 | -public class CordVtnConfigManager { | ||
46 | - | ||
47 | - protected final Logger log = getLogger(getClass()); | ||
48 | - | ||
49 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
50 | - protected CoreService coreService; | ||
51 | - | ||
52 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
53 | - protected NetworkConfigRegistry configRegistry; | ||
54 | - | ||
55 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
56 | - protected NetworkConfigService configService; | ||
57 | - | ||
58 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
59 | - protected CordVtnService cordVtnService; | ||
60 | - | ||
61 | - private final ConfigFactory configFactory = | ||
62 | - new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") { | ||
63 | - @Override | ||
64 | - public CordVtnConfig createConfig() { | ||
65 | - return new CordVtnConfig(); | ||
66 | - } | ||
67 | - }; | ||
68 | - | ||
69 | - private final NetworkConfigListener configListener = new InternalConfigListener(); | ||
70 | - private ApplicationId appId; | ||
71 | - protected ExecutorService eventExecutor; | ||
72 | - | ||
73 | - | ||
74 | - @Activate | ||
75 | - protected void active() { | ||
76 | - appId = coreService.getAppId(CordVtnService.CORDVTN_APP_ID); | ||
77 | - | ||
78 | - eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtncfg", "event-handler")); | ||
79 | - configService.addListener(configListener); | ||
80 | - configRegistry.registerConfigFactory(configFactory); | ||
81 | - } | ||
82 | - | ||
83 | - @Deactivate | ||
84 | - protected void deactivate() { | ||
85 | - configRegistry.unregisterConfigFactory(configFactory); | ||
86 | - configService.removeListener(configListener); | ||
87 | - eventExecutor.shutdown(); | ||
88 | - } | ||
89 | - | ||
90 | - private void readConfiguration() { | ||
91 | - CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class); | ||
92 | - | ||
93 | - if (config == null) { | ||
94 | - log.warn("No configuration found"); | ||
95 | - return; | ||
96 | - } | ||
97 | - | ||
98 | - config.cordVtnNodes().forEach(node -> { | ||
99 | - CordVtnNode cordVtnNode = new CordVtnNode( | ||
100 | - node.hostname(), | ||
101 | - node.ovsdbIp(), | ||
102 | - node.ovsdbPort(), | ||
103 | - node.bridgeId(), | ||
104 | - node.phyPortName(), | ||
105 | - node.localIp()); | ||
106 | - | ||
107 | - cordVtnService.addNode(cordVtnNode); | ||
108 | - }); | ||
109 | - } | ||
110 | - | ||
111 | - private class InternalConfigListener implements NetworkConfigListener { | ||
112 | - | ||
113 | - @Override | ||
114 | - public void event(NetworkConfigEvent event) { | ||
115 | - if (!event.configClass().equals(CordVtnConfig.class)) { | ||
116 | - return; | ||
117 | - } | ||
118 | - | ||
119 | - switch (event.type()) { | ||
120 | - case CONFIG_ADDED: | ||
121 | - log.info("Network configuration added"); | ||
122 | - eventExecutor.execute(CordVtnConfigManager.this::readConfiguration); | ||
123 | - break; | ||
124 | - case CONFIG_UPDATED: | ||
125 | - log.info("Network configuration updated"); | ||
126 | - eventExecutor.execute(CordVtnConfigManager.this::readConfiguration); | ||
127 | - break; | ||
128 | - default: | ||
129 | - break; | ||
130 | - } | ||
131 | - } | ||
132 | - } | ||
133 | -} |
1 | +/* | ||
2 | + * Copyright 2014-2015 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 | +package org.onosproject.cordvtn; | ||
17 | + | ||
18 | +import com.google.common.collect.Sets; | ||
19 | +import org.apache.felix.scr.annotations.Activate; | ||
20 | +import org.apache.felix.scr.annotations.Component; | ||
21 | +import org.apache.felix.scr.annotations.Deactivate; | ||
22 | +import org.apache.felix.scr.annotations.Reference; | ||
23 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
24 | +import org.apache.felix.scr.annotations.Service; | ||
25 | +import org.onlab.util.ItemNotFoundException; | ||
26 | +import org.onlab.util.KryoNamespace; | ||
27 | +import org.onosproject.cluster.ClusterService; | ||
28 | +import org.onosproject.core.ApplicationId; | ||
29 | +import org.onosproject.core.CoreService; | ||
30 | +import org.onosproject.mastership.MastershipService; | ||
31 | +import org.onosproject.net.ConnectPoint; | ||
32 | +import org.onosproject.net.DefaultAnnotations; | ||
33 | +import org.onosproject.net.Device; | ||
34 | +import org.onosproject.net.DeviceId; | ||
35 | +import org.onosproject.net.Host; | ||
36 | +import org.onosproject.net.Port; | ||
37 | +import org.onosproject.net.behaviour.BridgeConfig; | ||
38 | +import org.onosproject.net.behaviour.BridgeName; | ||
39 | +import org.onosproject.net.behaviour.ControllerInfo; | ||
40 | +import org.onosproject.net.behaviour.DefaultTunnelDescription; | ||
41 | +import org.onosproject.net.behaviour.TunnelConfig; | ||
42 | +import org.onosproject.net.behaviour.TunnelDescription; | ||
43 | +import org.onosproject.net.behaviour.TunnelName; | ||
44 | +import org.onosproject.net.config.ConfigFactory; | ||
45 | +import org.onosproject.net.config.NetworkConfigEvent; | ||
46 | +import org.onosproject.net.config.NetworkConfigListener; | ||
47 | +import org.onosproject.net.config.NetworkConfigRegistry; | ||
48 | +import org.onosproject.net.config.NetworkConfigService; | ||
49 | +import org.onosproject.net.config.basics.SubjectFactories; | ||
50 | +import org.onosproject.net.device.DeviceAdminService; | ||
51 | +import org.onosproject.net.device.DeviceEvent; | ||
52 | +import org.onosproject.net.device.DeviceListener; | ||
53 | +import org.onosproject.net.device.DeviceService; | ||
54 | +import org.onosproject.net.driver.DriverHandler; | ||
55 | +import org.onosproject.net.driver.DriverService; | ||
56 | +import org.onosproject.net.flow.FlowRuleService; | ||
57 | +import org.onosproject.net.group.GroupService; | ||
58 | +import org.onosproject.net.host.HostService; | ||
59 | +import org.onosproject.ovsdb.controller.OvsdbClientService; | ||
60 | +import org.onosproject.ovsdb.controller.OvsdbController; | ||
61 | +import org.onosproject.ovsdb.controller.OvsdbNodeId; | ||
62 | +import org.onosproject.store.serializers.KryoNamespaces; | ||
63 | +import org.onosproject.store.service.ConsistentMap; | ||
64 | +import org.onosproject.store.service.Serializer; | ||
65 | +import org.onosproject.store.service.StorageService; | ||
66 | +import org.slf4j.Logger; | ||
67 | + | ||
68 | +import java.util.ArrayList; | ||
69 | +import java.util.HashMap; | ||
70 | +import java.util.List; | ||
71 | +import java.util.Map; | ||
72 | +import java.util.concurrent.ExecutorService; | ||
73 | + | ||
74 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
75 | +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; | ||
76 | +import static org.onlab.util.Tools.groupedThreads; | ||
77 | +import static org.onosproject.net.Device.Type.SWITCH; | ||
78 | +import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN; | ||
79 | +import static org.slf4j.LoggerFactory.getLogger; | ||
80 | + | ||
81 | +/** | ||
82 | + * Reads node information from the network config file and handles the config | ||
83 | + * update events. | ||
84 | + * Only a leader controller performs the node addition or deletion. | ||
85 | + */ | ||
86 | +@Component(immediate = true) | ||
87 | +@Service(value = CordVtnNodeManager.class) | ||
88 | +public class CordVtnNodeManager { | ||
89 | + | ||
90 | + protected final Logger log = getLogger(getClass()); | ||
91 | + | ||
92 | + private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder() | ||
93 | + .register(KryoNamespaces.API) | ||
94 | + .register(CordVtnNode.class) | ||
95 | + .register(NodeState.class); | ||
96 | + | ||
97 | + private static final String DEFAULT_BRIDGE = "br-int"; | ||
98 | + private static final String DEFAULT_TUNNEL = "vxlan"; | ||
99 | + private static final String VPORT_PREFIX = "tap"; | ||
100 | + private static final String OK = "OK"; | ||
101 | + private static final String NO = "NO"; | ||
102 | + | ||
103 | + private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() { | ||
104 | + { | ||
105 | + put("key", "flow"); | ||
106 | + put("remote_ip", "flow"); | ||
107 | + } | ||
108 | + }; | ||
109 | + private static final int DPID_BEGIN = 3; | ||
110 | + private static final int OFPORT = 6653; | ||
111 | + | ||
112 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
113 | + protected CoreService coreService; | ||
114 | + | ||
115 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
116 | + protected NetworkConfigRegistry configRegistry; | ||
117 | + | ||
118 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
119 | + protected NetworkConfigService configService; | ||
120 | + | ||
121 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
122 | + protected StorageService storageService; | ||
123 | + | ||
124 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
125 | + protected DeviceAdminService adminService; | ||
126 | + | ||
127 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
128 | + protected OvsdbController controller; | ||
129 | + | ||
130 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
131 | + protected ClusterService clusterService; | ||
132 | + | ||
133 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
134 | + protected DriverService driverService; | ||
135 | + | ||
136 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
137 | + protected DeviceService deviceService; | ||
138 | + | ||
139 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
140 | + protected HostService hostService; | ||
141 | + | ||
142 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
143 | + protected FlowRuleService flowRuleService; | ||
144 | + | ||
145 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
146 | + protected MastershipService mastershipService; | ||
147 | + | ||
148 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
149 | + protected GroupService groupService; | ||
150 | + | ||
151 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
152 | + protected CordVtnService cordVtnService; | ||
153 | + | ||
154 | + private final ConfigFactory configFactory = | ||
155 | + new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") { | ||
156 | + @Override | ||
157 | + public CordVtnConfig createConfig() { | ||
158 | + return new CordVtnConfig(); | ||
159 | + } | ||
160 | + }; | ||
161 | + | ||
162 | + private final ExecutorService eventExecutor = | ||
163 | + newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtncfg", "event-handler")); | ||
164 | + | ||
165 | + private final NetworkConfigListener configListener = new InternalConfigListener(); | ||
166 | + private final DeviceListener deviceListener = new InternalDeviceListener(); | ||
167 | + | ||
168 | + private final OvsdbHandler ovsdbHandler = new OvsdbHandler(); | ||
169 | + private final BridgeHandler bridgeHandler = new BridgeHandler(); | ||
170 | + | ||
171 | + private ConsistentMap<CordVtnNode, NodeState> nodeStore; | ||
172 | + private CordVtnRuleInstaller ruleInstaller; | ||
173 | + private ApplicationId appId; | ||
174 | + | ||
175 | + private enum NodeState { | ||
176 | + | ||
177 | + INIT { | ||
178 | + @Override | ||
179 | + public void process(CordVtnNodeManager nodeManager, CordVtnNode node) { | ||
180 | + nodeManager.connectOvsdb(node); | ||
181 | + } | ||
182 | + }, | ||
183 | + OVSDB_CONNECTED { | ||
184 | + @Override | ||
185 | + public void process(CordVtnNodeManager nodeManager, CordVtnNode node) { | ||
186 | + if (!nodeManager.getOvsdbConnectionState(node)) { | ||
187 | + nodeManager.connectOvsdb(node); | ||
188 | + } else { | ||
189 | + nodeManager.createIntegrationBridge(node); | ||
190 | + } | ||
191 | + } | ||
192 | + }, | ||
193 | + BRIDGE_CREATED { | ||
194 | + @Override | ||
195 | + public void process(CordVtnNodeManager nodeManager, CordVtnNode node) { | ||
196 | + if (!nodeManager.getOvsdbConnectionState(node)) { | ||
197 | + nodeManager.connectOvsdb(node); | ||
198 | + } else { | ||
199 | + nodeManager.createTunnelInterface(node); | ||
200 | + } | ||
201 | + } | ||
202 | + }, | ||
203 | + COMPLETE { | ||
204 | + @Override | ||
205 | + public void process(CordVtnNodeManager nodeManager, CordVtnNode node) { | ||
206 | + nodeManager.postInit(node); | ||
207 | + } | ||
208 | + }, | ||
209 | + INCOMPLETE { | ||
210 | + @Override | ||
211 | + public void process(CordVtnNodeManager nodeManager, CordVtnNode node) { | ||
212 | + } | ||
213 | + }; | ||
214 | + | ||
215 | + // TODO Add physical port add state | ||
216 | + | ||
217 | + public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node); | ||
218 | + } | ||
219 | + | ||
220 | + @Activate | ||
221 | + protected void active() { | ||
222 | + appId = coreService.getAppId(CordVtnService.CORDVTN_APP_ID); | ||
223 | + | ||
224 | + nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder() | ||
225 | + .withSerializer(Serializer.using(NODE_SERIALIZER.build())) | ||
226 | + .withName("cordvtn-nodestore") | ||
227 | + .withApplicationId(appId) | ||
228 | + .build(); | ||
229 | + | ||
230 | + ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService, | ||
231 | + deviceService, | ||
232 | + driverService, | ||
233 | + groupService, | ||
234 | + mastershipService, | ||
235 | + DEFAULT_TUNNEL); | ||
236 | + | ||
237 | + deviceService.addListener(deviceListener); | ||
238 | + configService.addListener(configListener); | ||
239 | + configRegistry.registerConfigFactory(configFactory); | ||
240 | + } | ||
241 | + | ||
242 | + @Deactivate | ||
243 | + protected void deactivate() { | ||
244 | + configRegistry.unregisterConfigFactory(configFactory); | ||
245 | + configService.removeListener(configListener); | ||
246 | + deviceService.removeListener(deviceListener); | ||
247 | + | ||
248 | + eventExecutor.shutdown(); | ||
249 | + nodeStore.clear(); | ||
250 | + } | ||
251 | + | ||
252 | + /** | ||
253 | + * Adds a new node to the service. | ||
254 | + * | ||
255 | + * @param node cordvtn node | ||
256 | + */ | ||
257 | + public void addNode(CordVtnNode node) { | ||
258 | + checkNotNull(node); | ||
259 | + | ||
260 | + nodeStore.putIfAbsent(node, checkNodeState(node)); | ||
261 | + initNode(node); | ||
262 | + } | ||
263 | + | ||
264 | + /** | ||
265 | + * Deletes a node from the service. | ||
266 | + * | ||
267 | + * @param node cordvtn node | ||
268 | + */ | ||
269 | + public void deleteNode(CordVtnNode node) { | ||
270 | + checkNotNull(node); | ||
271 | + | ||
272 | + if (getOvsdbConnectionState(node)) { | ||
273 | + disconnectOvsdb(node); | ||
274 | + } | ||
275 | + | ||
276 | + nodeStore.remove(node); | ||
277 | + } | ||
278 | + | ||
279 | + /** | ||
280 | + * Initiates node to serve virtual tenant network. | ||
281 | + * | ||
282 | + * @param node cordvtn node | ||
283 | + */ | ||
284 | + public void initNode(CordVtnNode node) { | ||
285 | + checkNotNull(node); | ||
286 | + | ||
287 | + if (!nodeStore.containsKey(node)) { | ||
288 | + log.warn("Node {} does not exist, add node first", node.hostname()); | ||
289 | + return; | ||
290 | + } | ||
291 | + | ||
292 | + NodeState state = checkNodeState(node); | ||
293 | + state.process(this, node); | ||
294 | + } | ||
295 | + | ||
296 | + /** | ||
297 | + * Returns node initialization state. | ||
298 | + * | ||
299 | + * @param node cordvtn node | ||
300 | + * @return true if initial node setup is completed, otherwise false | ||
301 | + */ | ||
302 | + public boolean getNodeInitState(CordVtnNode node) { | ||
303 | + checkNotNull(node); | ||
304 | + | ||
305 | + NodeState state = getNodeState(node); | ||
306 | + return state != null && state.equals(NodeState.COMPLETE); | ||
307 | + } | ||
308 | + | ||
309 | + /** | ||
310 | + * Returns detailed node initialization state. | ||
311 | + * Return string includes the following information. | ||
312 | + * | ||
313 | + * Integration bridge created/connected: OK or NO | ||
314 | + * VXLAN interface created: OK or NO | ||
315 | + * Physical interface added: OK or NO | ||
316 | + * | ||
317 | + * @param node cordvtn node | ||
318 | + * @return string including detailed node init state | ||
319 | + */ | ||
320 | + public String checkNodeInitState(CordVtnNode node) { | ||
321 | + checkNotNull(node); | ||
322 | + | ||
323 | + NodeState state = getNodeState(node); | ||
324 | + if (state == null) { | ||
325 | + log.warn("Failed to get init state of {}", node.hostname()); | ||
326 | + return null; | ||
327 | + } | ||
328 | + | ||
329 | + String result = String.format( | ||
330 | + "Integration bridge created/connected : %s (%s)%n" + | ||
331 | + "VXLAN interface created : %s%n" + | ||
332 | + "Physical interface added : %s (%s)", | ||
333 | + checkIntegrationBridge(node) ? OK : NO, DEFAULT_BRIDGE, | ||
334 | + checkTunnelInterface(node) ? OK : NO, | ||
335 | + checkPhyInterface(node) ? OK : NO, node.phyPortName()); | ||
336 | + | ||
337 | + return result; | ||
338 | + } | ||
339 | + | ||
340 | + /** | ||
341 | + * Returns the number of the nodes known to the service. | ||
342 | + * | ||
343 | + * @return number of nodes | ||
344 | + */ | ||
345 | + public int getNodeCount() { | ||
346 | + return nodeStore.size(); | ||
347 | + } | ||
348 | + | ||
349 | + /** | ||
350 | + * Returns all nodes known to the service. | ||
351 | + * | ||
352 | + * @return list of nodes | ||
353 | + */ | ||
354 | + public List<CordVtnNode> getNodes() { | ||
355 | + List<CordVtnNode> nodes = new ArrayList<>(); | ||
356 | + nodes.addAll(nodeStore.keySet()); | ||
357 | + return nodes; | ||
358 | + } | ||
359 | + | ||
360 | + /** | ||
361 | + * Returns cordvtn node associated with a given OVSDB device. | ||
362 | + * | ||
363 | + * @param ovsdbId OVSDB device id | ||
364 | + * @return cordvtn node, null if it fails to find the node | ||
365 | + */ | ||
366 | + private CordVtnNode getNodeByOvsdbId(DeviceId ovsdbId) { | ||
367 | + return getNodes().stream() | ||
368 | + .filter(node -> node.ovsdbId().equals(ovsdbId)) | ||
369 | + .findFirst().orElse(null); | ||
370 | + } | ||
371 | + | ||
372 | + /** | ||
373 | + * Returns cordvtn node associated with a given integration bridge. | ||
374 | + * | ||
375 | + * @param bridgeId device id of integration bridge | ||
376 | + * @return cordvtn node, null if it fails to find the node | ||
377 | + */ | ||
378 | + private CordVtnNode getNodeByBridgeId(DeviceId bridgeId) { | ||
379 | + return getNodes().stream() | ||
380 | + .filter(node -> node.intBrId().equals(bridgeId)) | ||
381 | + .findFirst().orElse(null); | ||
382 | + } | ||
383 | + | ||
384 | + /** | ||
385 | + * Returns state of a given cordvtn node. | ||
386 | + * | ||
387 | + * @param node cordvtn node | ||
388 | + * @return node state, or null if no such node exists | ||
389 | + */ | ||
390 | + private NodeState getNodeState(CordVtnNode node) { | ||
391 | + checkNotNull(node); | ||
392 | + | ||
393 | + try { | ||
394 | + return nodeStore.get(node).value(); | ||
395 | + } catch (NullPointerException e) { | ||
396 | + log.error("Failed to get state of {}", node.hostname()); | ||
397 | + return null; | ||
398 | + } | ||
399 | + } | ||
400 | + | ||
401 | + /** | ||
402 | + * Sets a new state for a given cordvtn node. | ||
403 | + * | ||
404 | + * @param node cordvtn node | ||
405 | + * @param newState new node state | ||
406 | + */ | ||
407 | + private void setNodeState(CordVtnNode node, NodeState newState) { | ||
408 | + checkNotNull(node); | ||
409 | + | ||
410 | + log.debug("Changed {} state: {}", node.hostname(), newState.toString()); | ||
411 | + | ||
412 | + nodeStore.put(node, newState); | ||
413 | + newState.process(this, node); | ||
414 | + } | ||
415 | + | ||
416 | + /** | ||
417 | + * Checks current state of a given cordvtn node and returns it. | ||
418 | + * | ||
419 | + * @param node cordvtn node | ||
420 | + * @return node state | ||
421 | + */ | ||
422 | + private NodeState checkNodeState(CordVtnNode node) { | ||
423 | + checkNotNull(node); | ||
424 | + | ||
425 | + if (checkIntegrationBridge(node) && checkTunnelInterface(node)) { | ||
426 | + // TODO add physical port add state | ||
427 | + if (checkPhyInterface(node)) { | ||
428 | + return NodeState.COMPLETE; | ||
429 | + } else { | ||
430 | + return NodeState.INCOMPLETE; | ||
431 | + } | ||
432 | + } else if (checkIntegrationBridge(node)) { | ||
433 | + return NodeState.BRIDGE_CREATED; | ||
434 | + } else if (getOvsdbConnectionState(node)) { | ||
435 | + return NodeState.OVSDB_CONNECTED; | ||
436 | + } else { | ||
437 | + return NodeState.INIT; | ||
438 | + } | ||
439 | + } | ||
440 | + | ||
441 | + /** | ||
442 | + * Performs tasks after node initialization. | ||
443 | + * It disconnects unnecessary OVSDB connection and installs initial flow | ||
444 | + * rules on the device. | ||
445 | + * | ||
446 | + * @param node cordvtn node | ||
447 | + */ | ||
448 | + private void postInit(CordVtnNode node) { | ||
449 | + disconnectOvsdb(node); | ||
450 | + | ||
451 | + ruleInstaller.init(node.intBrId(), node.phyPortName(), node.localIp()); | ||
452 | + | ||
453 | + // add existing hosts to the service | ||
454 | + deviceService.getPorts(node.intBrId()).stream() | ||
455 | + .filter(port -> getPortName(port).startsWith(VPORT_PREFIX) && | ||
456 | + port.isEnabled()) | ||
457 | + .forEach(port -> cordVtnService.addServiceVm(node, getConnectPoint(port))); | ||
458 | + | ||
459 | + // remove stale hosts from the service | ||
460 | + hostService.getHosts().forEach(host -> { | ||
461 | + Port port = deviceService.getPort(host.location().deviceId(), host.location().port()); | ||
462 | + if (port == null) { | ||
463 | + cordVtnService.removeServiceVm(getConnectPoint(host)); | ||
464 | + } | ||
465 | + }); | ||
466 | + | ||
467 | + log.info("Finished init {}", node.hostname()); | ||
468 | + } | ||
469 | + | ||
470 | + /** | ||
471 | + * Returns port name. | ||
472 | + * | ||
473 | + * @param port port | ||
474 | + * @return port name | ||
475 | + */ | ||
476 | + private String getPortName(Port port) { | ||
477 | + return port.annotations().value("portName"); | ||
478 | + } | ||
479 | + | ||
480 | + /** | ||
481 | + * Returns connection state of OVSDB server for a given node. | ||
482 | + * | ||
483 | + * @param node cordvtn node | ||
484 | + * @return true if it is connected, false otherwise | ||
485 | + */ | ||
486 | + private boolean getOvsdbConnectionState(CordVtnNode node) { | ||
487 | + checkNotNull(node); | ||
488 | + | ||
489 | + OvsdbClientService ovsdbClient = getOvsdbClient(node); | ||
490 | + return deviceService.isAvailable(node.ovsdbId()) && | ||
491 | + ovsdbClient != null && ovsdbClient.isConnected(); | ||
492 | + } | ||
493 | + | ||
494 | + /** | ||
495 | + * Connects to OVSDB server for a given node. | ||
496 | + * | ||
497 | + * @param node cordvtn node | ||
498 | + */ | ||
499 | + private void connectOvsdb(CordVtnNode node) { | ||
500 | + checkNotNull(node); | ||
501 | + | ||
502 | + if (!nodeStore.containsKey(node)) { | ||
503 | + log.warn("Node {} does not exist", node.hostname()); | ||
504 | + return; | ||
505 | + } | ||
506 | + | ||
507 | + if (!getOvsdbConnectionState(node)) { | ||
508 | + controller.connect(node.ovsdbIp(), node.ovsdbPort()); | ||
509 | + } | ||
510 | + } | ||
511 | + | ||
512 | + /** | ||
513 | + * Disconnects OVSDB server for a given node. | ||
514 | + * | ||
515 | + * @param node cordvtn node | ||
516 | + */ | ||
517 | + private void disconnectOvsdb(CordVtnNode node) { | ||
518 | + checkNotNull(node); | ||
519 | + | ||
520 | + if (!nodeStore.containsKey(node)) { | ||
521 | + log.warn("Node {} does not exist", node.hostname()); | ||
522 | + return; | ||
523 | + } | ||
524 | + | ||
525 | + if (getOvsdbConnectionState(node)) { | ||
526 | + OvsdbClientService ovsdbClient = getOvsdbClient(node); | ||
527 | + ovsdbClient.disconnect(); | ||
528 | + } | ||
529 | + } | ||
530 | + | ||
531 | + /** | ||
532 | + * Returns OVSDB client for a given node. | ||
533 | + * | ||
534 | + * @param node cordvtn node | ||
535 | + * @return OVSDB client, or null if it fails to get OVSDB client | ||
536 | + */ | ||
537 | + private OvsdbClientService getOvsdbClient(CordVtnNode node) { | ||
538 | + checkNotNull(node); | ||
539 | + | ||
540 | + OvsdbClientService ovsdbClient = controller.getOvsdbClient( | ||
541 | + new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt())); | ||
542 | + if (ovsdbClient == null) { | ||
543 | + log.trace("Couldn't find OVSDB client for {}", node.hostname()); | ||
544 | + } | ||
545 | + return ovsdbClient; | ||
546 | + } | ||
547 | + | ||
548 | + /** | ||
549 | + * Creates an integration bridge for a given node. | ||
550 | + * | ||
551 | + * @param node cordvtn node | ||
552 | + */ | ||
553 | + private void createIntegrationBridge(CordVtnNode node) { | ||
554 | + if (checkIntegrationBridge(node)) { | ||
555 | + return; | ||
556 | + } | ||
557 | + | ||
558 | + List<ControllerInfo> controllers = new ArrayList<>(); | ||
559 | + Sets.newHashSet(clusterService.getNodes()).stream() | ||
560 | + .forEach(controller -> { | ||
561 | + ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp"); | ||
562 | + controllers.add(ctrlInfo); | ||
563 | + }); | ||
564 | + | ||
565 | + String dpid = node.intBrId().toString().substring(DPID_BEGIN); | ||
566 | + | ||
567 | + try { | ||
568 | + DriverHandler handler = driverService.createHandler(node.ovsdbId()); | ||
569 | + BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class); | ||
570 | + bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE), dpid, controllers); | ||
571 | + } catch (ItemNotFoundException e) { | ||
572 | + log.warn("Failed to create integration bridge on {}", node.ovsdbId()); | ||
573 | + } | ||
574 | + } | ||
575 | + | ||
576 | + /** | ||
577 | + * Creates tunnel interface to the integration bridge for a given node. | ||
578 | + * | ||
579 | + * @param node cordvtn node | ||
580 | + */ | ||
581 | + private void createTunnelInterface(CordVtnNode node) { | ||
582 | + if (checkTunnelInterface(node)) { | ||
583 | + return; | ||
584 | + } | ||
585 | + | ||
586 | + DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder(); | ||
587 | + for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) { | ||
588 | + optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key)); | ||
589 | + } | ||
590 | + | ||
591 | + TunnelDescription description = new DefaultTunnelDescription( | ||
592 | + null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL), | ||
593 | + optionBuilder.build()); | ||
594 | + | ||
595 | + try { | ||
596 | + DriverHandler handler = driverService.createHandler(node.ovsdbId()); | ||
597 | + TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class); | ||
598 | + tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE), description); | ||
599 | + } catch (ItemNotFoundException e) { | ||
600 | + log.warn("Failed to create tunnel interface on {}", node.ovsdbId()); | ||
601 | + } | ||
602 | + } | ||
603 | + | ||
604 | + /** | ||
605 | + * Checks if integration bridge exists and available. | ||
606 | + * | ||
607 | + * @param node cordvtn node | ||
608 | + * @return true if the bridge is available, false otherwise | ||
609 | + */ | ||
610 | + private boolean checkIntegrationBridge(CordVtnNode node) { | ||
611 | + return (deviceService.getDevice(node.intBrId()) != null | ||
612 | + && deviceService.isAvailable(node.intBrId())); | ||
613 | + } | ||
614 | + | ||
615 | + /** | ||
616 | + * Checks if tunnel interface exists. | ||
617 | + * | ||
618 | + * @param node cordvtn node | ||
619 | + * @return true if the interface exists, false otherwise | ||
620 | + */ | ||
621 | + private boolean checkTunnelInterface(CordVtnNode node) { | ||
622 | + return deviceService.getPorts(node.intBrId()) | ||
623 | + .stream() | ||
624 | + .filter(p -> getPortName(p).contains(DEFAULT_TUNNEL) && | ||
625 | + p.isEnabled()) | ||
626 | + .findAny().isPresent(); | ||
627 | + } | ||
628 | + | ||
629 | + /** | ||
630 | + * Checks if physical interface exists. | ||
631 | + * | ||
632 | + * @param node cordvtn node | ||
633 | + * @return true if the interface exists, false otherwise | ||
634 | + */ | ||
635 | + private boolean checkPhyInterface(CordVtnNode node) { | ||
636 | + return deviceService.getPorts(node.intBrId()) | ||
637 | + .stream() | ||
638 | + .filter(p -> getPortName(p).contains(node.phyPortName()) && | ||
639 | + p.isEnabled()) | ||
640 | + .findAny().isPresent(); | ||
641 | + } | ||
642 | + | ||
643 | + /** | ||
644 | + * Returns connect point of a given port. | ||
645 | + * | ||
646 | + * @param port port | ||
647 | + * @return connect point | ||
648 | + */ | ||
649 | + private ConnectPoint getConnectPoint(Port port) { | ||
650 | + return new ConnectPoint(port.element().id(), port.number()); | ||
651 | + } | ||
652 | + | ||
653 | + /** | ||
654 | + * Returns connect point of a given host. | ||
655 | + * | ||
656 | + * @param host host | ||
657 | + * @return connect point | ||
658 | + */ | ||
659 | + private ConnectPoint getConnectPoint(Host host) { | ||
660 | + return new ConnectPoint(host.location().deviceId(), host.location().port()); | ||
661 | + } | ||
662 | + | ||
663 | + private class OvsdbHandler implements ConnectionHandler<Device> { | ||
664 | + | ||
665 | + @Override | ||
666 | + public void connected(Device device) { | ||
667 | + CordVtnNode node = getNodeByOvsdbId(device.id()); | ||
668 | + if (node != null) { | ||
669 | + setNodeState(node, checkNodeState(node)); | ||
670 | + } else { | ||
671 | + log.debug("{} is detected on unregistered node, ignore it.", device.id()); | ||
672 | + } | ||
673 | + } | ||
674 | + | ||
675 | + @Override | ||
676 | + public void disconnected(Device device) { | ||
677 | + if (!deviceService.isAvailable(device.id())) { | ||
678 | + adminService.removeDevice(device.id()); | ||
679 | + } | ||
680 | + } | ||
681 | + } | ||
682 | + | ||
683 | + private class BridgeHandler implements ConnectionHandler<Device> { | ||
684 | + | ||
685 | + @Override | ||
686 | + public void connected(Device device) { | ||
687 | + CordVtnNode node = getNodeByBridgeId(device.id()); | ||
688 | + if (node != null) { | ||
689 | + setNodeState(node, checkNodeState(node)); | ||
690 | + } else { | ||
691 | + log.debug("{} is detected on unregistered node, ignore it.", device.id()); | ||
692 | + } | ||
693 | + } | ||
694 | + | ||
695 | + @Override | ||
696 | + public void disconnected(Device device) { | ||
697 | + CordVtnNode node = getNodeByBridgeId(device.id()); | ||
698 | + if (node != null) { | ||
699 | + log.debug("Integration Bridge is disconnected from {}", node.hostname()); | ||
700 | + setNodeState(node, NodeState.INCOMPLETE); | ||
701 | + } | ||
702 | + } | ||
703 | + | ||
704 | + /** | ||
705 | + * Handles port added situation. | ||
706 | + * If the added port is tunnel or physical port, proceed remaining node | ||
707 | + * initialization. Otherwise, do nothing. | ||
708 | + * | ||
709 | + * @param port port | ||
710 | + */ | ||
711 | + public void portAdded(Port port) { | ||
712 | + CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id()); | ||
713 | + String portName = getPortName(port); | ||
714 | + | ||
715 | + if (node == null) { | ||
716 | + log.debug("{} is added to unregistered node, ignore it.", portName); | ||
717 | + return; | ||
718 | + } | ||
719 | + | ||
720 | + log.debug("Port {} is added to {}", portName, node.hostname()); | ||
721 | + | ||
722 | + if (portName.startsWith(VPORT_PREFIX)) { | ||
723 | + if (getNodeInitState(node)) { | ||
724 | + cordVtnService.addServiceVm(node, getConnectPoint(port)); | ||
725 | + } else { | ||
726 | + log.debug("VM is detected on incomplete node, ignore it.", portName); | ||
727 | + } | ||
728 | + } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.phyPortName())) { | ||
729 | + setNodeState(node, checkNodeState(node)); | ||
730 | + } | ||
731 | + } | ||
732 | + | ||
733 | + /** | ||
734 | + * Handles port removed situation. | ||
735 | + * If the removed port is tunnel or physical port, proceed remaining node | ||
736 | + * initialization.Others, do nothing. | ||
737 | + * | ||
738 | + * @param port port | ||
739 | + */ | ||
740 | + public void portRemoved(Port port) { | ||
741 | + CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id()); | ||
742 | + String portName = getPortName(port); | ||
743 | + | ||
744 | + if (node == null) { | ||
745 | + return; | ||
746 | + } | ||
747 | + | ||
748 | + log.debug("Port {} is removed from {}", portName, node.hostname()); | ||
749 | + | ||
750 | + if (portName.startsWith(VPORT_PREFIX)) { | ||
751 | + if (getNodeInitState(node)) { | ||
752 | + cordVtnService.removeServiceVm(getConnectPoint(port)); | ||
753 | + } else { | ||
754 | + log.debug("VM is vanished from incomplete node, ignore it.", portName); | ||
755 | + } | ||
756 | + } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.phyPortName())) { | ||
757 | + setNodeState(node, NodeState.INCOMPLETE); | ||
758 | + } | ||
759 | + } | ||
760 | + } | ||
761 | + | ||
762 | + private class InternalDeviceListener implements DeviceListener { | ||
763 | + | ||
764 | + @Override | ||
765 | + public void event(DeviceEvent event) { | ||
766 | + | ||
767 | + Device device = event.subject(); | ||
768 | + ConnectionHandler<Device> handler = | ||
769 | + (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler); | ||
770 | + | ||
771 | + switch (event.type()) { | ||
772 | + case PORT_ADDED: | ||
773 | + eventExecutor.submit(() -> bridgeHandler.portAdded(event.port())); | ||
774 | + break; | ||
775 | + case PORT_UPDATED: | ||
776 | + if (!event.port().isEnabled()) { | ||
777 | + eventExecutor.submit(() -> bridgeHandler.portRemoved(event.port())); | ||
778 | + } | ||
779 | + break; | ||
780 | + case DEVICE_ADDED: | ||
781 | + case DEVICE_AVAILABILITY_CHANGED: | ||
782 | + if (deviceService.isAvailable(device.id())) { | ||
783 | + eventExecutor.submit(() -> handler.connected(device)); | ||
784 | + } else { | ||
785 | + eventExecutor.submit(() -> handler.disconnected(device)); | ||
786 | + } | ||
787 | + break; | ||
788 | + default: | ||
789 | + break; | ||
790 | + } | ||
791 | + } | ||
792 | + } | ||
793 | + | ||
794 | + /** | ||
795 | + * Reads node configuration from config file. | ||
796 | + */ | ||
797 | + private void readConfiguration() { | ||
798 | + CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class); | ||
799 | + | ||
800 | + if (config == null) { | ||
801 | + log.warn("No configuration found"); | ||
802 | + return; | ||
803 | + } | ||
804 | + | ||
805 | + config.cordVtnNodes().forEach(node -> { | ||
806 | + CordVtnNode cordVtnNode = new CordVtnNode( | ||
807 | + node.hostname(), | ||
808 | + node.ovsdbIp(), | ||
809 | + node.ovsdbPort(), | ||
810 | + node.bridgeId(), | ||
811 | + node.phyPortName(), | ||
812 | + node.localIp()); | ||
813 | + | ||
814 | + addNode(cordVtnNode); | ||
815 | + }); | ||
816 | + } | ||
817 | + | ||
818 | + private class InternalConfigListener implements NetworkConfigListener { | ||
819 | + | ||
820 | + @Override | ||
821 | + public void event(NetworkConfigEvent event) { | ||
822 | + if (!event.configClass().equals(CordVtnConfig.class)) { | ||
823 | + return; | ||
824 | + } | ||
825 | + | ||
826 | + switch (event.type()) { | ||
827 | + case CONFIG_ADDED: | ||
828 | + log.info("Network configuration added"); | ||
829 | + eventExecutor.execute(CordVtnNodeManager.this::readConfiguration); | ||
830 | + break; | ||
831 | + case CONFIG_UPDATED: | ||
832 | + log.info("Network configuration updated"); | ||
833 | + eventExecutor.execute(CordVtnNodeManager.this::readConfiguration); | ||
834 | + break; | ||
835 | + default: | ||
836 | + break; | ||
837 | + } | ||
838 | + } | ||
839 | + } | ||
840 | +} |
... | @@ -165,13 +165,10 @@ public class CordVtnRuleInstaller { | ... | @@ -165,13 +165,10 @@ public class CordVtnRuleInstaller { |
165 | * Populates basic rules that connect a VM to the other VMs in the system. | 165 | * Populates basic rules that connect a VM to the other VMs in the system. |
166 | * | 166 | * |
167 | * @param host host | 167 | * @param host host |
168 | - * @param hostIp host ip | ||
169 | * @param tunnelIp tunnel ip | 168 | * @param tunnelIp tunnel ip |
170 | * @param vNet openstack network | 169 | * @param vNet openstack network |
171 | */ | 170 | */ |
172 | - public void populateBasicConnectionRules(Host host, IpAddress hostIp, IpAddress tunnelIp, | 171 | + public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) { |
173 | - OpenstackNetwork vNet) { | ||
174 | - // TODO we can get host ip from host.ip() after applying NetworkConfig host provider | ||
175 | checkNotNull(host); | 172 | checkNotNull(host); |
176 | checkNotNull(vNet); | 173 | checkNotNull(vNet); |
177 | 174 | ||
... | @@ -182,6 +179,7 @@ public class CordVtnRuleInstaller { | ... | @@ -182,6 +179,7 @@ public class CordVtnRuleInstaller { |
182 | 179 | ||
183 | PortNumber inPort = host.location().port(); | 180 | PortNumber inPort = host.location().port(); |
184 | MacAddress dstMac = host.mac(); | 181 | MacAddress dstMac = host.mac(); |
182 | + IpAddress hostIp = host.ipAddresses().stream().findFirst().get(); | ||
185 | long tunnelId = Long.parseLong(vNet.segmentId()); | 183 | long tunnelId = Long.parseLong(vNet.segmentId()); |
186 | 184 | ||
187 | OpenstackSubnet subnet = vNet.subnets().stream() | 185 | OpenstackSubnet subnet = vNet.subnets().stream() |
... | @@ -352,7 +350,7 @@ public class CordVtnRuleInstaller { | ... | @@ -352,7 +350,7 @@ public class CordVtnRuleInstaller { |
352 | 350 | ||
353 | Group group = groupService.getGroup(deviceId, groupKey); | 351 | Group group = groupService.getGroup(deviceId, groupKey); |
354 | if (group == null) { | 352 | if (group == null) { |
355 | - log.debug("No group exists for service {} in {}", service.id(), deviceId); | 353 | + log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId); |
356 | continue; | 354 | continue; |
357 | } | 355 | } |
358 | 356 | ... | ... |
... | @@ -15,7 +15,7 @@ | ... | @@ -15,7 +15,7 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.cordvtn; | 16 | package org.onosproject.cordvtn; |
17 | 17 | ||
18 | -import java.util.List; | 18 | +import org.onosproject.net.ConnectPoint; |
19 | 19 | ||
20 | /** | 20 | /** |
21 | * Service for provisioning overlay virtual networks on compute nodes. | 21 | * Service for provisioning overlay virtual networks on compute nodes. |
... | @@ -23,61 +23,21 @@ import java.util.List; | ... | @@ -23,61 +23,21 @@ import java.util.List; |
23 | public interface CordVtnService { | 23 | public interface CordVtnService { |
24 | 24 | ||
25 | String CORDVTN_APP_ID = "org.onosproject.cordvtn"; | 25 | String CORDVTN_APP_ID = "org.onosproject.cordvtn"; |
26 | - /** | ||
27 | - * Adds a new node to the service. | ||
28 | - * | ||
29 | - * @param node cordvtn node | ||
30 | - */ | ||
31 | - void addNode(CordVtnNode node); | ||
32 | - | ||
33 | - /** | ||
34 | - * Deletes a node from the service. | ||
35 | - * | ||
36 | - * @param node cordvtn node | ||
37 | - */ | ||
38 | - void deleteNode(CordVtnNode node); | ||
39 | - | ||
40 | - /** | ||
41 | - * Initiates node to serve virtual tenant network. | ||
42 | - * | ||
43 | - * @param node cordvtn node | ||
44 | - */ | ||
45 | - void initNode(CordVtnNode node); | ||
46 | - | ||
47 | - /** | ||
48 | - * Returns the number of the nodes known to the service. | ||
49 | - * | ||
50 | - * @return number of nodes | ||
51 | - */ | ||
52 | - int getNodeCount(); | ||
53 | 26 | ||
54 | /** | 27 | /** |
55 | - * Returns node initialization state. | 28 | + * Adds a new VM on a given node and connect point. |
56 | - * | ||
57 | - * @param node cordvtn node | ||
58 | - * @return true if initial node setup is completed, otherwise false | ||
59 | - */ | ||
60 | - boolean getNodeInitState(CordVtnNode node); | ||
61 | - | ||
62 | - /** | ||
63 | - * Returns detailed node initialization state. | ||
64 | - * Return string includes the following information. | ||
65 | - * | ||
66 | - * Integration bridge created/connected: OK or NO | ||
67 | - * VXLAN interface created: OK or NO | ||
68 | - * Physical interface added: OK or NO | ||
69 | * | 29 | * |
70 | * @param node cordvtn node | 30 | * @param node cordvtn node |
71 | - * @return string including detailed node init state | 31 | + * @param connectPoint connect point |
72 | */ | 32 | */ |
73 | - String checkNodeInitState(CordVtnNode node); | 33 | + void addServiceVm(CordVtnNode node, ConnectPoint connectPoint); |
74 | 34 | ||
75 | /** | 35 | /** |
76 | - * Returns all nodes known to the service. | 36 | + * Removes a VM from a given node and connect point. |
77 | * | 37 | * |
78 | - * @return list of nodes | 38 | + * @param connectPoint connect point |
79 | */ | 39 | */ |
80 | - List<CordVtnNode> getNodes(); | 40 | + void removeServiceVm(ConnectPoint connectPoint); |
81 | 41 | ||
82 | /** | 42 | /** |
83 | * Creates dependencies for a given tenant service. | 43 | * Creates dependencies for a given tenant service. | ... | ... |
... | @@ -21,7 +21,7 @@ import org.apache.karaf.shell.commands.Command; | ... | @@ -21,7 +21,7 @@ import org.apache.karaf.shell.commands.Command; |
21 | import org.onlab.packet.IpAddress; | 21 | import org.onlab.packet.IpAddress; |
22 | import org.onlab.packet.TpPort; | 22 | import org.onlab.packet.TpPort; |
23 | import org.onosproject.cli.AbstractShellCommand; | 23 | import org.onosproject.cli.AbstractShellCommand; |
24 | -import org.onosproject.cordvtn.CordVtnService; | 24 | +import org.onosproject.cordvtn.CordVtnNodeManager; |
25 | import org.onosproject.cordvtn.CordVtnNode; | 25 | import org.onosproject.cordvtn.CordVtnNode; |
26 | import org.onosproject.net.DeviceId; | 26 | import org.onosproject.net.DeviceId; |
27 | 27 | ||
... | @@ -63,7 +63,7 @@ public class CordVtnNodeAddCommand extends AbstractShellCommand { | ... | @@ -63,7 +63,7 @@ public class CordVtnNodeAddCommand extends AbstractShellCommand { |
63 | checkArgument(ovsdb.contains(":"), "OVSDB address should be ip:port format"); | 63 | checkArgument(ovsdb.contains(":"), "OVSDB address should be ip:port format"); |
64 | checkArgument(bridgeId.startsWith("of:"), "bridgeId should be of:dpid format"); | 64 | checkArgument(bridgeId.startsWith("of:"), "bridgeId should be of:dpid format"); |
65 | 65 | ||
66 | - CordVtnService service = AbstractShellCommand.get(CordVtnService.class); | 66 | + CordVtnNodeManager nodeManager = AbstractShellCommand.get(CordVtnNodeManager.class); |
67 | String[] ipPort = ovsdb.split(":"); | 67 | String[] ipPort = ovsdb.split(":"); |
68 | CordVtnNode node = new CordVtnNode(hostname, | 68 | CordVtnNode node = new CordVtnNode(hostname, |
69 | IpAddress.valueOf(ipPort[0]), | 69 | IpAddress.valueOf(ipPort[0]), |
... | @@ -71,6 +71,6 @@ public class CordVtnNodeAddCommand extends AbstractShellCommand { | ... | @@ -71,6 +71,6 @@ public class CordVtnNodeAddCommand extends AbstractShellCommand { |
71 | DeviceId.deviceId(bridgeId), | 71 | DeviceId.deviceId(bridgeId), |
72 | phyPortName, | 72 | phyPortName, |
73 | IpAddress.valueOf(localIp)); | 73 | IpAddress.valueOf(localIp)); |
74 | - service.addNode(node); | 74 | + nodeManager.addNode(node); |
75 | } | 75 | } |
76 | } | 76 | } | ... | ... |
... | @@ -20,7 +20,7 @@ import org.apache.karaf.shell.commands.Argument; | ... | @@ -20,7 +20,7 @@ import org.apache.karaf.shell.commands.Argument; |
20 | import org.apache.karaf.shell.commands.Command; | 20 | import org.apache.karaf.shell.commands.Command; |
21 | import org.onosproject.cli.AbstractShellCommand; | 21 | import org.onosproject.cli.AbstractShellCommand; |
22 | import org.onosproject.cordvtn.CordVtnNode; | 22 | import org.onosproject.cordvtn.CordVtnNode; |
23 | -import org.onosproject.cordvtn.CordVtnService; | 23 | +import org.onosproject.cordvtn.CordVtnNodeManager; |
24 | 24 | ||
25 | /** | 25 | /** |
26 | * Checks detailed node init state. | 26 | * Checks detailed node init state. |
... | @@ -35,8 +35,8 @@ public class CordVtnNodeCheckCommand extends AbstractShellCommand { | ... | @@ -35,8 +35,8 @@ public class CordVtnNodeCheckCommand extends AbstractShellCommand { |
35 | 35 | ||
36 | @Override | 36 | @Override |
37 | protected void execute() { | 37 | protected void execute() { |
38 | - CordVtnService service = AbstractShellCommand.get(CordVtnService.class); | 38 | + CordVtnNodeManager nodeManager = AbstractShellCommand.get(CordVtnNodeManager.class); |
39 | - CordVtnNode node = service.getNodes() | 39 | + CordVtnNode node = nodeManager.getNodes() |
40 | .stream() | 40 | .stream() |
41 | .filter(n -> n.hostname().equals(hostname)) | 41 | .filter(n -> n.hostname().equals(hostname)) |
42 | .findFirst() | 42 | .findFirst() |
... | @@ -47,6 +47,6 @@ public class CordVtnNodeCheckCommand extends AbstractShellCommand { | ... | @@ -47,6 +47,6 @@ public class CordVtnNodeCheckCommand extends AbstractShellCommand { |
47 | return; | 47 | return; |
48 | } | 48 | } |
49 | 49 | ||
50 | - print(service.checkNodeInitState(node)); | 50 | + print(nodeManager.checkNodeInitState(node)); |
51 | } | 51 | } |
52 | } | 52 | } | ... | ... |
... | @@ -19,7 +19,7 @@ package org.onosproject.cordvtn.cli; | ... | @@ -19,7 +19,7 @@ package org.onosproject.cordvtn.cli; |
19 | import org.apache.karaf.shell.commands.Argument; | 19 | import org.apache.karaf.shell.commands.Argument; |
20 | import org.apache.karaf.shell.commands.Command; | 20 | import org.apache.karaf.shell.commands.Command; |
21 | import org.onosproject.cli.AbstractShellCommand; | 21 | import org.onosproject.cli.AbstractShellCommand; |
22 | -import org.onosproject.cordvtn.CordVtnService; | 22 | +import org.onosproject.cordvtn.CordVtnNodeManager; |
23 | import org.onosproject.cordvtn.CordVtnNode; | 23 | import org.onosproject.cordvtn.CordVtnNode; |
24 | 24 | ||
25 | import java.util.NoSuchElementException; | 25 | import java.util.NoSuchElementException; |
... | @@ -37,12 +37,12 @@ public class CordVtnNodeDeleteCommand extends AbstractShellCommand { | ... | @@ -37,12 +37,12 @@ public class CordVtnNodeDeleteCommand extends AbstractShellCommand { |
37 | 37 | ||
38 | @Override | 38 | @Override |
39 | protected void execute() { | 39 | protected void execute() { |
40 | - CordVtnService service = AbstractShellCommand.get(CordVtnService.class); | 40 | + CordVtnNodeManager nodeManager = AbstractShellCommand.get(CordVtnNodeManager.class); |
41 | 41 | ||
42 | for (String hostname : hostnames) { | 42 | for (String hostname : hostnames) { |
43 | CordVtnNode node; | 43 | CordVtnNode node; |
44 | try { | 44 | try { |
45 | - node = service.getNodes() | 45 | + node = nodeManager.getNodes() |
46 | .stream() | 46 | .stream() |
47 | .filter(n -> n.hostname().equals(hostname)) | 47 | .filter(n -> n.hostname().equals(hostname)) |
48 | .findFirst().get(); | 48 | .findFirst().get(); |
... | @@ -51,7 +51,7 @@ public class CordVtnNodeDeleteCommand extends AbstractShellCommand { | ... | @@ -51,7 +51,7 @@ public class CordVtnNodeDeleteCommand extends AbstractShellCommand { |
51 | continue; | 51 | continue; |
52 | } | 52 | } |
53 | 53 | ||
54 | - service.deleteNode(node); | 54 | + nodeManager.deleteNode(node); |
55 | } | 55 | } |
56 | } | 56 | } |
57 | } | 57 | } | ... | ... |
... | @@ -19,7 +19,7 @@ package org.onosproject.cordvtn.cli; | ... | @@ -19,7 +19,7 @@ package org.onosproject.cordvtn.cli; |
19 | import org.apache.karaf.shell.commands.Argument; | 19 | import org.apache.karaf.shell.commands.Argument; |
20 | import org.apache.karaf.shell.commands.Command; | 20 | import org.apache.karaf.shell.commands.Command; |
21 | import org.onosproject.cli.AbstractShellCommand; | 21 | import org.onosproject.cli.AbstractShellCommand; |
22 | -import org.onosproject.cordvtn.CordVtnService; | 22 | +import org.onosproject.cordvtn.CordVtnNodeManager; |
23 | import org.onosproject.cordvtn.CordVtnNode; | 23 | import org.onosproject.cordvtn.CordVtnNode; |
24 | 24 | ||
25 | import java.util.NoSuchElementException; | 25 | import java.util.NoSuchElementException; |
... | @@ -37,12 +37,12 @@ public class CordVtnNodeInitCommand extends AbstractShellCommand { | ... | @@ -37,12 +37,12 @@ public class CordVtnNodeInitCommand extends AbstractShellCommand { |
37 | 37 | ||
38 | @Override | 38 | @Override |
39 | protected void execute() { | 39 | protected void execute() { |
40 | - CordVtnService service = AbstractShellCommand.get(CordVtnService.class); | 40 | + CordVtnNodeManager nodeManager = AbstractShellCommand.get(CordVtnNodeManager.class); |
41 | 41 | ||
42 | for (String hostname : hostnames) { | 42 | for (String hostname : hostnames) { |
43 | CordVtnNode node; | 43 | CordVtnNode node; |
44 | try { | 44 | try { |
45 | - node = service.getNodes() | 45 | + node = nodeManager.getNodes() |
46 | .stream() | 46 | .stream() |
47 | .filter(n -> n.hostname().equals(hostname)) | 47 | .filter(n -> n.hostname().equals(hostname)) |
48 | .findFirst().get(); | 48 | .findFirst().get(); |
... | @@ -51,7 +51,7 @@ public class CordVtnNodeInitCommand extends AbstractShellCommand { | ... | @@ -51,7 +51,7 @@ public class CordVtnNodeInitCommand extends AbstractShellCommand { |
51 | continue; | 51 | continue; |
52 | } | 52 | } |
53 | 53 | ||
54 | - service.initNode(node); | 54 | + nodeManager.initNode(node); |
55 | } | 55 | } |
56 | } | 56 | } |
57 | } | 57 | } | ... | ... |
... | @@ -21,7 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; | ... | @@ -21,7 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; |
21 | import com.fasterxml.jackson.databind.node.ArrayNode; | 21 | import com.fasterxml.jackson.databind.node.ArrayNode; |
22 | import org.apache.karaf.shell.commands.Command; | 22 | import org.apache.karaf.shell.commands.Command; |
23 | import org.onosproject.cli.AbstractShellCommand; | 23 | import org.onosproject.cli.AbstractShellCommand; |
24 | -import org.onosproject.cordvtn.CordVtnService; | 24 | +import org.onosproject.cordvtn.CordVtnNodeManager; |
25 | import org.onosproject.cordvtn.CordVtnNode; | 25 | import org.onosproject.cordvtn.CordVtnNode; |
26 | 26 | ||
27 | import java.util.Collections; | 27 | import java.util.Collections; |
... | @@ -36,12 +36,12 @@ public class CordVtnNodeListCommand extends AbstractShellCommand { | ... | @@ -36,12 +36,12 @@ public class CordVtnNodeListCommand extends AbstractShellCommand { |
36 | 36 | ||
37 | @Override | 37 | @Override |
38 | protected void execute() { | 38 | protected void execute() { |
39 | - CordVtnService service = AbstractShellCommand.get(CordVtnService.class); | 39 | + CordVtnNodeManager nodeManager = AbstractShellCommand.get(CordVtnNodeManager.class); |
40 | - List<CordVtnNode> nodes = service.getNodes(); | 40 | + List<CordVtnNode> nodes = nodeManager.getNodes(); |
41 | Collections.sort(nodes, CordVtnNode.CORDVTN_NODE_COMPARATOR); | 41 | Collections.sort(nodes, CordVtnNode.CORDVTN_NODE_COMPARATOR); |
42 | 42 | ||
43 | if (outputJson()) { | 43 | if (outputJson()) { |
44 | - print("%s", json(service, nodes)); | 44 | + print("%s", json(nodeManager, nodes)); |
45 | } else { | 45 | } else { |
46 | for (CordVtnNode node : nodes) { | 46 | for (CordVtnNode node : nodes) { |
47 | print("hostname=%s, ovsdb=%s, br-int=%s, phyPort=%s, localIp=%s, init=%s", | 47 | print("hostname=%s, ovsdb=%s, br-int=%s, phyPort=%s, localIp=%s, init=%s", |
... | @@ -50,13 +50,13 @@ public class CordVtnNodeListCommand extends AbstractShellCommand { | ... | @@ -50,13 +50,13 @@ public class CordVtnNodeListCommand extends AbstractShellCommand { |
50 | node.intBrId().toString(), | 50 | node.intBrId().toString(), |
51 | node.phyPortName(), | 51 | node.phyPortName(), |
52 | node.localIp().toString(), | 52 | node.localIp().toString(), |
53 | - getState(service, node)); | 53 | + getState(nodeManager, node)); |
54 | } | 54 | } |
55 | - print("Total %s nodes", service.getNodeCount()); | 55 | + print("Total %s nodes", nodeManager.getNodeCount()); |
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
59 | - private JsonNode json(CordVtnService service, List<CordVtnNode> nodes) { | 59 | + private JsonNode json(CordVtnNodeManager nodeManager, List<CordVtnNode> nodes) { |
60 | ObjectMapper mapper = new ObjectMapper(); | 60 | ObjectMapper mapper = new ObjectMapper(); |
61 | ArrayNode result = mapper.createArrayNode(); | 61 | ArrayNode result = mapper.createArrayNode(); |
62 | for (CordVtnNode node : nodes) { | 62 | for (CordVtnNode node : nodes) { |
... | @@ -67,12 +67,12 @@ public class CordVtnNodeListCommand extends AbstractShellCommand { | ... | @@ -67,12 +67,12 @@ public class CordVtnNodeListCommand extends AbstractShellCommand { |
67 | .put("brInt", node.intBrId().toString()) | 67 | .put("brInt", node.intBrId().toString()) |
68 | .put("phyPort", node.phyPortName()) | 68 | .put("phyPort", node.phyPortName()) |
69 | .put("localIp", node.localIp().toString()) | 69 | .put("localIp", node.localIp().toString()) |
70 | - .put("init", getState(service, node))); | 70 | + .put("init", getState(nodeManager, node))); |
71 | } | 71 | } |
72 | return result; | 72 | return result; |
73 | } | 73 | } |
74 | 74 | ||
75 | - private String getState(CordVtnService service, CordVtnNode node) { | 75 | + private String getState(CordVtnNodeManager nodeManager, CordVtnNode node) { |
76 | - return service.getNodeInitState(node) ? "COMPLETE" : "INCOMPLETE"; | 76 | + return nodeManager.getNodeInitState(node) ? "COMPLETE" : "INCOMPLETE"; |
77 | } | 77 | } |
78 | } | 78 | } | ... | ... |
-
Please register or login to post a comment