blob: 50d9b37fce555d9461d863f28de2a0f00a70d82c [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;
41import org.onosproject.openstacknode.OpenstackNode;
42import org.onosproject.openstacknode.OpenstackNodeService;
43import org.openstack4j.model.network.Network;
44import org.slf4j.Logger;
45
46import java.util.concurrent.ExecutorService;
47
48import static java.util.concurrent.Executors.newSingleThreadExecutor;
49import static org.onlab.util.Tools.groupedThreads;
50import static org.onosproject.openstacknetworking.api.Constants.*;
51import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
52import 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
137 for (OpenstackNode osNode : osNodeService.completeNodes()) {
138 if (osNode.intBridge().equals(instPort.deviceId())) {
139 continue;
140 }
141
142 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
143 .extension(buildExtension(
144 deviceService,
145 osNode.intBridge(),
146 osNodeService.dataIp(instPort.deviceId()).get().getIp4Address()),
147 osNode.intBridge())
148 .setOutput(osNodeService.tunnelPort(osNode.intBridge()).get())
149 .build();
150
151 RulePopulatorUtil.setRule(
152 flowObjectiveService,
153 appId,
154 osNode.intBridge(),
155 selector,
156 treatmentToRemote,
157 ForwardingObjective.Flag.SPECIFIC,
158 PRIORITY_SWITCHING_RULE,
159 install);
160 }
161 }
162
163 private void setTunnelTagFlowRules(InstancePort instPort, boolean install) {
164 TrafficSelector selector = DefaultTrafficSelector.builder()
165 .matchEthType(Ethernet.TYPE_IPV4)
166 .matchInPort(instPort.portNumber())
167 .build();
168
169 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
170 .setTunnelId(getVni(instPort))
171 .build();
172
173 RulePopulatorUtil.setRule(
174 flowObjectiveService,
175 appId,
176 instPort.deviceId(),
177 selector,
178 treatment,
179 ForwardingObjective.Flag.SPECIFIC,
180 PRIORITY_TUNNEL_TAG_RULE,
181 install);
182 }
183
184 private Long getVni(InstancePort instPort) {
185 Network osNet = osNetworkService.network(instPort.networkId());
186 if (osNet == null || Strings.isNullOrEmpty(osNet.getProviderSegID())) {
187 final String error = String.format(
188 ERR_SET_FLOWS + "Failed to get VNI for %s",
189 instPort, osNet.getName());
190 throw new IllegalStateException(error);
191 }
192 return Long.valueOf(osNet.getProviderSegID());
193 }
194
195 private class InternalInstancePortListener implements InstancePortListener {
196
197 @Override
198 public boolean isRelevant(InstancePortEvent event) {
199 InstancePort instPort = event.subject();
200 return mastershipService.isLocalMaster(instPort.deviceId());
201 }
202
203 @Override
204 public void event(InstancePortEvent event) {
205 InstancePort instPort = event.subject();
206 switch (event.type()) {
207 case OPENSTACK_INSTANCE_PORT_UPDATED:
208 case OPENSTACK_INSTANCE_PORT_DETECTED:
209 eventExecutor.execute(() -> {
210 log.info("Instance port detected MAC:{} IP:{}",
211 instPort.macAddress(),
212 instPort.ipAddress());
213 instPortDetected(event.subject());
214 });
215 break;
216 case OPENSTACK_INSTANCE_PORT_VANISHED:
217 eventExecutor.execute(() -> {
218 log.info("Instance port vanished MAC:{} IP:{}",
219 instPort.macAddress(),
220 instPort.ipAddress());
221 instPortRemoved(event.subject());
222 });
223 break;
224 default:
225 break;
226 }
227 }
228
229 private void instPortDetected(InstancePort instPort) {
230 setNetworkRules(instPort, true);
231 // TODO add something else if needed
232 }
233
234 private void instPortRemoved(InstancePort instPort) {
235 setNetworkRules(instPort, false);
236 // TODO add something else if needed
237 }
238 }
239}