blob: b399fdfcb6bc85ba67e6b1ee4c58b9e445c37c92 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
2* Copyright 2016-present 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
17package org.onosproject.openstacknetworking.impl;
18
19import com.google.common.base.Strings;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.packet.Ethernet;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
28import org.onosproject.mastership.MastershipService;
29import org.onosproject.net.device.DeviceService;
30import org.onosproject.net.flow.DefaultTrafficSelector;
31import org.onosproject.net.flow.DefaultTrafficTreatment;
32import org.onosproject.net.flow.TrafficSelector;
33import org.onosproject.net.flow.TrafficTreatment;
34import org.onosproject.net.flowobjective.FlowObjectiveService;
35import org.onosproject.net.flowobjective.ForwardingObjective;
36import org.onosproject.openstacknetworking.api.InstancePort;
37import org.onosproject.openstacknetworking.api.InstancePortEvent;
38import org.onosproject.openstacknetworking.api.InstancePortListener;
39import org.onosproject.openstacknetworking.api.InstancePortService;
40import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.openstacknode.OpenstackNodeService;
42import org.openstack4j.model.network.Network;
43import org.slf4j.Logger;
44
45import java.util.concurrent.ExecutorService;
46
47import static java.util.concurrent.Executors.newSingleThreadExecutor;
48import static org.onlab.util.Tools.groupedThreads;
49import static org.onosproject.openstacknetworking.api.Constants.*;
50import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
Hyunsun Moonacde3f52017-02-23 17:57:35 +090051import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import static org.slf4j.LoggerFactory.getLogger;
53
54
55/**
56 * Populates switching flow rules on OVS for the basic connectivity among the
57 * virtual instances in the same network.
58 */
59@Component(immediate = true)
60public final class OpenstackSwitchingHandler {
61
62 private final Logger log = getLogger(getClass());
63
64 private static final String ERR_SET_FLOWS = "Failed to set flows for %s: ";
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected CoreService coreService;
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected MastershipService mastershipService;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected DeviceService deviceService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected FlowObjectiveService flowObjectiveService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected InstancePortService instancePortService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected OpenstackNetworkService osNetworkService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected OpenstackNodeService osNodeService;
86
87 private final ExecutorService eventExecutor = newSingleThreadExecutor(
88 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
89 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
90 private ApplicationId appId;
91
92 @Activate
93 protected void activate() {
94 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
95 instancePortService.addListener(instancePortListener);
96
97 log.info("Started");
98 }
99
100 @Deactivate
101 protected void deactivate() {
102 instancePortService.removeListener(instancePortListener);
103 eventExecutor.shutdown();
104
105 log.info("Stopped");
106 }
107
108 private void setNetworkRules(InstancePort instPort, boolean install) {
109 setTunnelTagFlowRules(instPort, install);
110 setForwardingRules(instPort, install);
111 }
112
113 private void setForwardingRules(InstancePort instPort, boolean install) {
114 // switching rules for the instPorts in the same node
115 TrafficSelector selector = DefaultTrafficSelector.builder()
116 .matchEthType(Ethernet.TYPE_IPV4)
117 .matchIPDst(instPort.ipAddress().toIpPrefix())
118 .matchTunnelId(getVni(instPort))
119 .build();
120
121 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
122 .setEthDst(instPort.macAddress())
123 .setOutput(instPort.portNumber())
124 .build();
125
126 RulePopulatorUtil.setRule(
127 flowObjectiveService,
128 appId,
129 instPort.deviceId(),
130 selector,
131 treatment,
132 ForwardingObjective.Flag.SPECIFIC,
133 PRIORITY_SWITCHING_RULE,
134 install);
135
136 // switching rules for the instPorts in the remote node
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900137 osNodeService.completeNodes().stream()
138 .filter(osNode -> osNode.type() == COMPUTE)
139 .filter(osNode -> !osNode.intBridge().equals(instPort.deviceId()))
140 .forEach(osNode -> {
141 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
142 .extension(buildExtension(
143 deviceService,
144 osNode.intBridge(),
145 osNodeService.dataIp(instPort.deviceId()).get().getIp4Address()),
146 osNode.intBridge())
147 .setOutput(osNodeService.tunnelPort(osNode.intBridge()).get())
148 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900150 RulePopulatorUtil.setRule(
151 flowObjectiveService,
152 appId,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900153 osNode.intBridge(),
Hyunsun Moonacde3f52017-02-23 17:57:35 +0900154 selector,
155 treatmentToRemote,
156 ForwardingObjective.Flag.SPECIFIC,
157 PRIORITY_SWITCHING_RULE,
158 install);
159 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160 }
161
162 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
163 TrafficSelector selector = DefaultTrafficSelector.builder()
164 .matchEthType(Ethernet.TYPE_IPV4)
165 .matchInPort(instPort.portNumber())
166 .build();
167
168 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
169 .setTunnelId(getVni(instPort))
170 .build();
171
172 RulePopulatorUtil.setRule(
173 flowObjectiveService,
174 appId,
175 instPort.deviceId(),
176 selector,
177 treatment,
178 ForwardingObjective.Flag.SPECIFIC,
179 PRIORITY_TUNNEL_TAG_RULE,
180 install);
181 }
182
183 private Long getVni(InstancePort instPort) {
184 Network osNet = osNetworkService.network(instPort.networkId());
185 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
186 final String error = String.format(
187 ERR_SET_FLOWS + "Failed to get VNI for %s",
rohit8e5c8992017-03-29 19:15:30 +0530188 instPort, osNet == null ? "<none>" : osNet.getName());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900189 throw new IllegalStateException(error);
190 }
191 return Long.valueOf(osNet.getProviderSegID());
192 }
193
194 private class InternalInstancePortListener implements InstancePortListener {
195
196 @Override
197 public boolean isRelevant(InstancePortEvent event) {
198 InstancePort instPort = event.subject();
199 return mastershipService.isLocalMaster(instPort.deviceId());
200 }
201
202 @Override
203 public void event(InstancePortEvent event) {
204 InstancePort instPort = event.subject();
205 switch (event.type()) {
206 case OPENSTACK_INSTANCE_PORT_UPDATED:
207 case OPENSTACK_INSTANCE_PORT_DETECTED:
208 eventExecutor.execute(() -> {
209 log.info("Instance port detected MAC:{} IP:{}",
210 instPort.macAddress(),
211 instPort.ipAddress());
212 instPortDetected(event.subject());
213 });
214 break;
215 case OPENSTACK_INSTANCE_PORT_VANISHED:
216 eventExecutor.execute(() -> {
217 log.info("Instance port vanished MAC:{} IP:{}",
218 instPort.macAddress(),
219 instPort.ipAddress());
220 instPortRemoved(event.subject());
221 });
222 break;
223 default:
224 break;
225 }
226 }
227
228 private void instPortDetected(InstancePort instPort) {
229 setNetworkRules(instPort, true);
230 // TODO add something else if needed
231 }
232
233 private void instPortRemoved(InstancePort instPort) {
234 setNetworkRules(instPort, false);
235 // TODO add something else if needed
236 }
237 }
238}