blob: 229443521f320e2b0c9a3b731494b949ba847387 [file] [log] [blame]
Jonathan Hart6344f572015-12-15 08:26:25 -08001/*
2 * Copyright 2016 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.routing.impl;
18
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onlab.packet.EthType;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.incubator.net.intf.Interface;
28import org.onosproject.incubator.net.intf.InterfaceService;
29import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.PortNumber;
32import org.onosproject.net.config.NetworkConfigEvent;
33import org.onosproject.net.config.NetworkConfigListener;
34import org.onosproject.net.config.NetworkConfigService;
35import org.onosproject.net.device.DeviceEvent;
36import org.onosproject.net.device.DeviceListener;
37import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
42import org.onosproject.net.flowobjective.DefaultForwardingObjective;
43import org.onosproject.net.flowobjective.FlowObjectiveService;
44import org.onosproject.net.flowobjective.ForwardingObjective;
45import org.onosproject.net.host.InterfaceIpAddress;
46import org.onosproject.routing.RoutingService;
47import org.onosproject.routing.config.RouterConfig;
48import org.slf4j.Logger;
49
50import static org.slf4j.LoggerFactory.getLogger;
51
52/**
53 * Manages connectivity between peers redirecting control traffic to a routing
54 * control plane available on the dataplane.
55 */
56@Component(immediate = true, enabled = false)
57public class ControlPlaneRedirectManager {
58
59 private final Logger log = getLogger(getClass());
60
61 private static final int PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080062 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -080063
64 private static final String APP_NAME = "org.onosproject.cpredirect";
65 private ApplicationId appId;
66
67 private ConnectPoint controlPlaneConnectPoint;
Jonathan Hartea492382016-01-13 09:33:13 -080068 private boolean ospfEnabled = false;
Jonathan Hart6344f572015-12-15 08:26:25 -080069
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected CoreService coreService;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected DeviceService deviceService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected InterfaceService interfaceService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected FlowObjectiveService flowObjectiveService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected NetworkConfigService networkConfigService;
84
85 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
86 private final InternalNetworkConfigListener networkConfigListener =
87 new InternalNetworkConfigListener();
88
89 @Activate
90 public void activate() {
91 this.appId = coreService.registerApplication(APP_NAME);
92
93 deviceService.addListener(deviceListener);
94 networkConfigService.addListener(networkConfigListener);
95
96 updateConfig();
97 }
98
99 @Deactivate
100 public void deactivate() {
101 deviceService.removeListener(deviceListener);
102 networkConfigService.removeListener(networkConfigListener);
103 }
104
105 private void updateConfig() {
106 ApplicationId routingAppId =
107 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
108
109 RouterConfig config = networkConfigService.getConfig(
110 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
111
112 if (config == null) {
113 log.info("Router config not available");
114 return;
115 }
116
Jonathan Hartea492382016-01-13 09:33:13 -0800117 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
118 ospfEnabled = config.getOspfEnabled();
Jonathan Hart6344f572015-12-15 08:26:25 -0800119
Jonathan Hartea492382016-01-13 09:33:13 -0800120 updateDevice();
121 }
122
123 private void updateDevice() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800124 if (controlPlaneConnectPoint != null &&
125 deviceService.isAvailable(controlPlaneConnectPoint.deviceId())) {
Jonathan Hartea492382016-01-13 09:33:13 -0800126 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
127
128 interfaceService.getInterfaces().stream()
129 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
130 .forEach(this::provisionInterface);
131
132 log.info("Set up interfaces on {}", controlPlaneConnectPoint.deviceId());
Jonathan Hart6344f572015-12-15 08:26:25 -0800133 }
134 }
135
Jonathan Hartea492382016-01-13 09:33:13 -0800136 private void provisionInterface(Interface intf) {
137 addBasicInterfaceForwarding(intf);
138 updateOspfForwarding(intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800139 }
140
Jonathan Hartea492382016-01-13 09:33:13 -0800141 private void addBasicInterfaceForwarding(Interface intf) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800142 log.debug("Adding interface objectives for {}", intf);
143
144 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
145 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
146
147 for (InterfaceIpAddress ip : intf.ipAddresses()) {
148 // IPv4 to router
149 TrafficSelector toSelector = DefaultTrafficSelector.builder()
150 .matchInPort(intf.connectPoint().port())
151 .matchEthDst(intf.mac())
152 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
153 .matchVlanId(intf.vlan())
154 .matchIPDst(ip.ipAddress().toIpPrefix())
155 .build();
156
157 TrafficTreatment toTreatment = DefaultTrafficTreatment.builder()
158 .setOutput(controlPlanePort)
159 .build();
160
161 flowObjectiveService.forward(deviceId,
Jonathan Hartea492382016-01-13 09:33:13 -0800162 buildForwardingObjective(toSelector, toTreatment, true));
Jonathan Hart6344f572015-12-15 08:26:25 -0800163
164 // IPv4 from router
165 TrafficSelector fromSelector = DefaultTrafficSelector.builder()
166 .matchInPort(controlPlanePort)
167 .matchEthSrc(intf.mac())
168 .matchVlanId(intf.vlan())
169 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
170 .matchIPSrc(ip.ipAddress().toIpPrefix())
171 .build();
172
173 TrafficTreatment intfTreatment = DefaultTrafficTreatment.builder()
174 .setOutput(intf.connectPoint().port())
175 .build();
176
177 flowObjectiveService.forward(deviceId,
Jonathan Hartea492382016-01-13 09:33:13 -0800178 buildForwardingObjective(fromSelector, intfTreatment, true));
Jonathan Hart6344f572015-12-15 08:26:25 -0800179
180 // ARP to router
181 toSelector = DefaultTrafficSelector.builder()
182 .matchInPort(intf.connectPoint().port())
183 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
184 .matchVlanId(intf.vlan())
185 .build();
186
187 toTreatment = DefaultTrafficTreatment.builder()
188 .setOutput(controlPlanePort)
189 .punt()
190 .build();
191
192 flowObjectiveService.forward(deviceId,
Jonathan Hartea492382016-01-13 09:33:13 -0800193 buildForwardingObjective(toSelector, toTreatment, true));
Jonathan Hart6344f572015-12-15 08:26:25 -0800194
195 // ARP from router
196 fromSelector = DefaultTrafficSelector.builder()
197 .matchInPort(controlPlanePort)
198 .matchEthSrc(intf.mac())
199 .matchVlanId(intf.vlan())
200 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
201 .build();
202
203 intfTreatment = DefaultTrafficTreatment.builder()
204 .setOutput(intf.connectPoint().port())
205 .punt()
206 .build();
207
208 flowObjectiveService.forward(deviceId,
Jonathan Hartea492382016-01-13 09:33:13 -0800209 buildForwardingObjective(fromSelector, intfTreatment, true));
Jonathan Hart6344f572015-12-15 08:26:25 -0800210 }
211 }
212
Jonathan Hartea492382016-01-13 09:33:13 -0800213 private void updateOspfForwarding(Interface intf) {
214 // OSPF to router
215 TrafficSelector toSelector = DefaultTrafficSelector.builder()
216 .matchInPort(intf.connectPoint().port())
217 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
218 .matchVlanId(intf.vlan())
219 .matchIPProtocol((byte) OSPF_IP_PROTO)
220 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800221
Jonathan Hartea492382016-01-13 09:33:13 -0800222 TrafficTreatment toTreatment = DefaultTrafficTreatment.builder()
223 .setOutput(controlPlaneConnectPoint.port())
224 .build();
225
226 flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(),
227 buildForwardingObjective(toSelector, toTreatment, ospfEnabled));
228 }
229
230 /**
231 * Builds a forwarding objective from the given selector and treatment.
232 *
233 * @param selector selector
234 * @param treatment treatment
235 * @param add true to create an add objective, false to create a remove
236 * objective
237 * @return forwarding objective
238 */
239 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
240 TrafficTreatment treatment,
241 boolean add) {
242
243 ForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800244 .withSelector(selector)
245 .withTreatment(treatment)
246 .fromApp(appId)
247 .withPriority(PRIORITY)
Jonathan Hartea492382016-01-13 09:33:13 -0800248 .withFlag(ForwardingObjective.Flag.VERSATILE);
249
250 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800251 }
252
Jonathan Hartea492382016-01-13 09:33:13 -0800253 /**
254 * Listener for device events.
255 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800256 private class InternalDeviceListener implements DeviceListener {
257 @Override
258 public void event(DeviceEvent event) {
259 if (controlPlaneConnectPoint != null &&
260 event.subject().id().equals(controlPlaneConnectPoint.deviceId())) {
261 switch (event.type()) {
262 case DEVICE_ADDED:
263 case DEVICE_AVAILABILITY_CHANGED:
264 if (deviceService.isAvailable(event.subject().id())) {
265 log.info("Device connected {}", event.subject().id());
Jonathan Hartea492382016-01-13 09:33:13 -0800266 updateDevice();
Jonathan Hart6344f572015-12-15 08:26:25 -0800267 }
268
269 break;
270 case DEVICE_UPDATED:
271 case DEVICE_REMOVED:
272 case DEVICE_SUSPENDED:
273 case PORT_ADDED:
274 case PORT_UPDATED:
275 case PORT_REMOVED:
276 default:
277 break;
278 }
279 }
280 }
281 }
282
Jonathan Hartea492382016-01-13 09:33:13 -0800283 /**
284 * Listener for network config events.
285 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800286 private class InternalNetworkConfigListener implements NetworkConfigListener {
287 @Override
288 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800289 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800290 switch (event.type()) {
291 case CONFIG_ADDED:
292 case CONFIG_UPDATED:
293 updateConfig();
294 break;
295 case CONFIG_REGISTERED:
296 case CONFIG_UNREGISTERED:
297 case CONFIG_REMOVED:
298 default:
299 break;
300 }
301 }
302 }
303 }
304}