blob: f72963c38634cc4db8a7bc8304039f0ab84d255d [file] [log] [blame]
Jonathan Hart6344f572015-12-15 08:26:25 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-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
17package org.onosproject.routing.impl;
18
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;
60import org.onosproject.routing.RoutingService;
61import org.onosproject.routing.config.RouterConfig;
62import org.slf4j.Logger;
63
Jonathan Hartf04b7d92016-03-29 09:39:11 -070064import java.util.Iterator;
65import java.util.List;
66import java.util.Map;
67import java.util.Optional;
68import java.util.Set;
69
70import static com.google.common.base.Preconditions.checkState;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070071import static org.onlab.packet.Ethernet.TYPE_ARP;
72import static org.onlab.packet.Ethernet.TYPE_IPV4;
73import static org.onlab.packet.Ethernet.TYPE_IPV6;
74import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
75import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
76import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070077import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080078
79/**
80 * Manages connectivity between peers redirecting control traffic to a routing
81 * control plane available on the dataplane.
82 */
83@Component(immediate = true, enabled = false)
84public class ControlPlaneRedirectManager {
85
86 private final Logger log = getLogger(getClass());
87
Charles Chand0fd5dc2016-02-16 23:14:49 -080088 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +053089 private static final int IPV4_PRIORITY = 2000;
90 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053091 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -080092 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -080093
Jonathan Hart6344f572015-12-15 08:26:25 -080094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected CoreService coreService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected DeviceService deviceService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected InterfaceService interfaceService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected FlowObjectiveService flowObjectiveService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected NetworkConfigService networkConfigService;
108
Charles Chand0fd5dc2016-02-16 23:14:49 -0800109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected MastershipService mastershipService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected HostService hostService;
114
kishore786b7e42016-05-19 16:25:57 +0530115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected ApplicationService applicationService;
117
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700118 private static final String APP_NAME = "org.onosproject.vrouter";
119 private ApplicationId appId;
120
121 private ConnectPoint controlPlaneConnectPoint;
122 private boolean ospfEnabled = false;
123 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
124
125 private RouterInterfaceManager interfaceManager;
126 private AsyncDeviceFetcher asyncDeviceFetcher;
127
Jonathan Hart6344f572015-12-15 08:26:25 -0800128 private final InternalNetworkConfigListener networkConfigListener =
129 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800130 private final InternalHostListener hostListener = new InternalHostListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800131
132 @Activate
133 public void activate() {
134 this.appId = coreService.registerApplication(APP_NAME);
135
Jonathan Hart6344f572015-12-15 08:26:25 -0800136 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800137 hostService.addListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700138
139 asyncDeviceFetcher = AsyncDeviceFetcher.create(deviceService);
Jonathan Hart6344f572015-12-15 08:26:25 -0800140
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800141 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800142
143 // FIXME There can be an issue when this component is deactivated before vRouter
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700144 applicationService.registerDeactivateHook(this.appId, () -> {
145 if (interfaceManager != null) {
146 interfaceManager.cleanup();
147 }
148 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800149 }
150
151 @Deactivate
152 public void deactivate() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800153 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800154 hostService.removeListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700155 asyncDeviceFetcher.shutdown();
156 }
157
kishore786b7e42016-05-19 16:25:57 +0530158 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700159 * Sets up the router interfaces if router config is available.
160 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800161 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800162 ApplicationId routingAppId =
163 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
164
165 RouterConfig config = networkConfigService.getConfig(
166 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
167
168 if (config == null) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800169 log.warn("Router config not available");
Jonathan Hart6344f572015-12-15 08:26:25 -0800170 return;
171 }
172
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700173 if (interfaceManager == null) {
174 controlPlaneConnectPoint = config.getControlPlaneConnectPoint();
175 ospfEnabled = config.getOspfEnabled();
Jonathan Hart6344f572015-12-15 08:26:25 -0800176
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700177 DeviceId deviceId = config.getControlPlaneConnectPoint().deviceId();
Jonathan Hartea492382016-01-13 09:33:13 -0800178
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700179 asyncDeviceFetcher.getDevice(deviceId)
180 .thenAccept(deviceId1 ->
181 interfaceManager = createRouter(deviceId,
182 Sets.newHashSet(config.getInterfaces())));
Jonathan Hartea492382016-01-13 09:33:13 -0800183
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700184 } else {
185 interfaceManager.changeConfiguredInterfaces(Sets.newHashSet(config.getInterfaces()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800186 }
187 }
188
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800189 /**
190 * Cleans up after router config was removed.
191 */
192 private void removeRouterConfig() {
193 if (interfaceManager != null) {
194 interfaceManager.cleanup();
195 }
196 }
197
198 private RouterInterfaceManager createRouter(DeviceId deviceId, Set<String> configuredInterfaces) {
199 return new RouterInterfaceManager(deviceId,
200 configuredInterfaces,
201 interfaceService,
202 this::provisionInterface,
203 this::unprovisionInterface);
204 }
205
206 private void provisionInterface(Interface intf) {
207 updateInterfaceObjectives(intf, true);
208 }
209
210 private void unprovisionInterface(Interface intf) {
211 updateInterfaceObjectives(intf, false);
212 }
213
214 /**
215 * Installs or removes flow objectives relating to a give interface.
216 *
217 * @param intf interface to change objectives for
218 * @param install true to install the objectives, false to remove them
219 */
220 private void updateInterfaceObjectives(Interface intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700221 updateInterfaceForwarding(intf, install);
222 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800223 }
224
kishore71a27532016-03-16 20:23:49 +0530225 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800226 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530227 *
228 * @param intf the Interface on which event is received
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800229 * @param install true to install the objectives, false to remove them
230 */
Jonathan Hartf8035d32016-06-16 16:23:26 -0700231 private void updateInterfaceForwarding(Interface intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800232 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800233
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700234 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart6344f572015-12-15 08:26:25 -0800235 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800236 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800237 // create nextObjectives for forwarding to this interface and the
238 // controlPlaneConnectPoint
239 int cpNextId, intfNextId;
240 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530241 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800242 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530243 true, install);
244 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Saurav Das49cb5a12016-01-16 22:54:07 -0800245 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530246 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800247 } else {
kishore71a27532016-03-16 20:23:49 +0530248 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
249 intf.vlan(), false, install);
250 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
251 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800252 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530253 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
254 TrafficSelector selector;
255 // IP traffic toward the router.
256 selector = buildIPDstSelector(
257 ip.ipAddress().toIpPrefix(),
258 intf.connectPoint().port(),
259 null,
260 intf.mac(),
261 intf.vlan()
262 );
263 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
264 // IP traffic from the router.
265 selector = buildIPSrcSelector(
266 ip.ipAddress().toIpPrefix(),
267 controlPlanePort,
268 intf.mac(),
269 null,
270 intf.vlan()
271 );
272 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
273 // We build the punt treatment.
274 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800275 .punt()
276 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530277 // Handling of neighbour discovery protocols.
278 // IPv4 traffic - we have to deal with the ARP protocol.
279 // IPv6 traffic - we have to deal with the NDP protocol.
280 if (ip.ipAddress().isIp4()) {
281 // ARP traffic towards the router.
282 selector = buildArpSelector(
283 intf.connectPoint().port(),
284 intf.vlan(),
285 null,
286 null
287 );
288 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
289 // ARP traffic from the router.
290 selector = buildArpSelector(
291 controlPlanePort,
292 intf.vlan(),
293 ip.ipAddress().getIp4Address(),
294 intf.mac()
295 );
296 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
297 } else {
298 // Neighbour solicitation traffic towards the router.
299 selector = buildNdpSelector(
300 intf.connectPoint().port(),
301 intf.vlan(),
302 null,
303 NEIGHBOR_SOLICITATION,
304 null
305 );
306 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
307 // Neighbour solicitation traffic from the router.
308 selector = buildNdpSelector(
309 controlPlanePort,
310 intf.vlan(),
311 ip.ipAddress().toIpPrefix(),
312 NEIGHBOR_SOLICITATION,
313 intf.mac()
314 );
315 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
316 // Neighbour advertisement traffic towards the router.
317 selector = buildNdpSelector(
318 intf.connectPoint().port(),
319 intf.vlan(),
320 null,
321 NEIGHBOR_ADVERTISEMENT,
322 null
323 );
324 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
325 // Neighbour advertisement traffic from the router.
326 selector = buildNdpSelector(
327 controlPlanePort,
328 intf.vlan(),
329 ip.ipAddress().toIpPrefix(),
330 NEIGHBOR_ADVERTISEMENT,
331 intf.mac()
332 );
333 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
334 }
335 // Finally we push the fwd objectives through the flow objective service.
336 fwdToSend.stream().forEach(forwardingObjective ->
337 flowObjectiveService.forward(deviceId, forwardingObjective)
338 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800339 }
340 }
341
kishore71a27532016-03-16 20:23:49 +0530342 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700343 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530344 *
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700345 * @param intf the interface on which event is received
kishore71a27532016-03-16 20:23:49 +0530346 * @param install true to create an add objective, false to create a remove
347 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800348 */
kishore71a27532016-03-16 20:23:49 +0530349 private void updateOspfForwarding(Interface intf, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800350 // TODO IPv6 support has not been implemented yet
351
352 log.debug("{} OSPF flows for {}", operation(install), intf);
353
Jonathan Hartea492382016-01-13 09:33:13 -0800354 // OSPF to router
355 TrafficSelector toSelector = DefaultTrafficSelector.builder()
356 .matchInPort(intf.connectPoint().port())
357 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
358 .matchVlanId(intf.vlan())
359 .matchIPProtocol((byte) OSPF_IP_PROTO)
360 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800361
Saurav Das49cb5a12016-01-16 22:54:07 -0800362 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700363 DeviceId deviceId = intf.connectPoint().deviceId();
364 PortNumber controlPlanePort = intf.connectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800365 int cpNextId;
366 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530367 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Saurav Das49cb5a12016-01-16 22:54:07 -0800368 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530369 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800370 } else {
kishore71a27532016-03-16 20:23:49 +0530371 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
372 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800373 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700374 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800375 buildForwardingObjective(toSelector, null, cpNextId,
376 install ? ospfEnabled : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800377 }
378
379 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800380 * Creates a next objective for forwarding to a port. Handles metadata for
381 * some pipelines that require vlan information for egress port.
382 *
383 * @param deviceId the device on which the next objective is being created
384 * @param portNumber the egress port
385 * @param vlanId vlan information for egress port
386 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530387 * @param install true to create an add next objective, false to create a remove
388 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800389 * @return nextId of the next objective created
390 */
kishore71a27532016-03-16 20:23:49 +0530391 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
392 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800393 int nextId = flowObjectiveService.allocateNextId();
394 NextObjective.Builder nextObjBuilder = DefaultNextObjective
395 .builder().withId(nextId)
396 .withType(NextObjective.Type.SIMPLE)
397 .fromApp(appId);
398
399 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
400 if (popVlan) {
401 ttBuilder.popVlan();
402 }
403 ttBuilder.setOutput(portNumber);
404
405 // setup metadata to pass to nextObjective - indicate the vlan on egress
406 // if needed by the switch pipeline.
407 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
408 metabuilder.matchVlanId(vlanId);
409
410 nextObjBuilder.withMeta(metabuilder.build());
411 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700412 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800413 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530414 if (install) {
415 flowObjectiveService.next(deviceId, nextObjBuilder.add());
416 } else {
417 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
418 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800419 return nextId;
420 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700421
Saurav Das49cb5a12016-01-16 22:54:07 -0800422 /**
423 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800424 *
425 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800426 * @param treatment treatment to apply to packet, can be null
427 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800428 * @param add true to create an add objective, false to create a remove
429 * objective
430 * @return forwarding objective
431 */
432 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
433 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800434 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530435 boolean add,
436 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800437 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
438 fobBuilder.withSelector(selector);
439 if (treatment != null) {
440 fobBuilder.withTreatment(treatment);
441 }
442 if (nextId != -1) {
443 fobBuilder.nextStep(nextId);
444 }
445 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530446 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800447 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800448
449 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800450 }
451
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800452
453 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
454 MacAddress srcMac,
455 MacAddress dstMac,
456 VlanId vlanId) {
457 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
458 if (inPort != null) {
459 selectorBuilder.matchInPort(inPort);
460 }
461 if (srcMac != null) {
462 selectorBuilder.matchEthSrc(srcMac);
463 }
464 if (dstMac != null) {
465 selectorBuilder.matchEthDst(dstMac);
466 }
467 if (vlanId != null) {
468 selectorBuilder.matchVlanId(vlanId);
469 }
470 return selectorBuilder;
471 }
472
473 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
474 PortNumber inPort,
475 MacAddress srcMac,
476 MacAddress dstMac,
477 VlanId vlanId) {
478 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
479 if (dstIp.isIp4()) {
480 selector.matchEthType(TYPE_IPV4);
481 selector.matchIPDst(dstIp);
482 } else {
483 selector.matchEthType(TYPE_IPV6);
484 selector.matchIPv6Dst(dstIp);
485 }
486 return selector.build();
487 }
488
489 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
490 PortNumber inPort,
491 MacAddress srcMac,
492 MacAddress dstMac,
493 VlanId vlanId) {
494 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
495 if (srcIp.isIp4()) {
496 selector.matchEthType(TYPE_IPV4);
497 selector.matchIPSrc(srcIp);
498 } else {
499 selector.matchEthType(TYPE_IPV6);
500 selector.matchIPv6Src(srcIp);
501 }
502 return selector.build();
503 }
504
505 static TrafficSelector buildArpSelector(PortNumber inPort,
506 VlanId vlanId,
507 Ip4Address arpSpa,
508 MacAddress srcMac) {
509 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
510 selector.matchEthType(TYPE_ARP);
511 if (arpSpa != null) {
512 selector.matchArpSpa(arpSpa);
513 }
514 if (srcMac != null) {
515 selector.matchEthSrc(srcMac);
516 }
517 return selector.build();
518 }
519
520 static TrafficSelector buildNdpSelector(PortNumber inPort,
521 VlanId vlanId,
522 IpPrefix srcIp,
523 byte subProto,
524 MacAddress srcMac) {
525 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
526 selector.matchEthType(TYPE_IPV6)
527 .matchIPProtocol(PROTOCOL_ICMP6)
528 .matchIcmpv6Type(subProto);
529 if (srcIp != null) {
530 selector.matchIPv6Src(srcIp);
531 }
532 if (srcMac != null) {
533 selector.matchEthSrc(srcMac);
534 }
535 return selector.build();
536 }
537
538 private int getPriorityFromPrefix(IpPrefix prefix) {
539 return (prefix.isIp4()) ?
540 IPV4_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY :
541 IPV6_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY;
542 }
543
544 private String operation(boolean install) {
545 return install ? "Installing" : "Removing";
546 }
547
548
Jonathan Hartea492382016-01-13 09:33:13 -0800549 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800550 * Listener for network config events.
551 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800552 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530553
Jonathan Hart6344f572015-12-15 08:26:25 -0800554 @Override
555 public void event(NetworkConfigEvent event) {
Jonathan Hartea492382016-01-13 09:33:13 -0800556 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800557 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700558 case CONFIG_ADDED:
559 case CONFIG_UPDATED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800560 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700561 break;
562 case CONFIG_REGISTERED:
563 break;
564 case CONFIG_UNREGISTERED:
565 break;
566 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800567 removeRouterConfig();
kishore36d1c272016-09-21 15:44:10 +0530568 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530569 default:
570 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800571 }
572 }
573 }
574 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800575
576 /**
577 * Listener for host events.
578 */
579 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530580
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700581 private Optional<Interface> getPeerInterface(Host peer) {
582 return interfaceService.getInterfacesByPort(peer.location()).stream()
583 .filter(intf -> interfaceManager.configuredInterfaces().isEmpty()
584 || interfaceManager.configuredInterfaces().contains(intf.name()))
Charles Chand0fd5dc2016-02-16 23:14:49 -0800585 .filter(intf -> peer.vlan().equals(intf.vlan()))
586 .findFirst();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700587 }
588
589 private void peerAdded(HostEvent event) {
590 Host peer = event.subject();
591 if (interfaceManager == null) {
592 return;
593 }
594
595 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800596 if (!peerIntf.isPresent()) {
597 log.debug("Adding peer {}/{} on {} but the interface is not configured",
598 peer.mac(), peer.vlan(), peer.location());
599 return;
600 }
601
602 // Generate L3 Unicast groups and store it in the map
603 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700604 peer.vlan(), peer.location().deviceId(), peerIntf.get().connectPoint().port());
Charles Chand0fd5dc2016-02-16 23:14:49 -0800605 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
606 peer.vlan(), peer.location().deviceId(), peer.location().port());
607 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
608
609 // From peer to router
610 peerIntf.get().ipAddresses().forEach(routerIp -> {
611 flowObjectiveService.forward(peer.location().deviceId(),
612 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
613 });
614
615 // From router to peer
616 peer.ipAddresses().forEach(peerIp -> {
617 flowObjectiveService.forward(peer.location().deviceId(),
618 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
619 });
620 }
621
622 private void peerRemoved(HostEvent event) {
623 Host peer = event.subject();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700624 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800625 if (!peerIntf.isPresent()) {
626 log.debug("Removing peer {}/{} on {} but the interface is not configured",
627 peer.mac(), peer.vlan(), peer.location());
628 return;
629 }
630
Charles Chand0fd5dc2016-02-16 23:14:49 -0800631 checkState(peerNextId.get(peer) != null,
632 "Peer nextId should not be null");
633 checkState(peerNextId.get(peer).size() == 2,
634 "Wrong nextId associated with the peer");
635 Iterator<Integer> iter = peerNextId.get(peer).iterator();
636 int toRouterL3Unicast = iter.next();
637 int toPeerL3Unicast = iter.next();
638
639 // From peer to router
640 peerIntf.get().ipAddresses().forEach(routerIp -> {
641 flowObjectiveService.forward(peer.location().deviceId(),
642 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
643 });
644
645 // From router to peer
646 peer.ipAddresses().forEach(peerIp -> {
647 flowObjectiveService.forward(peer.location().deviceId(),
648 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
649 });
650 }
651
652 private ForwardingObjective.Builder createPeerObjBuilder(
653 int nextId, IpPrefix ipAddresses) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530654 TrafficSelector selector = buildIPDstSelector(ipAddresses, null, null, null, null);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800655 DefaultForwardingObjective.Builder builder =
656 DefaultForwardingObjective.builder()
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530657 .withSelector(selector)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800658 .fromApp(appId)
659 .withPriority(getPriorityFromPrefix(ipAddresses))
660 .withFlag(ForwardingObjective.Flag.SPECIFIC);
661 if (nextId != -1) {
662 builder.nextStep(nextId);
663 }
664 return builder;
665 }
666
667 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
668 VlanId vlanId, DeviceId deviceId, PortNumber port) {
669 int nextId = flowObjectiveService.allocateNextId();
670 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
671 .withId(nextId)
672 .withType(NextObjective.Type.SIMPLE)
673 .fromApp(appId);
674
675 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
676 ttBuilder.setEthSrc(srcMac);
677 ttBuilder.setEthDst(dstMac);
678 ttBuilder.setOutput(port);
679 nextObjBuilder.addTreatment(ttBuilder.build());
680
681 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
682 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
683 VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN) :
684 vlanId;
685 metabuilder.matchVlanId(matchVlanId);
686 nextObjBuilder.withMeta(metabuilder.build());
687
688 flowObjectiveService.next(deviceId, nextObjBuilder.add());
689 return nextId;
690 }
691
692 @Override
693 public void event(HostEvent event) {
694 DeviceId deviceId = event.subject().location().deviceId();
695 if (!mastershipService.isLocalMaster(deviceId)) {
696 return;
697 }
698 switch (event.type()) {
699 case HOST_ADDED:
700 peerAdded(event);
701 break;
702 case HOST_MOVED:
703 //TODO We assume BGP peer does not move for now
704 break;
705 case HOST_REMOVED:
706 peerRemoved(event);
707 break;
708 case HOST_UPDATED:
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530709 //FIXME We assume BGP peer does not change IP for now
710 // but we can discover new address.
Charles Chand0fd5dc2016-02-16 23:14:49 -0800711 break;
712 default:
713 break;
714 }
715 }
716 }
717
Jonathan Hart6344f572015-12-15 08:26:25 -0800718}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530719