blob: e1d2d39c024603bb223cda33b21c088e1b99f67c [file] [log] [blame]
Jonathan Hart6344f572015-12-15 08:26:25 -08001/*
Jonathan Hartf4bd0482017-01-27 15:11:18 -08002 * Copyright 2017-present Open Networking Laboratory
Jonathan Hart6344f572015-12-15 08:26:25 -08003 *
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
Jonathan Hartf4bd0482017-01-27 15:11:18 -080017package org.onosproject.routing.cpr;
Jonathan Hart6344f572015-12-15 08:26:25 -080018
Jonathan Hartf04b7d92016-03-29 09:39:11 -070019import com.google.common.collect.ImmutableSortedSet;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053020import com.google.common.collect.Lists;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070021import com.google.common.collect.Maps;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070022import com.google.common.collect.Sets;
Jonathan Hart6344f572015-12-15 08:26:25 -080023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.onlab.packet.EthType;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053029import org.onlab.packet.Ip4Address;
Charles Chand0fd5dc2016-02-16 23:14:49 -080030import org.onlab.packet.IpPrefix;
31import org.onlab.packet.MacAddress;
Saurav Das49cb5a12016-01-16 22:54:07 -080032import org.onlab.packet.VlanId;
kishore786b7e42016-05-19 16:25:57 +053033import org.onosproject.app.ApplicationService;
Jonathan Hart6344f572015-12-15 08:26:25 -080034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
36import org.onosproject.incubator.net.intf.Interface;
37import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080038import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080039import org.onosproject.net.ConnectPoint;
40import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080041import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080042import org.onosproject.net.PortNumber;
43import org.onosproject.net.config.NetworkConfigEvent;
44import org.onosproject.net.config.NetworkConfigListener;
45import org.onosproject.net.config.NetworkConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -080046import org.onosproject.net.device.DeviceService;
47import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.TrafficSelector;
50import org.onosproject.net.flow.TrafficTreatment;
51import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080052import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Hart6344f572015-12-15 08:26:25 -080053import org.onosproject.net.flowobjective.FlowObjectiveService;
54import org.onosproject.net.flowobjective.ForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080055import org.onosproject.net.flowobjective.NextObjective;
Charles Chand0fd5dc2016-02-16 23:14:49 -080056import org.onosproject.net.host.HostEvent;
57import org.onosproject.net.host.HostListener;
58import org.onosproject.net.host.HostService;
Jonathan Hart6344f572015-12-15 08:26:25 -080059import org.onosproject.net.host.InterfaceIpAddress;
Jonathan Hartf4bd0482017-01-27 15:11:18 -080060import org.onosproject.routing.AsyncDeviceFetcher;
61import org.onosproject.routing.RouterInterfaceManager;
Jonathan Hart6344f572015-12-15 08:26:25 -080062import org.onosproject.routing.RoutingService;
63import org.onosproject.routing.config.RouterConfig;
64import org.slf4j.Logger;
65
Jonathan Hartf04b7d92016-03-29 09:39:11 -070066import java.util.Iterator;
67import java.util.List;
68import java.util.Map;
69import java.util.Optional;
70import java.util.Set;
71
72import static com.google.common.base.Preconditions.checkState;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070073import static org.onlab.packet.Ethernet.TYPE_ARP;
74import static org.onlab.packet.Ethernet.TYPE_IPV4;
75import static org.onlab.packet.Ethernet.TYPE_IPV6;
76import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
77import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
78import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070079import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080080
81/**
82 * Manages connectivity between peers redirecting control traffic to a routing
83 * control plane available on the dataplane.
84 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080085@Component(immediate = true)
Jonathan Hart6344f572015-12-15 08:26:25 -080086public class ControlPlaneRedirectManager {
87
88 private final Logger log = getLogger(getClass());
89
Jonathan Hartf4bd0482017-01-27 15:11:18 -080090 public static final short ASSIGNED_VLAN = 4094;
91
Charles Chand0fd5dc2016-02-16 23:14:49 -080092 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +053093 private static final int IPV4_PRIORITY = 2000;
94 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053095 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080096 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -080097
Jonathan Hart6344f572015-12-15 08:26:25 -080098 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected CoreService coreService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected DeviceService deviceService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected InterfaceService interfaceService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected FlowObjectiveService flowObjectiveService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected NetworkConfigService networkConfigService;
112
Charles Chand0fd5dc2016-02-16 23:14:49 -0800113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected MastershipService mastershipService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected HostService hostService;
118
kishore786b7e42016-05-19 16:25:57 +0530119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected ApplicationService applicationService;
121
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700122 private static final String APP_NAME = "org.onosproject.vrouter";
123 private ApplicationId appId;
124
125 private ConnectPoint controlPlaneConnectPoint;
126 private boolean ospfEnabled = false;
127 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
128
129 private RouterInterfaceManager interfaceManager;
130 private AsyncDeviceFetcher asyncDeviceFetcher;
131
Jonathan Hart6344f572015-12-15 08:26:25 -0800132 private final InternalNetworkConfigListener networkConfigListener =
133 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800134 private final InternalHostListener hostListener = new InternalHostListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800135
136 @Activate
137 public void activate() {
138 this.appId = coreService.registerApplication(APP_NAME);
139
Jonathan Hart6344f572015-12-15 08:26:25 -0800140 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800141 hostService.addListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700142
143 asyncDeviceFetcher = AsyncDeviceFetcher.create(deviceService);
Jonathan Hart6344f572015-12-15 08:26:25 -0800144
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800145 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800146
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800147
Charles Chan00d8b5f2016-12-04 17:17:39 -0800148 // FIXME There can be an issue when this component is deactivated before vRouter
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700149 applicationService.registerDeactivateHook(this.appId, () -> {
150 if (interfaceManager != null) {
151 interfaceManager.cleanup();
152 }
153 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800154 }
155
156 @Deactivate
157 public void deactivate() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800158 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800159 hostService.removeListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700160 asyncDeviceFetcher.shutdown();
161 }
162
kishore786b7e42016-05-19 16:25:57 +0530163 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700164 * Sets up the router interfaces if router config is available.
165 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800166 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800167 ApplicationId routingAppId =
168 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
169
170 RouterConfig config = networkConfigService.getConfig(
171 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
172
173 if (config == null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800174 log.warn("Router config not available");
Jonathan Hart6344f572015-12-15 08:26:25 -0800175 return;
176 }
177
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700178 if (interfaceManager == null) {
179 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
180 ospfEnabled = config.getOspfEnabled();
Jonathan Hart6344f572015-12-15 08:26:25 -0800181
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700182 DeviceId deviceId = config.getControlPlaneConnectPoint().deviceId();
Jonathan Hartea492382016-01-13 09:33:13 -0800183
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700184 asyncDeviceFetcher.getDevice(deviceId)
185 .thenAccept(deviceId1 ->
186 interfaceManager = createRouter(deviceId,
187 Sets.newHashSet(config.getInterfaces())));
Jonathan Hartea492382016-01-13 09:33:13 -0800188
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700189 } else {
190 interfaceManager.changeConfiguredInterfaces(Sets.newHashSet(config.getInterfaces()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800191 }
192 }
193
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800194 /**
195 * Cleans up after router config was removed.
196 */
197 private void removeRouterConfig() {
198 if (interfaceManager != null) {
199 interfaceManager.cleanup();
200 }
201 }
202
203 private RouterInterfaceManager createRouter(DeviceId deviceId, Set<String> configuredInterfaces) {
204 return new RouterInterfaceManager(deviceId,
205 configuredInterfaces,
206 interfaceService,
207 this::provisionInterface,
208 this::unprovisionInterface);
209 }
210
211 private void provisionInterface(Interface intf) {
212 updateInterfaceObjectives(intf, true);
213 }
214
215 private void unprovisionInterface(Interface intf) {
216 updateInterfaceObjectives(intf, false);
217 }
218
219 /**
220 * Installs or removes flow objectives relating to a give interface.
221 *
222 * @param intf interface to change objectives for
223 * @param install true to install the objectives, false to remove them
224 */
225 private void updateInterfaceObjectives(Interface intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700226 updateInterfaceForwarding(intf, install);
227 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800228 }
229
kishore71a27532016-03-16 20:23:49 +0530230 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800231 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530232 *
233 * @param intf the Interface on which event is received
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800234 * @param install true to install the objectives, false to remove them
235 */
Jonathan Hartf8035d32016-06-16 16:23:26 -0700236 private void updateInterfaceForwarding(Interface intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800237 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800238
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700239 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart6344f572015-12-15 08:26:25 -0800240 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800241 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800242 // create nextObjectives for forwarding to this interface and the
243 // controlPlaneConnectPoint
244 int cpNextId, intfNextId;
245 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530246 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800247 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530248 true, install);
249 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800250 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530251 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800252 } else {
kishore71a27532016-03-16 20:23:49 +0530253 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
254 intf.vlan(), false, install);
255 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
256 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800257 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530258 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
259 TrafficSelector selector;
260 // IP traffic toward the router.
261 selector = buildIPDstSelector(
262 ip.ipAddress().toIpPrefix(),
263 intf.connectPoint().port(),
264 null,
265 intf.mac(),
266 intf.vlan()
267 );
268 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
269 // IP traffic from the router.
270 selector = buildIPSrcSelector(
271 ip.ipAddress().toIpPrefix(),
272 controlPlanePort,
273 intf.mac(),
274 null,
275 intf.vlan()
276 );
277 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
278 // We build the punt treatment.
279 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800280 .punt()
281 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530282 // Handling of neighbour discovery protocols.
283 // IPv4 traffic - we have to deal with the ARP protocol.
284 // IPv6 traffic - we have to deal with the NDP protocol.
285 if (ip.ipAddress().isIp4()) {
286 // ARP traffic towards the router.
287 selector = buildArpSelector(
288 intf.connectPoint().port(),
289 intf.vlan(),
290 null,
291 null
292 );
293 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
294 // ARP traffic from the router.
295 selector = buildArpSelector(
296 controlPlanePort,
297 intf.vlan(),
298 ip.ipAddress().getIp4Address(),
299 intf.mac()
300 );
301 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
302 } else {
303 // Neighbour solicitation traffic towards the router.
304 selector = buildNdpSelector(
305 intf.connectPoint().port(),
306 intf.vlan(),
307 null,
308 NEIGHBOR_SOLICITATION,
309 null
310 );
311 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
312 // Neighbour solicitation traffic from the router.
313 selector = buildNdpSelector(
314 controlPlanePort,
315 intf.vlan(),
316 ip.ipAddress().toIpPrefix(),
317 NEIGHBOR_SOLICITATION,
318 intf.mac()
319 );
320 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
321 // Neighbour advertisement traffic towards the router.
322 selector = buildNdpSelector(
323 intf.connectPoint().port(),
324 intf.vlan(),
325 null,
326 NEIGHBOR_ADVERTISEMENT,
327 null
328 );
329 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
330 // Neighbour advertisement traffic from the router.
331 selector = buildNdpSelector(
332 controlPlanePort,
333 intf.vlan(),
334 ip.ipAddress().toIpPrefix(),
335 NEIGHBOR_ADVERTISEMENT,
336 intf.mac()
337 );
338 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
339 }
340 // Finally we push the fwd objectives through the flow objective service.
341 fwdToSend.stream().forEach(forwardingObjective ->
342 flowObjectiveService.forward(deviceId, forwardingObjective)
343 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800344 }
345 }
346
kishore71a27532016-03-16 20:23:49 +0530347 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700348 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530349 *
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700350 * @param intf the interface on which event is received
kishore71a27532016-03-16 20:23:49 +0530351 * @param install true to create an add objective, false to create a remove
352 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800353 */
kishore71a27532016-03-16 20:23:49 +0530354 private void updateOspfForwarding(Interface intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800355 // TODO IPv6 support has not been implemented yet
356
357 log.debug("{} OSPF flows for {}", operation(install), intf);
358
Jonathan Hartea492382016-01-13 09:33:13 -0800359 // OSPF to router
360 TrafficSelector toSelector = DefaultTrafficSelector.builder()
361 .matchInPort(intf.connectPoint().port())
362 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
363 .matchVlanId(intf.vlan())
364 .matchIPProtocol((byte) OSPF_IP_PROTO)
365 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800366
Saurav Das49cb5a12016-01-16 22:54:07 -0800367 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700368 DeviceId deviceId = intf.connectPoint().deviceId();
369 PortNumber controlPlanePort = intf.connectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800370 int cpNextId;
371 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530372 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800373 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530374 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800375 } else {
kishore71a27532016-03-16 20:23:49 +0530376 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
377 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800378 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700379 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800380 buildForwardingObjective(toSelector, null, cpNextId,
381 install ? ospfEnabled : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800382 }
383
384 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800385 * Creates a next objective for forwarding to a port. Handles metadata for
386 * some pipelines that require vlan information for egress port.
387 *
388 * @param deviceId the device on which the next objective is being created
389 * @param portNumber the egress port
390 * @param vlanId vlan information for egress port
391 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530392 * @param install true to create an add next objective, false to create a remove
393 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800394 * @return nextId of the next objective created
395 */
kishore71a27532016-03-16 20:23:49 +0530396 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
397 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800398 int nextId = flowObjectiveService.allocateNextId();
399 NextObjective.Builder nextObjBuilder = DefaultNextObjective
400 .builder().withId(nextId)
401 .withType(NextObjective.Type.SIMPLE)
402 .fromApp(appId);
403
404 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
405 if (popVlan) {
406 ttBuilder.popVlan();
407 }
408 ttBuilder.setOutput(portNumber);
409
410 // setup metadata to pass to nextObjective - indicate the vlan on egress
411 // if needed by the switch pipeline.
412 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
413 metabuilder.matchVlanId(vlanId);
414
415 nextObjBuilder.withMeta(metabuilder.build());
416 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700417 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800418 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530419 if (install) {
420 flowObjectiveService.next(deviceId, nextObjBuilder.add());
421 } else {
422 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
423 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800424 return nextId;
425 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700426
Saurav Das49cb5a12016-01-16 22:54:07 -0800427 /**
428 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800429 *
430 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800431 * @param treatment treatment to apply to packet, can be null
432 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800433 * @param add true to create an add objective, false to create a remove
434 * objective
435 * @return forwarding objective
436 */
437 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
438 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800439 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530440 boolean add,
441 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800442 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
443 fobBuilder.withSelector(selector);
444 if (treatment != null) {
445 fobBuilder.withTreatment(treatment);
446 }
447 if (nextId != -1) {
448 fobBuilder.nextStep(nextId);
449 }
450 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530451 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800452 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800453
454 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800455 }
456
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800457
458 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
459 MacAddress srcMac,
460 MacAddress dstMac,
461 VlanId vlanId) {
462 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
463 if (inPort != null) {
464 selectorBuilder.matchInPort(inPort);
465 }
466 if (srcMac != null) {
467 selectorBuilder.matchEthSrc(srcMac);
468 }
469 if (dstMac != null) {
470 selectorBuilder.matchEthDst(dstMac);
471 }
472 if (vlanId != null) {
473 selectorBuilder.matchVlanId(vlanId);
474 }
475 return selectorBuilder;
476 }
477
478 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
479 PortNumber inPort,
480 MacAddress srcMac,
481 MacAddress dstMac,
482 VlanId vlanId) {
483 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
484 if (dstIp.isIp4()) {
485 selector.matchEthType(TYPE_IPV4);
486 selector.matchIPDst(dstIp);
487 } else {
488 selector.matchEthType(TYPE_IPV6);
489 selector.matchIPv6Dst(dstIp);
490 }
491 return selector.build();
492 }
493
494 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
495 PortNumber inPort,
496 MacAddress srcMac,
497 MacAddress dstMac,
498 VlanId vlanId) {
499 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
500 if (srcIp.isIp4()) {
501 selector.matchEthType(TYPE_IPV4);
502 selector.matchIPSrc(srcIp);
503 } else {
504 selector.matchEthType(TYPE_IPV6);
505 selector.matchIPv6Src(srcIp);
506 }
507 return selector.build();
508 }
509
510 static TrafficSelector buildArpSelector(PortNumber inPort,
511 VlanId vlanId,
512 Ip4Address arpSpa,
513 MacAddress srcMac) {
514 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
515 selector.matchEthType(TYPE_ARP);
516 if (arpSpa != null) {
517 selector.matchArpSpa(arpSpa);
518 }
519 if (srcMac != null) {
520 selector.matchEthSrc(srcMac);
521 }
522 return selector.build();
523 }
524
525 static TrafficSelector buildNdpSelector(PortNumber inPort,
526 VlanId vlanId,
527 IpPrefix srcIp,
528 byte subProto,
529 MacAddress srcMac) {
530 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
531 selector.matchEthType(TYPE_IPV6)
532 .matchIPProtocol(PROTOCOL_ICMP6)
533 .matchIcmpv6Type(subProto);
534 if (srcIp != null) {
535 selector.matchIPv6Src(srcIp);
536 }
537 if (srcMac != null) {
538 selector.matchEthSrc(srcMac);
539 }
540 return selector.build();
541 }
542
543 private int getPriorityFromPrefix(IpPrefix prefix) {
544 return (prefix.isIp4()) ?
545 IPV4_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY :
546 IPV6_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY;
547 }
548
549 private String operation(boolean install) {
550 return install ? "Installing" : "Removing";
551 }
552
553
Jonathan Hartea492382016-01-13 09:33:13 -0800554 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800555 * Listener for network config events.
556 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800557 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530558
Jonathan Hart6344f572015-12-15 08:26:25 -0800559 @Override
560 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800561 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800562 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700563 case CONFIG_ADDED:
564 case CONFIG_UPDATED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800565 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700566 break;
567 case CONFIG_REGISTERED:
568 break;
569 case CONFIG_UNREGISTERED:
570 break;
571 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800572 removeRouterConfig();
kishore36d1c272016-09-21 15:44:10 +0530573 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530574 default:
575 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800576 }
577 }
578 }
579 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800580
581 /**
582 * Listener for host events.
583 */
584 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530585
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700586 private Optional<Interface> getPeerInterface(Host peer) {
587 return interfaceService.getInterfacesByPort(peer.location()).stream()
588 .filter(intf -> interfaceManager.configuredInterfaces().isEmpty()
589 || interfaceManager.configuredInterfaces().contains(intf.name()))
Charles Chand0fd5dc2016-02-16 23:14:49 -0800590 .filter(intf -> peer.vlan().equals(intf.vlan()))
591 .findFirst();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700592 }
593
594 private void peerAdded(HostEvent event) {
595 Host peer = event.subject();
596 if (interfaceManager == null) {
597 return;
598 }
599
600 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800601 if (!peerIntf.isPresent()) {
602 log.debug("Adding peer {}/{} on {} but the interface is not configured",
603 peer.mac(), peer.vlan(), peer.location());
604 return;
605 }
606
607 // Generate L3 Unicast groups and store it in the map
608 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700609 peer.vlan(), peer.location().deviceId(), peerIntf.get().connectPoint().port());
Charles Chand0fd5dc2016-02-16 23:14:49 -0800610 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
611 peer.vlan(), peer.location().deviceId(), peer.location().port());
612 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
613
614 // From peer to router
615 peerIntf.get().ipAddresses().forEach(routerIp -> {
616 flowObjectiveService.forward(peer.location().deviceId(),
617 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
618 });
619
620 // From router to peer
621 peer.ipAddresses().forEach(peerIp -> {
622 flowObjectiveService.forward(peer.location().deviceId(),
623 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
624 });
625 }
626
627 private void peerRemoved(HostEvent event) {
628 Host peer = event.subject();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700629 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800630 if (!peerIntf.isPresent()) {
631 log.debug("Removing peer {}/{} on {} but the interface is not configured",
632 peer.mac(), peer.vlan(), peer.location());
633 return;
634 }
635
Charles Chand0fd5dc2016-02-16 23:14:49 -0800636 checkState(peerNextId.get(peer) != null,
637 "Peer nextId should not be null");
638 checkState(peerNextId.get(peer).size() == 2,
639 "Wrong nextId associated with the peer");
640 Iterator<Integer> iter = peerNextId.get(peer).iterator();
641 int toRouterL3Unicast = iter.next();
642 int toPeerL3Unicast = iter.next();
643
644 // From peer to router
645 peerIntf.get().ipAddresses().forEach(routerIp -> {
646 flowObjectiveService.forward(peer.location().deviceId(),
647 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
648 });
649
650 // From router to peer
651 peer.ipAddresses().forEach(peerIp -> {
652 flowObjectiveService.forward(peer.location().deviceId(),
653 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
654 });
655 }
656
657 private ForwardingObjective.Builder createPeerObjBuilder(
658 int nextId, IpPrefix ipAddresses) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530659 TrafficSelector selector = buildIPDstSelector(ipAddresses, null, null, null, null);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800660 DefaultForwardingObjective.Builder builder =
661 DefaultForwardingObjective.builder()
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530662 .withSelector(selector)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800663 .fromApp(appId)
664 .withPriority(getPriorityFromPrefix(ipAddresses))
665 .withFlag(ForwardingObjective.Flag.SPECIFIC);
666 if (nextId != -1) {
667 builder.nextStep(nextId);
668 }
669 return builder;
670 }
671
672 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
673 VlanId vlanId, DeviceId deviceId, PortNumber port) {
674 int nextId = flowObjectiveService.allocateNextId();
675 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
676 .withId(nextId)
677 .withType(NextObjective.Type.SIMPLE)
678 .fromApp(appId);
679
680 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
681 ttBuilder.setEthSrc(srcMac);
682 ttBuilder.setEthDst(dstMac);
683 ttBuilder.setOutput(port);
684 nextObjBuilder.addTreatment(ttBuilder.build());
685
686 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
687 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800688 VlanId.vlanId(ASSIGNED_VLAN) :
Charles Chand0fd5dc2016-02-16 23:14:49 -0800689 vlanId;
690 metabuilder.matchVlanId(matchVlanId);
691 nextObjBuilder.withMeta(metabuilder.build());
692
693 flowObjectiveService.next(deviceId, nextObjBuilder.add());
694 return nextId;
695 }
696
697 @Override
698 public void event(HostEvent event) {
699 DeviceId deviceId = event.subject().location().deviceId();
700 if (!mastershipService.isLocalMaster(deviceId)) {
701 return;
702 }
703 switch (event.type()) {
704 case HOST_ADDED:
705 peerAdded(event);
706 break;
707 case HOST_MOVED:
708 //TODO We assume BGP peer does not move for now
709 break;
710 case HOST_REMOVED:
711 peerRemoved(event);
712 break;
713 case HOST_UPDATED:
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530714 //FIXME We assume BGP peer does not change IP for now
715 // but we can discover new address.
Charles Chand0fd5dc2016-02-16 23:14:49 -0800716 break;
717 default:
718 break;
719 }
720 }
721 }
722
Jonathan Hart6344f572015-12-15 08:26:25 -0800723}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530724