blob: c5e7142a9d9b87377c8bb42178df69ee76b3efd1 [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;
62
63 private static final String APP_NAME = "org.onosproject.cpredirect";
64 private ApplicationId appId;
65
66 private ConnectPoint controlPlaneConnectPoint;
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected CoreService coreService;
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected DeviceService deviceService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected InterfaceService interfaceService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected FlowObjectiveService flowObjectiveService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected NetworkConfigService networkConfigService;
82
83 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
84 private final InternalNetworkConfigListener networkConfigListener =
85 new InternalNetworkConfigListener();
86
87 @Activate
88 public void activate() {
89 this.appId = coreService.registerApplication(APP_NAME);
90
91 deviceService.addListener(deviceListener);
92 networkConfigService.addListener(networkConfigListener);
93
94 updateConfig();
95 }
96
97 @Deactivate
98 public void deactivate() {
99 deviceService.removeListener(deviceListener);
100 networkConfigService.removeListener(networkConfigListener);
101 }
102
103 private void updateConfig() {
104 ApplicationId routingAppId =
105 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
106
107 RouterConfig config = networkConfigService.getConfig(
108 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
109
110 if (config == null) {
111 log.info("Router config not available");
112 return;
113 }
114
115 if (!config.getControlPlaneConnectPoint().equals(controlPlaneConnectPoint)) {
116 this.controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
117 }
118
119 if (controlPlaneConnectPoint != null &&
120 deviceService.isAvailable(controlPlaneConnectPoint.deviceId())) {
121 notifySwitchAvailable();
122 }
123 }
124
125 private void notifySwitchAvailable() {
126 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
127
128 interfaceService.getInterfaces().stream()
129 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
130 .forEach(this::addInterfaceForwarding);
131
132 log.info("Sent interface objectives to {}", controlPlaneConnectPoint.deviceId());
133 }
134
135 private void addInterfaceForwarding(Interface intf) {
136 log.debug("Adding interface objectives for {}", intf);
137
138 DeviceId deviceId = controlPlaneConnectPoint.deviceId();
139 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
140
141 for (InterfaceIpAddress ip : intf.ipAddresses()) {
142 // IPv4 to router
143 TrafficSelector toSelector = DefaultTrafficSelector.builder()
144 .matchInPort(intf.connectPoint().port())
145 .matchEthDst(intf.mac())
146 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
147 .matchVlanId(intf.vlan())
148 .matchIPDst(ip.ipAddress().toIpPrefix())
149 .build();
150
151 TrafficTreatment toTreatment = DefaultTrafficTreatment.builder()
152 .setOutput(controlPlanePort)
153 .build();
154
155 flowObjectiveService.forward(deviceId,
156 buildForwardingObjective(toSelector, toTreatment));
157
158 // IPv4 from router
159 TrafficSelector fromSelector = DefaultTrafficSelector.builder()
160 .matchInPort(controlPlanePort)
161 .matchEthSrc(intf.mac())
162 .matchVlanId(intf.vlan())
163 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
164 .matchIPSrc(ip.ipAddress().toIpPrefix())
165 .build();
166
167 TrafficTreatment intfTreatment = DefaultTrafficTreatment.builder()
168 .setOutput(intf.connectPoint().port())
169 .build();
170
171 flowObjectiveService.forward(deviceId,
172 buildForwardingObjective(fromSelector, intfTreatment));
173
174
175 // ARP to router
176 toSelector = DefaultTrafficSelector.builder()
177 .matchInPort(intf.connectPoint().port())
178 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
179 .matchVlanId(intf.vlan())
180 .build();
181
182 toTreatment = DefaultTrafficTreatment.builder()
183 .setOutput(controlPlanePort)
184 .punt()
185 .build();
186
187 flowObjectiveService.forward(deviceId,
188 buildForwardingObjective(toSelector, toTreatment));
189
190 // ARP from router
191 fromSelector = DefaultTrafficSelector.builder()
192 .matchInPort(controlPlanePort)
193 .matchEthSrc(intf.mac())
194 .matchVlanId(intf.vlan())
195 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
196 .build();
197
198 intfTreatment = DefaultTrafficTreatment.builder()
199 .setOutput(intf.connectPoint().port())
200 .punt()
201 .build();
202
203 flowObjectiveService.forward(deviceId,
204 buildForwardingObjective(fromSelector, intfTreatment));
205 }
206 }
207
208 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
209 TrafficTreatment treatment) {
210
211 return DefaultForwardingObjective.builder()
212 .withSelector(selector)
213 .withTreatment(treatment)
214 .fromApp(appId)
215 .withPriority(PRIORITY)
216 .withFlag(ForwardingObjective.Flag.VERSATILE)
217 .add();
218 }
219
220 private class InternalDeviceListener implements DeviceListener {
221 @Override
222 public void event(DeviceEvent event) {
223 if (controlPlaneConnectPoint != null &&
224 event.subject().id().equals(controlPlaneConnectPoint.deviceId())) {
225 switch (event.type()) {
226 case DEVICE_ADDED:
227 case DEVICE_AVAILABILITY_CHANGED:
228 if (deviceService.isAvailable(event.subject().id())) {
229 log.info("Device connected {}", event.subject().id());
230 notifySwitchAvailable();
231 }
232
233 break;
234 case DEVICE_UPDATED:
235 case DEVICE_REMOVED:
236 case DEVICE_SUSPENDED:
237 case PORT_ADDED:
238 case PORT_UPDATED:
239 case PORT_REMOVED:
240 default:
241 break;
242 }
243 }
244 }
245 }
246
247 private class InternalNetworkConfigListener implements NetworkConfigListener {
248 @Override
249 public void event(NetworkConfigEvent event) {
250 if (event.subject().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
251 switch (event.type()) {
252 case CONFIG_ADDED:
253 case CONFIG_UPDATED:
254 updateConfig();
255 break;
256 case CONFIG_REGISTERED:
257 case CONFIG_UNREGISTERED:
258 case CONFIG_REMOVED:
259 default:
260 break;
261 }
262 }
263 }
264 }
265}