blob: 7a857acfa694300cf98c83f49a9ed12cb77dc3c5 [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
Brian O'Connor0947d7e2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
sangho80f11cb2015-04-01 13:05:26 -07003 *
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 */
16package org.onosproject.segmentrouting;
17
Jonathan Hart61e24e12017-11-30 18:23:42 -080018import com.google.common.collect.HashMultimap;
19import com.google.common.collect.ImmutableMap;
20import com.google.common.collect.Maps;
21import com.google.common.collect.Multimap;
Charles Chanf0ae41e2017-08-23 13:55:39 -070022import com.google.common.collect.Sets;
sangho80f11cb2015-04-01 13:05:26 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
Charles Chan873661e2017-11-30 15:37:50 -080026import org.apache.felix.scr.annotations.Modified;
27import org.apache.felix.scr.annotations.Property;
sangho80f11cb2015-04-01 13:05:26 -070028import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho27462c62015-05-14 00:39:53 -070030import org.apache.felix.scr.annotations.Service;
sangho80f11cb2015-04-01 13:05:26 -070031import org.onlab.packet.Ethernet;
Pier Ventreb6b81d52016-12-02 08:16:05 -080032import org.onlab.packet.ICMP6;
Charles Chan77277672015-10-20 16:24:19 -070033import org.onlab.packet.IPv4;
Pier Ventreb6a7f342016-11-26 21:05:22 -080034import org.onlab.packet.IPv6;
Jonghwan Hyune5ef7622017-08-25 17:48:36 -070035import org.onlab.packet.IpAddress;
Charles Chan77277672015-10-20 16:24:19 -070036import org.onlab.packet.IpPrefix;
Jonathan Hart54541d12016-04-12 15:39:44 -070037import org.onlab.packet.VlanId;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -070038import org.onlab.util.KryoNamespace;
Charles Chan873661e2017-11-30 15:37:50 -080039import org.onlab.util.Tools;
Saurav Dasc3604f12016-03-23 11:22:49 -070040import org.onosproject.cfg.ComponentConfigService;
Pier Luigi580fd8a2018-01-16 10:47:50 +010041import org.onosproject.cluster.ClusterService;
42import org.onosproject.cluster.LeadershipService;
sangho80f11cb2015-04-01 13:05:26 -070043import org.onosproject.core.ApplicationId;
44import org.onosproject.core.CoreService;
45import org.onosproject.event.Event;
Jonathan Hart54541d12016-04-12 15:39:44 -070046import org.onosproject.mastership.MastershipService;
Pier1f87aca2018-03-14 16:47:32 -070047import org.onosproject.mcast.api.McastEvent;
48import org.onosproject.mcast.api.McastListener;
49import org.onosproject.mcast.api.MulticastRouteService;
Pier Ventreb6a7f342016-11-26 21:05:22 -080050import org.onosproject.net.ConnectPoint;
Jonathan Hart54541d12016-04-12 15:39:44 -070051import org.onosproject.net.Device;
52import org.onosproject.net.DeviceId;
Charles Chanf0ae41e2017-08-23 13:55:39 -070053import org.onosproject.net.Host;
54import org.onosproject.net.HostId;
Jonathan Hart54541d12016-04-12 15:39:44 -070055import org.onosproject.net.Link;
56import org.onosproject.net.Port;
Charles Chanf4586112015-11-09 16:37:23 -080057import org.onosproject.net.PortNumber;
Jonghwan Hyune5ef7622017-08-25 17:48:36 -070058import org.onosproject.net.config.ConfigException;
Charles Chan72f556a2015-10-05 17:50:33 -070059import org.onosproject.net.config.ConfigFactory;
60import org.onosproject.net.config.NetworkConfigEvent;
Charles Chan72f556a2015-10-05 17:50:33 -070061import org.onosproject.net.config.NetworkConfigListener;
Jonathan Hart54541d12016-04-12 15:39:44 -070062import org.onosproject.net.config.NetworkConfigRegistry;
Ray Milkeyae0068a2017-08-15 11:02:29 -070063import org.onosproject.net.config.basics.InterfaceConfig;
64import org.onosproject.net.config.basics.McastConfig;
Charles Chan72f556a2015-10-05 17:50:33 -070065import org.onosproject.net.config.basics.SubjectFactories;
Saurav Dase6c448a2018-01-18 12:07:33 -080066import org.onosproject.net.device.DeviceAdminService;
Jonathan Hart54541d12016-04-12 15:39:44 -070067import org.onosproject.net.device.DeviceEvent;
68import org.onosproject.net.device.DeviceListener;
69import org.onosproject.net.device.DeviceService;
Charles Chanf4586112015-11-09 16:37:23 -080070import org.onosproject.net.flow.TrafficSelector;
71import org.onosproject.net.flow.TrafficTreatment;
Jonathan Hart54541d12016-04-12 15:39:44 -070072import org.onosproject.net.flowobjective.FlowObjectiveService;
Charles Chanf4586112015-11-09 16:37:23 -080073import org.onosproject.net.host.HostEvent;
74import org.onosproject.net.host.HostListener;
Charles Chan873661e2017-11-30 15:37:50 -080075import org.onosproject.net.host.HostLocationProbingService;
Pier Ventreb6a7f342016-11-26 21:05:22 -080076import org.onosproject.net.host.HostService;
Jonghwan Hyune5ef7622017-08-25 17:48:36 -070077import org.onosproject.net.host.InterfaceIpAddress;
Ray Milkeyae0068a2017-08-15 11:02:29 -070078import org.onosproject.net.intf.Interface;
79import org.onosproject.net.intf.InterfaceService;
Pier Ventreb6a7f342016-11-26 21:05:22 -080080import org.onosproject.net.link.LinkEvent;
81import org.onosproject.net.link.LinkListener;
82import org.onosproject.net.link.LinkService;
Ray Milkeyae0068a2017-08-15 11:02:29 -070083import org.onosproject.net.neighbour.NeighbourResolutionService;
Pier Ventreb6a7f342016-11-26 21:05:22 -080084import org.onosproject.net.packet.InboundPacket;
85import org.onosproject.net.packet.PacketContext;
86import org.onosproject.net.packet.PacketProcessor;
87import org.onosproject.net.packet.PacketService;
Pier Luigid8a15162018-02-15 16:33:08 +010088import org.onosproject.net.topology.TopologyEvent;
89import org.onosproject.net.topology.TopologyListener;
Charles Chanc91c8782016-03-30 17:54:24 -070090import org.onosproject.net.topology.TopologyService;
Charles Chanf0ae41e2017-08-23 13:55:39 -070091import org.onosproject.routeservice.ResolvedRoute;
Ray Milkeyae0068a2017-08-15 11:02:29 -070092import org.onosproject.routeservice.RouteEvent;
93import org.onosproject.routeservice.RouteListener;
94import org.onosproject.routeservice.RouteService;
Charles Chanc91c8782016-03-30 17:54:24 -070095import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
96import org.onosproject.segmentrouting.config.DeviceConfiguration;
Pier Ventre6b19e482016-11-07 16:21:04 -080097import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Ray Milkeyae0068a2017-08-15 11:02:29 -070098import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chan82f19972016-05-17 13:13:55 -070099import org.onosproject.segmentrouting.config.XConnectConfig;
Charles Chanc91c8782016-03-30 17:54:24 -0700100import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
Saurav Das261c3002017-06-13 15:35:54 -0700101import org.onosproject.segmentrouting.grouphandler.DestinationSet;
102import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
Pier Luigi69f774d2018-02-28 12:10:50 +0100103import org.onosproject.segmentrouting.mcast.McastHandler;
104import org.onosproject.segmentrouting.mcast.McastRole;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700105import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
Andreas Pantelopoulos96851252018-03-20 13:58:49 -0700106import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800107import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelHandler;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700108import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
Andreas Pantelopouloscdbb22c2018-02-23 14:18:00 -0800109
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800110import org.onosproject.segmentrouting.pwaas.L2Tunnel;
Ray Milkeyae0068a2017-08-15 11:02:29 -0700111import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800112import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
Andreas Pantelopouloscdbb22c2018-02-23 14:18:00 -0800113import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
114
Saurav Das261c3002017-06-13 15:35:54 -0700115import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
Pier Luigi0f9635b2018-01-15 18:06:43 +0100116import org.onosproject.segmentrouting.storekey.McastStoreKey;
Charles Chan1eaf4802016-04-18 13:44:03 -0700117import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
Charles Chan10b0fb72017-02-02 16:20:42 -0800118import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
Charles Chan82f19972016-05-17 13:13:55 -0700119import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
Jonathan Hart54541d12016-04-12 15:39:44 -0700120import org.onosproject.store.serializers.KryoNamespaces;
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700121import org.onosproject.store.service.EventuallyConsistentMap;
122import org.onosproject.store.service.EventuallyConsistentMapBuilder;
123import org.onosproject.store.service.StorageService;
124import org.onosproject.store.service.WallClockTimestamp;
Charles Chan873661e2017-11-30 15:37:50 -0800125import org.osgi.service.component.ComponentContext;
sangho80f11cb2015-04-01 13:05:26 -0700126import org.slf4j.Logger;
127import org.slf4j.LoggerFactory;
128
Andreas Pantelopoulosd988c1a2018-03-15 16:56:09 -0700129import java.util.ArrayList;
Jonathan Hart61e24e12017-11-30 18:23:42 -0800130import java.util.Collections;
Charles Chan873661e2017-11-30 15:37:50 -0800131import java.util.Dictionary;
Jonathan Hart61e24e12017-11-30 18:23:42 -0800132import java.util.HashSet;
133import java.util.List;
134import java.util.Map;
Jonathan Hart61e24e12017-11-30 18:23:42 -0800135import java.util.Optional;
136import java.util.Set;
137import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart61e24e12017-11-30 18:23:42 -0800138import java.util.concurrent.Executors;
139import java.util.concurrent.ScheduledExecutorService;
Jonathan Hart61e24e12017-11-30 18:23:42 -0800140import java.util.concurrent.TimeUnit;
141import java.util.concurrent.atomic.AtomicBoolean;
142import java.util.stream.Collectors;
sangho80f11cb2015-04-01 13:05:26 -0700143
Charles Chand6d25332016-02-26 22:19:52 -0800144import static com.google.common.base.Preconditions.checkState;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800145import static org.onlab.packet.Ethernet.TYPE_ARP;
Yuta HIGUCHIebee2f12016-07-21 16:54:33 -0700146import static org.onlab.util.Tools.groupedThreads;
Saurav Dase321cff2018-02-09 17:26:45 -0800147import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REGISTERED;
148import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UNREGISTERED;
Charles Chand6d25332016-02-26 22:19:52 -0800149
Charles Chanb7f75ac2016-01-11 18:28:54 -0800150/**
151 * Segment routing manager.
152 */
Jonathan Hart54541d12016-04-12 15:39:44 -0700153@Service
154@Component(immediate = true)
sangho27462c62015-05-14 00:39:53 -0700155public class SegmentRoutingManager implements SegmentRoutingService {
sangho80f11cb2015-04-01 13:05:26 -0700156
Charles Chan46fdfaf2016-11-09 20:51:44 -0800157 private static Logger log = LoggerFactory.getLogger(SegmentRoutingManager.class);
Charles Chan910be6a2017-08-23 14:46:43 -0700158 private static final String NOT_MASTER = "Current instance is not the master of {}. Ignore.";
sangho80f11cb2015-04-01 13:05:26 -0700159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700161 private ComponentConfigService compCfgService;
sangho80f11cb2015-04-01 13:05:26 -0700162
163 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventreb6a7f342016-11-26 21:05:22 -0800164 private NeighbourResolutionService neighbourResolutionService;
165
166 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Luigi69f774d2018-02-28 12:10:50 +0100167 public CoreService coreService;
sangho80f11cb2015-04-01 13:05:26 -0700168
169 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700170 PacketService packetService;
sangho80f11cb2015-04-01 13:05:26 -0700171
172 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700173 HostService hostService;
sangho80f11cb2015-04-01 13:05:26 -0700174
175 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan873661e2017-11-30 15:37:50 -0800176 HostLocationProbingService probingService;
177
178 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Luigi69f774d2018-02-28 12:10:50 +0100179 public DeviceService deviceService;
sangho80f11cb2015-04-01 13:05:26 -0700180
181 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Saurav Dase6c448a2018-01-18 12:07:33 -0800182 DeviceAdminService deviceAdminService;
183
184 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventref3cf5b92016-11-09 14:17:26 -0800185 public FlowObjectiveService flowObjectiveService;
sangho80f11cb2015-04-01 13:05:26 -0700186
187 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Luigi69f774d2018-02-28 12:10:50 +0100188 public LinkService linkService;
sangho27462c62015-05-14 00:39:53 -0700189
Charles Chan82ab1932016-01-30 23:22:37 -0800190 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventref3cf5b92016-11-09 14:17:26 -0800191 public MastershipService mastershipService;
Charles Chandebfea32016-10-24 14:52:01 -0700192
193 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Ventref3cf5b92016-11-09 14:17:26 -0800194 public StorageService storageService;
Charles Chandebfea32016-10-24 14:52:01 -0700195
196 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pier Luigi69f774d2018-02-28 12:10:50 +0100197 public MulticastRouteService multicastRouteService;
Charles Chandebfea32016-10-24 14:52:01 -0700198
199 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan83163812018-01-09 13:45:07 -0800200 public TopologyService topologyService;
Charles Chandebfea32016-10-24 14:52:01 -0700201
202 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chandebfea32016-10-24 14:52:01 -0700203 RouteService routeService;
Charles Chan82ab1932016-01-30 23:22:37 -0800204
205 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800206 public NetworkConfigRegistry cfgService;
Charles Chan82ab1932016-01-30 23:22:37 -0800207
Saurav Dasc3604f12016-03-23 11:22:49 -0700208 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800209 public InterfaceService interfaceService;
210
Pier Luigi580fd8a2018-01-16 10:47:50 +0100211 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
212 public ClusterService clusterService;
213
214 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
215 public LeadershipService leadershipService;
216
Charles Chan873661e2017-11-30 15:37:50 -0800217 @Property(name = "activeProbing", boolValue = true,
218 label = "Enable active probing to discover dual-homed hosts.")
219 boolean activeProbing = true;
220
Charles Chandebfea32016-10-24 14:52:01 -0700221 ArpHandler arpHandler = null;
222 IcmpHandler icmpHandler = null;
223 IpHandler ipHandler = null;
224 RoutingRulePopulator routingRulePopulator = null;
Ray Milkeyb85de082017-04-05 09:42:04 -0700225 ApplicationId appId;
226 DeviceConfiguration deviceConfiguration = null;
sangho80f11cb2015-04-01 13:05:26 -0700227
Charles Chandebfea32016-10-24 14:52:01 -0700228 DefaultRoutingHandler defaultRoutingHandler = null;
sangho27462c62015-05-14 00:39:53 -0700229 private TunnelHandler tunnelHandler = null;
230 private PolicyHandler policyHandler = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700231 private InternalPacketProcessor processor = null;
232 private InternalLinkListener linkListener = null;
233 private InternalDeviceListener deviceListener = null;
Charles Chan82f19972016-05-17 13:13:55 -0700234 private AppConfigHandler appCfgHandler = null;
Pier Luigi69f774d2018-02-28 12:10:50 +0100235 public XConnectHandler xConnectHandler = null;
Saurav Dase6c448a2018-01-18 12:07:33 -0800236 McastHandler mcastHandler = null;
237 HostHandler hostHandler = null;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800238 private RouteHandler routeHandler = null;
Saurav Dase6c448a2018-01-18 12:07:33 -0800239 LinkHandler linkHandler = null;
Pier Ventreb6b81d52016-12-02 08:16:05 -0800240 private SegmentRoutingNeighbourDispatcher neighbourHandler = null;
Andreas Pantelopouloscdbb22c2018-02-23 14:18:00 -0800241 private DefaultL2TunnelHandler l2TunnelHandler = null;
Pier Luigid8a15162018-02-15 16:33:08 +0100242 private TopologyHandler topologyHandler = null;
Charles Chan82ab1932016-01-30 23:22:37 -0800243 private final InternalHostListener hostListener = new InternalHostListener();
Charles Chanc91c8782016-03-30 17:54:24 -0700244 private final InternalConfigListener cfgListener = new InternalConfigListener(this);
245 private final InternalMcastListener mcastListener = new InternalMcastListener();
Charles Chandebfea32016-10-24 14:52:01 -0700246 private final InternalRouteEventListener routeListener = new InternalRouteEventListener();
Pier Luigid8a15162018-02-15 16:33:08 +0100247 private final InternalTopologyListener topologyListener = new InternalTopologyListener();
sangho80f11cb2015-04-01 13:05:26 -0700248
Charles Chan52003922018-04-05 16:31:15 -0700249 // Handles device, link, topology and network config events
250 private ScheduledExecutorService mainEventExecutor = Executors
251 .newScheduledThreadPool(1, groupedThreads("sr-event-main", "%d", log));
sangho80f11cb2015-04-01 13:05:26 -0700252
Charles Chan52003922018-04-05 16:31:15 -0700253 // Handles host, route, mcast events
254 private ScheduledExecutorService hostEventExecutor = Executors
255 .newScheduledThreadPool(1, groupedThreads("sr-event-host", "%d", log));
256 private ScheduledExecutorService routeEventExecutor = Executors
257 .newScheduledThreadPool(1, groupedThreads("sr-event-route", "%d", log));
258 private ScheduledExecutorService mcastEventExecutor = Executors
259 .newScheduledThreadPool(1, groupedThreads("sr-event-mcast", "%d", log));
260
261
262 Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<>();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800263 /**
Saurav Das261c3002017-06-13 15:35:54 -0700264 * Per device next objective ID store with (device id + destination set) as key.
Charles Chan53de91f2017-08-22 15:07:34 -0700265 * Used to keep track on MPLS group information.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800266 */
Charles Chan873661e2017-11-30 15:37:50 -0800267 private EventuallyConsistentMap<DestinationSetNextObjectiveStoreKey, NextNeighbors>
Saurav Das261c3002017-06-13 15:35:54 -0700268 dsNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800269 /**
Charles Chan53de91f2017-08-22 15:07:34 -0700270 * Per device next objective ID store with (device id + vlanid) as key.
271 * Used to keep track on L2 flood group information.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800272 */
Charles Chan873661e2017-11-30 15:37:50 -0800273 private EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
Charles Chan10b0fb72017-02-02 16:20:42 -0800274 vlanNextObjStore = null;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800275 /**
Charles Chan53de91f2017-08-22 15:07:34 -0700276 * Per device next objective ID store with (device id + port + treatment + meta) as key.
277 * Used to keep track on L2 interface group and L3 unicast group information.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800278 */
Charles Chan873661e2017-11-30 15:37:50 -0800279 private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das2d94d312015-11-24 23:21:05 -0800280 portNextObjStore = null;
Charles Chan10b0fb72017-02-02 16:20:42 -0800281
Saurav Das2d94d312015-11-24 23:21:05 -0800282 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
283 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho4a5c42a2015-05-20 22:16:38 -0700284
Saurav Das261c3002017-06-13 15:35:54 -0700285 private AtomicBoolean programmingScheduled = new AtomicBoolean();
286
Charles Chanc91c8782016-03-30 17:54:24 -0700287 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> deviceConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700288 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(
289 SubjectFactories.DEVICE_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700290 SegmentRoutingDeviceConfig.class, "segmentrouting") {
Charles Chan72f556a2015-10-05 17:50:33 -0700291 @Override
Charles Chan82ab1932016-01-30 23:22:37 -0800292 public SegmentRoutingDeviceConfig createConfig() {
293 return new SegmentRoutingDeviceConfig();
Charles Chan72f556a2015-10-05 17:50:33 -0700294 }
295 };
Pier Ventre6b19e482016-11-07 16:21:04 -0800296
Charles Chanc91c8782016-03-30 17:54:24 -0700297 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> appConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700298 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(
299 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700300 SegmentRoutingAppConfig.class, "segmentrouting") {
Charles Chan82ab1932016-01-30 23:22:37 -0800301 @Override
302 public SegmentRoutingAppConfig createConfig() {
303 return new SegmentRoutingAppConfig();
304 }
305 };
Pier Ventre6b19e482016-11-07 16:21:04 -0800306
Charles Chan82f19972016-05-17 13:13:55 -0700307 private final ConfigFactory<ApplicationId, XConnectConfig> xConnectConfigFactory =
308 new ConfigFactory<ApplicationId, XConnectConfig>(
309 SubjectFactories.APP_SUBJECT_FACTORY,
310 XConnectConfig.class, "xconnect") {
311 @Override
312 public XConnectConfig createConfig() {
313 return new XConnectConfig();
314 }
315 };
Pier Ventre6b19e482016-11-07 16:21:04 -0800316
Charles Chanc91c8782016-03-30 17:54:24 -0700317 private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
Charles Chan82f19972016-05-17 13:13:55 -0700318 new ConfigFactory<ApplicationId, McastConfig>(
319 SubjectFactories.APP_SUBJECT_FACTORY,
Charles Chanc91c8782016-03-30 17:54:24 -0700320 McastConfig.class, "multicast") {
321 @Override
322 public McastConfig createConfig() {
323 return new McastConfig();
324 }
325 };
326
Charles Chan3ed34d82017-06-22 18:03:14 -0700327 private static final Object THREAD_SCHED_LOCK = new Object();
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -0700328 private static int numOfEventsQueued = 0;
329 private static int numOfEventsExecuted = 0;
sangho80f11cb2015-04-01 13:05:26 -0700330 private static int numOfHandlerExecution = 0;
331 private static int numOfHandlerScheduled = 0;
332
Charles Chan1963f4f2016-02-18 14:22:42 -0800333 /**
334 * Segment Routing App ID.
335 */
Charles Chan46fdfaf2016-11-09 20:51:44 -0800336 public static final String APP_NAME = "org.onosproject.segmentrouting";
Charles Chan10b0fb72017-02-02 16:20:42 -0800337
Charles Chanb7f75ac2016-01-11 18:28:54 -0800338 /**
339 * The default VLAN ID assigned to the interfaces without subnet config.
340 */
Charles Chan10b0fb72017-02-02 16:20:42 -0800341 public static final VlanId INTERNAL_VLAN = VlanId.vlanId((short) 4094);
Saurav Das7c305372015-10-28 12:39:42 -0700342
sangho80f11cb2015-04-01 13:05:26 -0700343 @Activate
Charles Chan873661e2017-11-30 15:37:50 -0800344 protected void activate(ComponentContext context) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800345 appId = coreService.registerApplication(APP_NAME);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700346
347 log.debug("Creating EC map nsnextobjectivestore");
Saurav Das261c3002017-06-13 15:35:54 -0700348 EventuallyConsistentMapBuilder<DestinationSetNextObjectiveStoreKey, NextNeighbors>
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700349 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das261c3002017-06-13 15:35:54 -0700350 dsNextObjStore = nsNextObjMapBuilder
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700351 .withName("nsnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700352 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700353 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700354 .build();
Saurav Das261c3002017-06-13 15:35:54 -0700355 log.trace("Current size {}", dsNextObjStore.size());
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700356
Charles Chan10b0fb72017-02-02 16:20:42 -0800357 log.debug("Creating EC map vlannextobjectivestore");
358 EventuallyConsistentMapBuilder<VlanNextObjectiveStoreKey, Integer>
359 vlanNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
360 vlanNextObjStore = vlanNextObjMapBuilder
361 .withName("vlannextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700362 .withSerializer(createSerializer())
Charles Chan77277672015-10-20 16:24:19 -0700363 .withTimestampProvider((k, v) -> new WallClockTimestamp())
364 .build();
365
Saurav Das2d94d312015-11-24 23:21:05 -0800366 log.debug("Creating EC map subnetnextobjectivestore");
367 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
368 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
369 portNextObjStore = portNextObjMapBuilder
370 .withName("portnextobjectivestore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700371 .withSerializer(createSerializer())
Saurav Das2d94d312015-11-24 23:21:05 -0800372 .withTimestampProvider((k, v) -> new WallClockTimestamp())
373 .build();
374
sangho4a5c42a2015-05-20 22:16:38 -0700375 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
376 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700377 tunnelStore = tunnelMapBuilder
378 .withName("tunnelstore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700379 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700380 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700381 .build();
382
383 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
384 storageService.eventuallyConsistentMapBuilder();
sangho4a5c42a2015-05-20 22:16:38 -0700385 policyStore = policyMapBuilder
386 .withName("policystore")
Jonathan Hart54541d12016-04-12 15:39:44 -0700387 .withSerializer(createSerializer())
Madan Jampani675ae202015-06-24 19:05:56 -0700388 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho4a5c42a2015-05-20 22:16:38 -0700389 .build();
390
Saurav Dasc3604f12016-03-23 11:22:49 -0700391 compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
Pier Luigib9632ba2017-01-12 18:14:58 -0800392 "purgeOnDisconnection", "true");
Saurav Dasc3604f12016-03-23 11:22:49 -0700393 compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
Pier Luigib9632ba2017-01-12 18:14:58 -0800394 "purgeOnDisconnection", "true");
Pier Luigib9632ba2017-01-12 18:14:58 -0800395 compCfgService.preSetProperty("org.onosproject.provider.host.impl.HostLocationProvider",
396 "requestInterceptsEnabled", "false");
Charles Chanc1909e12017-08-08 15:13:37 -0700397 compCfgService.preSetProperty("org.onosproject.net.neighbour.impl.NeighbourResolutionManager",
Pier Luigibc976df2017-01-12 22:46:39 -0800398 "requestInterceptsEnabled", "false");
Charles Chan9597f8d2017-07-24 15:56:10 -0700399 compCfgService.preSetProperty("org.onosproject.dhcprelay.DhcpRelayManager",
Pier Luigibc976df2017-01-12 22:46:39 -0800400 "arpEnabled", "false");
Pier Luigi0ebeb312017-02-02 22:31:34 -0800401 compCfgService.preSetProperty("org.onosproject.net.host.impl.HostManager",
402 "greedyLearningIpv6", "true");
Charles Chancf8ea472017-02-28 15:15:17 -0800403 compCfgService.preSetProperty("org.onosproject.routing.cpr.ControlPlaneRedirectManager",
404 "forceUnprovision", "true");
Charles Chanc7b73c72017-08-10 16:57:28 -0700405 compCfgService.preSetProperty("org.onosproject.routeservice.store.RouteStoreImpl",
Charles Chan4c95c0d2017-07-20 16:16:25 -0700406 "distributed", "true");
Charles Chan804772f2017-08-14 11:42:11 -0700407 compCfgService.preSetProperty("org.onosproject.provider.host.impl.HostLocationProvider",
408 "multihomingEnabled", "true");
Charles Chan0c9c19f2017-11-29 19:54:20 -0800409 compCfgService.preSetProperty("org.onosproject.provider.lldp.impl.LldpLinkProvider",
410 "staleLinkAge", "15000");
411 compCfgService.preSetProperty("org.onosproject.net.host.impl.HostManager",
412 "allowDuplicateIps", "false");
Charles Chan873661e2017-11-30 15:37:50 -0800413 compCfgService.registerProperties(getClass());
414 modified(context);
Saurav Dasc3604f12016-03-23 11:22:49 -0700415
Charles Chan2b078ae2015-10-14 11:24:40 -0700416 processor = new InternalPacketProcessor();
417 linkListener = new InternalLinkListener();
418 deviceListener = new InternalDeviceListener();
Charles Chan82f19972016-05-17 13:13:55 -0700419 appCfgHandler = new AppConfigHandler(this);
420 xConnectHandler = new XConnectHandler(this);
Charles Chan1eaf4802016-04-18 13:44:03 -0700421 mcastHandler = new McastHandler(this);
422 hostHandler = new HostHandler(this);
Saurav Dase6c448a2018-01-18 12:07:33 -0800423 linkHandler = new LinkHandler(this);
Charles Chandebfea32016-10-24 14:52:01 -0700424 routeHandler = new RouteHandler(this);
Pier Ventreb6b81d52016-12-02 08:16:05 -0800425 neighbourHandler = new SegmentRoutingNeighbourDispatcher(this);
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800426 l2TunnelHandler = new DefaultL2TunnelHandler(this);
Pier Luigid8a15162018-02-15 16:33:08 +0100427 topologyHandler = new TopologyHandler(this);
Charles Chan2b078ae2015-10-14 11:24:40 -0700428
Charles Chand6d25332016-02-26 22:19:52 -0800429 cfgService.addListener(cfgListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700430 cfgService.registerConfigFactory(deviceConfigFactory);
431 cfgService.registerConfigFactory(appConfigFactory);
Charles Chan82f19972016-05-17 13:13:55 -0700432 cfgService.registerConfigFactory(xConnectConfigFactory);
Charles Chanc91c8782016-03-30 17:54:24 -0700433 cfgService.registerConfigFactory(mcastConfigFactory);
Saurav Dase321cff2018-02-09 17:26:45 -0800434 log.info("Configuring network before adding listeners");
Charles Chan6961f222018-01-04 14:26:07 -0800435 cfgListener.configureNetwork();
436
Charles Chan82ab1932016-01-30 23:22:37 -0800437 hostService.addListener(hostListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700438 packetService.addProcessor(processor, PacketProcessor.director(2));
439 linkService.addListener(linkListener);
440 deviceService.addListener(deviceListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700441 multicastRouteService.addListener(mcastListener);
Charles Chanfd48c222017-06-19 00:43:31 -0700442 routeService.addListener(routeListener);
Pier Luigid8a15162018-02-15 16:33:08 +0100443 topologyService.addListener(topologyListener);
Charles Chan2b078ae2015-10-14 11:24:40 -0700444
Charles Chanc12c3d02018-03-09 15:53:44 -0800445 linkHandler.init();
Andreas Pantelopoulos75eef062018-01-11 07:53:48 -0800446 l2TunnelHandler.init();
447
sangho80f11cb2015-04-01 13:05:26 -0700448 log.info("Started");
449 }
450
Saurav Dase6c448a2018-01-18 12:07:33 -0800451 KryoNamespace.Builder createSerializer() {
Jonathan Hart54541d12016-04-12 15:39:44 -0700452 return new KryoNamespace.Builder()
453 .register(KryoNamespaces.API)
Saurav Das261c3002017-06-13 15:35:54 -0700454 .register(DestinationSetNextObjectiveStoreKey.class,
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800455 VlanNextObjectiveStoreKey.class,
456 DestinationSet.class,
457 NextNeighbors.class,
458 Tunnel.class,
459 DefaultTunnel.class,
460 Policy.class,
461 TunnelPolicy.class,
462 Policy.Type.class,
463 PortNextObjectiveStoreKey.class,
464 XConnectStoreKey.class,
465 L2Tunnel.class,
466 L2TunnelPolicy.class,
467 DefaultL2Tunnel.class,
468 DefaultL2TunnelPolicy.class
Jonathan Hart54541d12016-04-12 15:39:44 -0700469 );
470 }
471
sangho80f11cb2015-04-01 13:05:26 -0700472 @Deactivate
473 protected void deactivate() {
Charles Chan72f556a2015-10-05 17:50:33 -0700474 cfgService.removeListener(cfgListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700475 cfgService.unregisterConfigFactory(deviceConfigFactory);
476 cfgService.unregisterConfigFactory(appConfigFactory);
Charles Chandebfea32016-10-24 14:52:01 -0700477 cfgService.unregisterConfigFactory(xConnectConfigFactory);
Charles Chanc91c8782016-03-30 17:54:24 -0700478 cfgService.unregisterConfigFactory(mcastConfigFactory);
Charles Chan873661e2017-11-30 15:37:50 -0800479 compCfgService.unregisterProperties(getClass(), false);
Charles Chan72f556a2015-10-05 17:50:33 -0700480
Charles Chanfd48c222017-06-19 00:43:31 -0700481 hostService.removeListener(hostListener);
sangho80f11cb2015-04-01 13:05:26 -0700482 packetService.removeProcessor(processor);
Charles Chan2b078ae2015-10-14 11:24:40 -0700483 linkService.removeListener(linkListener);
484 deviceService.removeListener(deviceListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700485 multicastRouteService.removeListener(mcastListener);
Charles Chandebfea32016-10-24 14:52:01 -0700486 routeService.removeListener(routeListener);
Pier Luigid8a15162018-02-15 16:33:08 +0100487 topologyService.removeListener(topologyListener);
Charles Chanc91c8782016-03-30 17:54:24 -0700488
Charles Chan2e71ef32017-02-23 15:44:08 -0800489 neighbourResolutionService.unregisterNeighbourHandlers(appId);
490
sangho80f11cb2015-04-01 13:05:26 -0700491 processor = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700492 linkListener = null;
Charles Chanc91c8782016-03-30 17:54:24 -0700493 deviceListener = null;
Charles Chan2b078ae2015-10-14 11:24:40 -0700494 groupHandlerMap.clear();
495
Saurav Das261c3002017-06-13 15:35:54 -0700496 dsNextObjStore.destroy();
Charles Chan10b0fb72017-02-02 16:20:42 -0800497 vlanNextObjStore.destroy();
Charles Chanc91c8782016-03-30 17:54:24 -0700498 portNextObjStore.destroy();
Charles Chanc91c8782016-03-30 17:54:24 -0700499 tunnelStore.destroy();
500 policyStore.destroy();
Pier Luigi35dab3f2018-01-25 16:16:02 +0100501
502 mcastHandler.terminate();
sangho80f11cb2015-04-01 13:05:26 -0700503 log.info("Stopped");
504 }
505
Charles Chan873661e2017-11-30 15:37:50 -0800506 @Modified
507 private void modified(ComponentContext context) {
508 Dictionary<?, ?> properties = context.getProperties();
509 if (properties == null) {
510 return;
511 }
512
513 String strActiveProving = Tools.get(properties, "activeProbing");
514 boolean expectActiveProbing = Boolean.parseBoolean(strActiveProving);
515
516 if (expectActiveProbing != activeProbing) {
517 activeProbing = expectActiveProbing;
518 log.info("{} active probing", activeProbing ? "Enabling" : "Disabling");
519 }
520 }
521
sangho27462c62015-05-14 00:39:53 -0700522 @Override
523 public List<Tunnel> getTunnels() {
524 return tunnelHandler.getTunnels();
525 }
526
527 @Override
sanghobd812f82015-06-29 14:58:47 -0700528 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
529 return tunnelHandler.createTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700530 }
531
532 @Override
sanghobd812f82015-06-29 14:58:47 -0700533 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho27462c62015-05-14 00:39:53 -0700534 for (Policy policy: policyHandler.getPolicies()) {
535 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
536 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
537 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
538 log.warn("Cannot remove the tunnel used by a policy");
sanghobd812f82015-06-29 14:58:47 -0700539 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho27462c62015-05-14 00:39:53 -0700540 }
541 }
542 }
sanghobd812f82015-06-29 14:58:47 -0700543 return tunnelHandler.removeTunnel(tunnel);
sangho27462c62015-05-14 00:39:53 -0700544 }
545
546 @Override
sanghobd812f82015-06-29 14:58:47 -0700547 public PolicyHandler.Result removePolicy(Policy policy) {
548 return policyHandler.removePolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700549 }
550
551 @Override
sanghobd812f82015-06-29 14:58:47 -0700552 public PolicyHandler.Result createPolicy(Policy policy) {
553 return policyHandler.createPolicy(policy);
sangho27462c62015-05-14 00:39:53 -0700554 }
555
556 @Override
557 public List<Policy> getPolicies() {
558 return policyHandler.getPolicies();
559 }
560
Saurav Das07c74602016-04-27 18:35:50 -0700561 @Override
Andreas Pantelopoulosd988c1a2018-03-15 16:56:09 -0700562 public Set<L2TunnelDescription> getL2TunnelDescriptions(boolean pending) {
563 return l2TunnelHandler.getL2Descriptions(pending);
Andreas Pantelopoulosfc4bc2a2018-03-12 16:30:20 -0700564 }
565
566 @Override
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800567 public List<L2Tunnel> getL2Tunnels() {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700568 return l2TunnelHandler.getL2Tunnels();
569 }
570
571 @Override
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800572 public List<L2TunnelPolicy> getL2Policies() {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700573 return l2TunnelHandler.getL2Policies();
574 }
575
Andreas Pantelopoulos96851252018-03-20 13:58:49 -0700576 @Deprecated
Andreas Pantelopoulosfc4bc2a2018-03-12 16:30:20 -0700577 public L2TunnelHandler.Result addPseudowiresBulk(List<DefaultL2TunnelDescription> bulkPseudowires) {
578
Andreas Pantelopoulosd988c1a2018-03-15 16:56:09 -0700579 // get both added and pending pseudowires
580 List<L2TunnelDescription> pseudowires = new ArrayList<>();
581 pseudowires.addAll(l2TunnelHandler.getL2Descriptions(false));
582 pseudowires.addAll(l2TunnelHandler.getL2Descriptions(true));
Andreas Pantelopoulosfc4bc2a2018-03-12 16:30:20 -0700583 pseudowires.addAll(bulkPseudowires);
Andreas Pantelopoulosd988c1a2018-03-15 16:56:09 -0700584
Andreas Pantelopoulosfc4bc2a2018-03-12 16:30:20 -0700585 Set<L2TunnelDescription> newPseudowires = new HashSet(bulkPseudowires);
586
Andreas Pantelopoulos96851252018-03-20 13:58:49 -0700587 L2TunnelHandler.Result retRes = L2TunnelHandler.Result.SUCCESS;
588 L2TunnelHandler.Result res;
589 for (DefaultL2TunnelDescription pw : bulkPseudowires) {
590 res = addPseudowire(pw);
591 if (res != L2TunnelHandler.Result.SUCCESS) {
592 log.error("Pseudowire with id {} can not be instantiated !", res);
593 retRes = res;
594 }
Andreas Pantelopoulosfc4bc2a2018-03-12 16:30:20 -0700595 }
Andreas Pantelopoulos96851252018-03-20 13:58:49 -0700596
597 return retRes;
Andreas Pantelopoulosfc4bc2a2018-03-12 16:30:20 -0700598 }
599
600 @Override
Andreas Pantelopouloscdbb22c2018-02-23 14:18:00 -0800601 public L2TunnelHandler.Result addPseudowire(L2TunnelDescription l2TunnelDescription) {
Andreas Pantelopoulos87a06102018-03-21 16:44:18 -0700602 return l2TunnelHandler.deployPseudowire(l2TunnelDescription);
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700603 }
604
605 @Override
Andreas Pantelopouloscdbb22c2018-02-23 14:18:00 -0800606 public L2TunnelHandler.Result removePseudowire(Integer pwId) {
Andreas Pantelopoulos87a06102018-03-21 16:44:18 -0700607 return l2TunnelHandler.tearDownPseudowire(pwId);
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700608 }
609
610 @Override
Saurav Das07c74602016-04-27 18:35:50 -0700611 public void rerouteNetwork() {
612 cfgListener.configureNetwork();
Saurav Das07c74602016-04-27 18:35:50 -0700613 }
614
Charles Chand7844e52016-10-20 17:02:44 -0700615 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800616 public Map<DeviceId, Set<IpPrefix>> getDeviceSubnetMap() {
617 Map<DeviceId, Set<IpPrefix>> deviceSubnetMap = Maps.newHashMap();
Jonathan Hart61e24e12017-11-30 18:23:42 -0800618 deviceConfiguration.getRouters().forEach(device ->
619 deviceSubnetMap.put(device, deviceConfiguration.getSubnets(device)));
Charles Chand7844e52016-10-20 17:02:44 -0700620 return deviceSubnetMap;
621 }
622
Saurav Das62ae6792017-05-15 15:34:25 -0700623
624 @Override
625 public ImmutableMap<DeviceId, EcmpShortestPathGraph> getCurrentEcmpSpg() {
626 if (defaultRoutingHandler != null) {
627 return defaultRoutingHandler.getCurrentEmcpSpgMap();
628 } else {
629 return null;
630 }
631 }
632
633 @Override
Saurav Das261c3002017-06-13 15:35:54 -0700634 public ImmutableMap<DestinationSetNextObjectiveStoreKey, NextNeighbors> getDestinationSet() {
635 if (dsNextObjStore != null) {
636 return ImmutableMap.copyOf(dsNextObjStore.entrySet());
Saurav Das62ae6792017-05-15 15:34:25 -0700637 } else {
638 return ImmutableMap.of();
639 }
640 }
641
Saurav Dasfbe74572017-08-03 18:30:35 -0700642 @Override
643 public void verifyGroups(DeviceId id) {
644 DefaultGroupHandler gh = groupHandlerMap.get(id);
645 if (gh != null) {
646 gh.triggerBucketCorrector();
647 }
648 }
649
Saurav Das6430f412018-01-25 09:49:01 -0800650 @Override
651 public ImmutableMap<Link, Boolean> getSeenLinks() {
652 return linkHandler.getSeenLinks();
653 }
654
655 @Override
656 public ImmutableMap<DeviceId, Set<PortNumber>> getDownedPortState() {
657 return linkHandler.getDownedPorts();
658 }
659
Pier Luigi0f9635b2018-01-15 18:06:43 +0100660 @Override
661 public Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp) {
662 return mcastHandler.getMcastNextIds(mcastIp);
663 }
664
665 @Override
Pier Luigi69f774d2018-02-28 12:10:50 +0100666 public Map<McastStoreKey, McastRole> getMcastRoles(IpAddress mcastIp) {
Pier Luigi0f9635b2018-01-15 18:06:43 +0100667 return mcastHandler.getMcastRoles(mcastIp);
668 }
669
670 @Override
671 public Map<ConnectPoint, List<ConnectPoint>> getMcastPaths(IpAddress mcastIp) {
672 return mcastHandler.getMcastPaths(mcastIp);
673 }
674
sangho80f1f892015-05-19 11:57:42 -0700675 /**
Ray Milkeyb85de082017-04-05 09:42:04 -0700676 * Extracts the application ID from the manager.
677 *
678 * @return application ID
679 */
680 public ApplicationId appId() {
681 return appId;
682 }
683
684 /**
685 * Returns the device configuration.
686 *
687 * @return device configuration
688 */
689 public DeviceConfiguration deviceConfiguration() {
690 return deviceConfiguration;
691 }
692
693 /**
Saurav Das261c3002017-06-13 15:35:54 -0700694 * Per device next objective ID store with (device id + destination set) as key.
Charles Chan53de91f2017-08-22 15:07:34 -0700695 * Used to keep track on MPLS group information.
Ray Milkeyb85de082017-04-05 09:42:04 -0700696 *
697 * @return next objective ID store
698 */
Saurav Das261c3002017-06-13 15:35:54 -0700699 public EventuallyConsistentMap<DestinationSetNextObjectiveStoreKey, NextNeighbors>
700 dsNextObjStore() {
701 return dsNextObjStore;
Ray Milkeyb85de082017-04-05 09:42:04 -0700702 }
703
704 /**
Charles Chan53de91f2017-08-22 15:07:34 -0700705 * Per device next objective ID store with (device id + vlanid) as key.
706 * Used to keep track on L2 flood group information.
Ray Milkeyb85de082017-04-05 09:42:04 -0700707 *
708 * @return vlan next object store
709 */
710 public EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer> vlanNextObjStore() {
711 return vlanNextObjStore;
712 }
713
714 /**
Charles Chan53de91f2017-08-22 15:07:34 -0700715 * Per device next objective ID store with (device id + port + treatment + meta) as key.
716 * Used to keep track on L2 interface group and L3 unicast group information.
Ray Milkeyb85de082017-04-05 09:42:04 -0700717 *
718 * @return port next object store.
719 */
720 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer> portNextObjStore() {
721 return portNextObjStore;
722 }
723
724 /**
Saurav Das261c3002017-06-13 15:35:54 -0700725 * Returns the MPLS-ECMP configuration which indicates whether ECMP on
726 * labeled packets should be programmed or not.
Pier Ventre7a78de22016-10-31 15:00:01 -0700727 *
728 * @return MPLS-ECMP value
729 */
730 public boolean getMplsEcmp() {
731 SegmentRoutingAppConfig segmentRoutingAppConfig = cfgService
732 .getConfig(this.appId, SegmentRoutingAppConfig.class);
733 return segmentRoutingAppConfig != null && segmentRoutingAppConfig.mplsEcmp();
734 }
735
736 /**
sangho80f1f892015-05-19 11:57:42 -0700737 * Returns the tunnel object with the tunnel ID.
738 *
739 * @param tunnelId Tunnel ID
740 * @return Tunnel reference
741 */
sangho27462c62015-05-14 00:39:53 -0700742 public Tunnel getTunnel(String tunnelId) {
743 return tunnelHandler.getTunnel(tunnelId);
744 }
745
Charles Chan90772a72017-02-08 15:52:08 -0800746 // TODO Consider moving these to InterfaceService
sangho80f11cb2015-04-01 13:05:26 -0700747 /**
Charles Chan10b0fb72017-02-02 16:20:42 -0800748 * Returns untagged VLAN configured on given connect point.
Charles Chan90772a72017-02-08 15:52:08 -0800749 * <p>
750 * Only returns the first match if there are multiple untagged VLAN configured
751 * on the connect point.
sangho80f11cb2015-04-01 13:05:26 -0700752 *
Charles Chan10b0fb72017-02-02 16:20:42 -0800753 * @param connectPoint connect point
754 * @return untagged VLAN or null if not configured
sangho80f11cb2015-04-01 13:05:26 -0700755 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700756 VlanId getUntaggedVlanId(ConnectPoint connectPoint) {
Charles Chan10b0fb72017-02-02 16:20:42 -0800757 return interfaceService.getInterfacesByPort(connectPoint).stream()
758 .filter(intf -> !intf.vlanUntagged().equals(VlanId.NONE))
759 .map(Interface::vlanUntagged)
760 .findFirst().orElse(null);
sangho80f11cb2015-04-01 13:05:26 -0700761 }
762
sangho27462c62015-05-14 00:39:53 -0700763 /**
Charles Chan90772a72017-02-08 15:52:08 -0800764 * Returns tagged VLAN configured on given connect point.
765 * <p>
766 * Returns all matches if there are multiple tagged VLAN configured
767 * on the connect point.
768 *
769 * @param connectPoint connect point
770 * @return tagged VLAN or empty set if not configured
771 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700772 Set<VlanId> getTaggedVlanId(ConnectPoint connectPoint) {
Charles Chan90772a72017-02-08 15:52:08 -0800773 Set<Interface> interfaces = interfaceService.getInterfacesByPort(connectPoint);
774 return interfaces.stream()
775 .map(Interface::vlanTagged)
Charles Chan3ed34d82017-06-22 18:03:14 -0700776 .flatMap(Set::stream)
Charles Chan90772a72017-02-08 15:52:08 -0800777 .collect(Collectors.toSet());
778 }
779
780 /**
781 * Returns native VLAN configured on given connect point.
782 * <p>
783 * Only returns the first match if there are multiple native VLAN configured
784 * on the connect point.
785 *
786 * @param connectPoint connect point
787 * @return native VLAN or null if not configured
788 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700789 VlanId getNativeVlanId(ConnectPoint connectPoint) {
Charles Chan90772a72017-02-08 15:52:08 -0800790 Set<Interface> interfaces = interfaceService.getInterfacesByPort(connectPoint);
791 return interfaces.stream()
792 .filter(intf -> !intf.vlanNative().equals(VlanId.NONE))
793 .map(Interface::vlanNative)
794 .findFirst()
795 .orElse(null);
796 }
797
798 /**
Charles Chand9265a32017-06-16 15:19:24 -0700799 * Returns internal VLAN for untagged hosts on given connect point.
800 * <p>
801 * The internal VLAN is either vlan-untagged for an access port,
802 * or vlan-native for a trunk port.
803 *
804 * @param connectPoint connect point
805 * @return internal VLAN or null if both vlan-untagged and vlan-native are undefined
806 */
Pier Luigi69f774d2018-02-28 12:10:50 +0100807 public VlanId getInternalVlanId(ConnectPoint connectPoint) {
Charles Chand9265a32017-06-16 15:19:24 -0700808 VlanId untaggedVlanId = getUntaggedVlanId(connectPoint);
809 VlanId nativeVlanId = getNativeVlanId(connectPoint);
810 return untaggedVlanId != null ? untaggedVlanId : nativeVlanId;
811 }
812
813 /**
Charles Chan3ed34d82017-06-22 18:03:14 -0700814 * Returns optional pair device ID of given device.
815 *
816 * @param deviceId device ID
817 * @return optional pair device ID. Might be empty if pair device is not configured
818 */
819 Optional<DeviceId> getPairDeviceId(DeviceId deviceId) {
820 SegmentRoutingDeviceConfig deviceConfig =
821 cfgService.getConfig(deviceId, SegmentRoutingDeviceConfig.class);
822 return Optional.ofNullable(deviceConfig).map(SegmentRoutingDeviceConfig::pairDeviceId);
823 }
824 /**
825 * Returns optional pair device local port of given device.
826 *
827 * @param deviceId device ID
828 * @return optional pair device ID. Might be empty if pair device is not configured
829 */
830 Optional<PortNumber> getPairLocalPorts(DeviceId deviceId) {
831 SegmentRoutingDeviceConfig deviceConfig =
832 cfgService.getConfig(deviceId, SegmentRoutingDeviceConfig.class);
833 return Optional.ofNullable(deviceConfig).map(SegmentRoutingDeviceConfig::pairLocalPort);
834 }
835
836 /**
Charles Chan910be6a2017-08-23 14:46:43 -0700837 * Determine if current instance is the master of given connect point.
838 *
839 * @param cp connect point
840 * @return true if current instance is the master of given connect point
841 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700842 public boolean isMasterOf(ConnectPoint cp) {
Charles Chan910be6a2017-08-23 14:46:43 -0700843 boolean isMaster = mastershipService.isLocalMaster(cp.deviceId());
844 if (!isMaster) {
845 log.debug(NOT_MASTER, cp);
846 }
847 return isMaster;
848 }
849
850 /**
Charles Chanf0ae41e2017-08-23 13:55:39 -0700851 * Returns locations of given resolved route.
852 *
853 * @param resolvedRoute resolved route
854 * @return locations of nexthop. Might be empty if next hop is not found
855 */
856 Set<ConnectPoint> nextHopLocations(ResolvedRoute resolvedRoute) {
857 HostId hostId = HostId.hostId(resolvedRoute.nextHopMac(), resolvedRoute.nextHopVlan());
858 return Optional.ofNullable(hostService.getHost(hostId))
859 .map(Host::locations).orElse(Sets.newHashSet())
860 .stream().map(l -> (ConnectPoint) l).collect(Collectors.toSet());
861 }
862
863 /**
Charles Chan90772a72017-02-08 15:52:08 -0800864 * Returns vlan port map of given device.
865 *
866 * @param deviceId device id
867 * @return vlan-port multimap
868 */
869 public Multimap<VlanId, PortNumber> getVlanPortMap(DeviceId deviceId) {
870 HashMultimap<VlanId, PortNumber> vlanPortMap = HashMultimap.create();
871
872 interfaceService.getInterfaces().stream()
873 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
874 .forEach(intf -> {
875 vlanPortMap.put(intf.vlanUntagged(), intf.connectPoint().port());
Charles Chan3ed34d82017-06-22 18:03:14 -0700876 intf.vlanTagged().forEach(vlanTagged ->
877 vlanPortMap.put(vlanTagged, intf.connectPoint().port())
878 );
Charles Chan90772a72017-02-08 15:52:08 -0800879 vlanPortMap.put(intf.vlanNative(), intf.connectPoint().port());
880 });
881 vlanPortMap.removeAll(VlanId.NONE);
882
883 return vlanPortMap;
884 }
885
886 /**
Charles Chan10b0fb72017-02-02 16:20:42 -0800887 * Returns the next objective ID for the given vlan id. It is expected
Saurav Das2d94d312015-11-24 23:21:05 -0800888 * that the next-objective has been pre-created from configuration.
Charles Chan77277672015-10-20 16:24:19 -0700889 *
890 * @param deviceId Device ID
Charles Chan10b0fb72017-02-02 16:20:42 -0800891 * @param vlanId VLAN ID
Saurav Das2d94d312015-11-24 23:21:05 -0800892 * @return next objective ID or -1 if it was not found
Charles Chan77277672015-10-20 16:24:19 -0700893 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700894 int getVlanNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
Charles Chan77277672015-10-20 16:24:19 -0700895 if (groupHandlerMap.get(deviceId) != null) {
Charles Chan10b0fb72017-02-02 16:20:42 -0800896 log.trace("getVlanNextObjectiveId query in device {}", deviceId);
897 return groupHandlerMap.get(deviceId).getVlanNextObjectiveId(vlanId);
Charles Chan77277672015-10-20 16:24:19 -0700898 } else {
Charles Chan10b0fb72017-02-02 16:20:42 -0800899 log.warn("getVlanNextObjectiveId query - groupHandler for "
Saurav Das2d94d312015-11-24 23:21:05 -0800900 + "device {} not found", deviceId);
901 return -1;
902 }
903 }
904
905 /**
906 * Returns the next objective ID for the given portNumber, given the treatment.
907 * There could be multiple different treatments to the same outport, which
Saurav Das2cb38292017-03-29 19:09:17 -0700908 * would result in different objectives. If the next object does not exist,
909 * and should be created, a new one is created and its id is returned.
Saurav Das2d94d312015-11-24 23:21:05 -0800910 *
911 * @param deviceId Device ID
912 * @param portNum port number on device for which NextObjective is queried
913 * @param treatment the actions to apply on the packets (should include outport)
914 * @param meta metadata passed into the creation of a Next Objective if necessary
Saurav Das2cb38292017-03-29 19:09:17 -0700915 * @param createIfMissing true if a next object should be created if not found
Saurav Das07c74602016-04-27 18:35:50 -0700916 * @return next objective ID or -1 if an error occurred during retrieval or creation
Saurav Das2d94d312015-11-24 23:21:05 -0800917 */
918 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
919 TrafficTreatment treatment,
Saurav Das2cb38292017-03-29 19:09:17 -0700920 TrafficSelector meta,
921 boolean createIfMissing) {
Saurav Das2d94d312015-11-24 23:21:05 -0800922 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
923 if (ghdlr != null) {
Saurav Das2cb38292017-03-29 19:09:17 -0700924 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta, createIfMissing);
Saurav Das2d94d312015-11-24 23:21:05 -0800925 } else {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800926 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
927 + " not found", deviceId);
928 return -1;
929 }
930 }
931
Saurav Das62ae6792017-05-15 15:34:25 -0700932 /**
933 * Returns the group handler object for the specified device id.
934 *
935 * @param devId the device identifier
936 * @return the groupHandler object for the device id, or null if not found
937 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700938 DefaultGroupHandler getGroupHandler(DeviceId devId) {
Saurav Das62ae6792017-05-15 15:34:25 -0700939 return groupHandlerMap.get(devId);
940 }
941
942 /**
Saurav Dasfbe74572017-08-03 18:30:35 -0700943 * Returns the default routing handler object.
944 *
945 * @return the default routing handler object
946 */
947 public DefaultRoutingHandler getRoutingHandler() {
948 return defaultRoutingHandler;
949 }
950
sangho80f11cb2015-04-01 13:05:26 -0700951 private class InternalPacketProcessor implements PacketProcessor {
sangho80f11cb2015-04-01 13:05:26 -0700952 @Override
953 public void process(PacketContext context) {
954
955 if (context.isHandled()) {
956 return;
957 }
958
959 InboundPacket pkt = context.inPacket();
960 Ethernet ethernet = pkt.parsed();
Pier Luigi37a35432017-02-01 13:50:04 -0800961
962 if (ethernet == null) {
963 return;
964 }
965
Saurav Das261c3002017-06-13 15:35:54 -0700966 log.trace("Rcvd pktin from {}: {}", context.inPacket().receivedFrom(),
967 ethernet);
Pier Ventreadb4ae62016-11-23 09:57:42 -0800968 if (ethernet.getEtherType() == TYPE_ARP) {
Saurav Das62ae6792017-05-15 15:34:25 -0700969 log.warn("Received unexpected ARP packet on {}",
970 context.inPacket().receivedFrom());
Saurav Das368cf212017-03-15 15:15:14 -0700971 log.trace("{}", ethernet);
Pier Ventre6b2c1b32016-12-09 17:26:04 -0800972 return;
sangho80f11cb2015-04-01 13:05:26 -0700973 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
Pier Ventreb6b81d52016-12-02 08:16:05 -0800974 IPv4 ipv4Packet = (IPv4) ethernet.getPayload();
975 //ipHandler.addToPacketBuffer(ipv4Packet);
976 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_ICMP) {
977 icmpHandler.processIcmp(ethernet, pkt.receivedFrom());
sangho80f11cb2015-04-01 13:05:26 -0700978 } else {
Charles Chand041ad82017-01-13 17:20:44 -0800979 // NOTE: We don't support IP learning at this moment so this
980 // is not necessary. Also it causes duplication of DHCP packets.
Pier Ventre6b2c1b32016-12-09 17:26:04 -0800981 // ipHandler.processPacketIn(ipv4Packet, pkt.receivedFrom());
sangho80f11cb2015-04-01 13:05:26 -0700982 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800983 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV6) {
984 IPv6 ipv6Packet = (IPv6) ethernet.getPayload();
Pier Ventreb6b81d52016-12-02 08:16:05 -0800985 //ipHandler.addToPacketBuffer(ipv6Packet);
Pier Luigi37a35432017-02-01 13:50:04 -0800986 // We deal with the packet only if the packet is a ICMP6 ECHO/REPLY
Pier Ventreb6b81d52016-12-02 08:16:05 -0800987 if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
988 ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
989 if (icmp6Packet.getIcmpType() == ICMP6.ECHO_REQUEST ||
990 icmp6Packet.getIcmpType() == ICMP6.ECHO_REPLY) {
991 icmpHandler.processIcmpv6(ethernet, pkt.receivedFrom());
992 } else {
Saurav Das62ae6792017-05-15 15:34:25 -0700993 log.trace("Received ICMPv6 0x{} - not handled",
Charles Chand3727b72017-03-13 13:10:30 -0700994 Integer.toHexString(icmp6Packet.getIcmpType() & 0xff));
Pier Ventreb6b81d52016-12-02 08:16:05 -0800995 }
996 } else {
997 // NOTE: We don't support IP learning at this moment so this
998 // is not necessary. Also it causes duplication of DHCPv6 packets.
999 // ipHandler.processPacketIn(ipv6Packet, pkt.receivedFrom());
1000 }
sangho80f11cb2015-04-01 13:05:26 -07001001 }
1002 }
1003 }
1004
sangho80f11cb2015-04-01 13:05:26 -07001005 private class InternalEventHandler implements Runnable {
Charles Chan52003922018-04-05 16:31:15 -07001006 private Event event;
1007
1008 InternalEventHandler(Event event) {
1009 this.event = event;
1010 }
1011
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -07001012 @Override
sangho80f11cb2015-04-01 13:05:26 -07001013 public void run() {
Charles Chan52003922018-04-05 16:31:15 -07001014 try {
1015 // TODO We should also change SR routing and PW to listen to TopologyEvents
1016 if (event.type() == LinkEvent.Type.LINK_ADDED ||
1017 event.type() == LinkEvent.Type.LINK_UPDATED) {
1018 linkHandler.processLinkAdded((Link) event.subject());
1019 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
1020 linkHandler.processLinkRemoved((Link) event.subject());
1021 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
1022 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
1023 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
1024 DeviceId deviceId = ((Device) event.subject()).id();
1025 if (deviceService.isAvailable(deviceId)) {
1026 log.info("** DEVICE UP Processing device event {} "
1027 + "for available device {}",
1028 event.type(), ((Device) event.subject()).id());
1029 processDeviceAdded((Device) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001030 } else {
Charles Chan52003922018-04-05 16:31:15 -07001031 log.info(" ** DEVICE DOWN Processing device event {}"
1032 + " for unavailable device {}",
1033 event.type(), ((Device) event.subject()).id());
1034 processDeviceRemoved((Device) event.subject());
Srikanth Vavilapalli64d96c12015-05-14 20:22:47 -07001035 }
Charles Chan52003922018-04-05 16:31:15 -07001036 } else if (event.type() == DeviceEvent.Type.PORT_ADDED) {
1037 // typically these calls come when device is added first time
1038 // so port filtering rules are handled at the device_added event.
1039 // port added calls represent all ports on the device,
1040 // enabled or not.
1041 log.trace("** PORT ADDED {}/{} -> {}",
1042 ((DeviceEvent) event).subject().id(),
1043 ((DeviceEvent) event).port().number(),
1044 event.type());
1045 } else if (event.type() == DeviceEvent.Type.PORT_UPDATED) {
1046 // these calls happen for every subsequent event
1047 // ports enabled, disabled, switch goes away, comes back
1048 log.info("** PORT UPDATED {}/{} -> {}",
1049 event.subject(),
1050 ((DeviceEvent) event).port(),
1051 event.type());
1052 processPortUpdated(((Device) event.subject()),
1053 ((DeviceEvent) event).port());
1054 } else if (event.type() == TopologyEvent.Type.TOPOLOGY_CHANGED) {
1055 // Process topology event, needed for all modules relying on
1056 // topology service for path computation
1057 TopologyEvent topologyEvent = (TopologyEvent) event;
1058 log.info("Processing topology event {}, topology age {}, reasons {}",
1059 event.type(), topologyEvent.subject().time(),
1060 topologyEvent.reasons().size());
1061 topologyHandler.processTopologyChange(topologyEvent.reasons());
1062 } else if (event.type() == HostEvent.Type.HOST_ADDED) {
1063 hostHandler.processHostAddedEvent((HostEvent) event);
1064 } else if (event.type() == HostEvent.Type.HOST_MOVED) {
1065 hostHandler.processHostMovedEvent((HostEvent) event);
1066 routeHandler.processHostMovedEvent((HostEvent) event);
1067 } else if (event.type() == HostEvent.Type.HOST_REMOVED) {
1068 hostHandler.processHostRemovedEvent((HostEvent) event);
1069 } else if (event.type() == HostEvent.Type.HOST_UPDATED) {
1070 hostHandler.processHostUpdatedEvent((HostEvent) event);
1071 } else if (event.type() == RouteEvent.Type.ROUTE_ADDED) {
1072 routeHandler.processRouteAdded((RouteEvent) event);
1073 } else if (event.type() == RouteEvent.Type.ROUTE_UPDATED) {
1074 routeHandler.processRouteUpdated((RouteEvent) event);
1075 } else if (event.type() == RouteEvent.Type.ROUTE_REMOVED) {
1076 routeHandler.processRouteRemoved((RouteEvent) event);
1077 } else if (event.type() == RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED) {
1078 routeHandler.processAlternativeRoutesChanged((RouteEvent) event);
1079 } else if (event.type() == McastEvent.Type.SOURCES_ADDED ||
1080 event.type() == McastEvent.Type.SOURCES_REMOVED ||
1081 event.type() == McastEvent.Type.SINKS_ADDED ||
1082 event.type() == McastEvent.Type.SINKS_REMOVED ||
1083 event.type() == McastEvent.Type.ROUTE_ADDED ||
1084 event.type() == McastEvent.Type.ROUTE_REMOVED) {
1085 mcastHandler.processMcastEvent((McastEvent) event);
1086 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
1087 NetworkConfigEvent netcfgEvent = (NetworkConfigEvent) event;
1088 Class configClass = netcfgEvent.configClass();
1089 if (configClass.equals(SegmentRoutingAppConfig.class)) {
1090 appCfgHandler.processAppConfigAdded(netcfgEvent);
1091 log.info("App config event .. configuring network");
1092 cfgListener.configureNetwork();
1093 } else if (configClass.equals(SegmentRoutingDeviceConfig.class)) {
1094 log.info("Segment Routing Device Config added for {}", event.subject());
1095 cfgListener.configureNetwork();
1096 } else if (configClass.equals(XConnectConfig.class)) {
1097 xConnectHandler.processXConnectConfigAdded(netcfgEvent);
1098 } else if (configClass.equals(InterfaceConfig.class)) {
1099 log.info("Interface Config added for {}", event.subject());
1100 cfgListener.configureNetwork();
1101 } else {
1102 log.error("Unhandled config class: {}", configClass);
1103 }
1104 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
1105 NetworkConfigEvent netcfgEvent = (NetworkConfigEvent) event;
1106 Class configClass = netcfgEvent.configClass();
1107 if (configClass.equals(SegmentRoutingAppConfig.class)) {
1108 appCfgHandler.processAppConfigUpdated(netcfgEvent);
1109 log.info("App config event .. configuring network");
1110 cfgListener.configureNetwork();
1111 } else if (configClass.equals(SegmentRoutingDeviceConfig.class)) {
1112 log.info("Segment Routing Device Config updated for {}", event.subject());
1113 createOrUpdateDeviceConfiguration();
1114 } else if (configClass.equals(XConnectConfig.class)) {
1115 xConnectHandler.processXConnectConfigUpdated(netcfgEvent);
1116 } else if (configClass.equals(InterfaceConfig.class)) {
1117 log.info("Interface Config updated for {}", event.subject());
1118 createOrUpdateDeviceConfiguration();
1119 updateInterface((InterfaceConfig) netcfgEvent.config().get(),
1120 (InterfaceConfig) netcfgEvent.prevConfig().get());
1121 } else {
1122 log.error("Unhandled config class: {}", configClass);
1123 }
1124 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
1125 NetworkConfigEvent netcfgEvent = (NetworkConfigEvent) event;
1126 Class configClass = netcfgEvent.configClass();
1127 if (configClass.equals(SegmentRoutingAppConfig.class)) {
1128 appCfgHandler.processAppConfigRemoved(netcfgEvent);
1129 log.info("App config event .. configuring network");
1130 cfgListener.configureNetwork();
1131 } else if (configClass.equals(SegmentRoutingDeviceConfig.class)) {
1132 // TODO Handle sr device config removal
1133 log.info("SegmentRoutingDeviceConfig removal is not handled in current implementation");
1134 } else if (configClass.equals(XConnectConfig.class)) {
1135 xConnectHandler.processXConnectConfigRemoved(netcfgEvent);
1136 } else if (configClass.equals(InterfaceConfig.class)) {
1137 // TODO Handle interface removal
1138 log.info("InterfaceConfig removal is not handled in current implementation");
1139 } else {
1140 log.error("Unhandled config class: {}", configClass);
1141 }
1142 } else {
1143 log.warn("Unhandled event type: {}", event.type());
sangho80f11cb2015-04-01 13:05:26 -07001144 }
Charles Chan52003922018-04-05 16:31:15 -07001145 } catch (Exception e) {
1146 log.error("SegmentRouting event handler thread thrown an exception: {}",
1147 e.getMessage(), e);
sangho80f11cb2015-04-01 13:05:26 -07001148 }
sangho80f11cb2015-04-01 13:05:26 -07001149 }
1150 }
1151
Saurav Dase6c448a2018-01-18 12:07:33 -08001152 void processDeviceAdded(Device device) {
Saurav Dasb149be12016-06-07 10:08:06 -07001153 log.info("** DEVICE ADDED with ID {}", device.id());
Charles Chan9bd6aea2017-06-27 18:48:32 -07001154
1155 // NOTE: Punt ARP/NDP even when the device is not configured.
1156 // Host learning without network config is required for CORD config generator.
1157 routingRulePopulator.populateIpPunts(device.id());
1158 routingRulePopulator.populateArpNdpPunts(device.id());
1159
Charles Chan319d1a22015-11-03 10:42:14 -08001160 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das261c3002017-06-13 15:35:54 -07001161 log.warn("Device configuration unavailable. Device {} will be "
1162 + "processed after configuration.", device.id());
Saurav Das8ec0ec42015-11-03 14:39:27 -08001163 return;
1164 }
Charles Chan72779502016-04-23 17:36:10 -07001165 processDeviceAddedInternal(device.id());
1166 }
1167
1168 private void processDeviceAddedInternal(DeviceId deviceId) {
Saurav Dasc28b3432015-10-30 17:45:38 -07001169 // Irrespective of whether the local is a MASTER or not for this device,
1170 // we need to create a SR-group-handler instance. This is because in a
1171 // multi-instance setup, any instance can initiate forwarding/next-objectives
1172 // for any switch (even if this instance is a SLAVE or not even connected
1173 // to the switch). To handle this, a default-group-handler instance is necessary
1174 // per switch.
Charles Chan72779502016-04-23 17:36:10 -07001175 log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet());
1176 if (groupHandlerMap.get(deviceId) == null) {
Charles Chan319d1a22015-11-03 10:42:14 -08001177 DefaultGroupHandler groupHandler;
1178 try {
1179 groupHandler = DefaultGroupHandler.
Charles Chan72779502016-04-23 17:36:10 -07001180 createGroupHandler(deviceId,
1181 appId,
1182 deviceConfiguration,
1183 linkService,
1184 flowObjectiveService,
1185 this);
Charles Chan319d1a22015-11-03 10:42:14 -08001186 } catch (DeviceConfigNotFoundException e) {
1187 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
1188 return;
1189 }
Saurav Das2b6a00f2017-12-05 15:00:23 -08001190 log.debug("updating groupHandlerMap with new grpHdlr for device: {}",
Charles Chan72779502016-04-23 17:36:10 -07001191 deviceId);
1192 groupHandlerMap.put(deviceId, groupHandler);
Saurav Das8ec0ec42015-11-03 14:39:27 -08001193 }
Saurav Dasb149be12016-06-07 10:08:06 -07001194
Charles Chan72779502016-04-23 17:36:10 -07001195 if (mastershipService.isLocalMaster(deviceId)) {
Saurav Dasf9332192017-02-18 14:05:44 -08001196 defaultRoutingHandler.populatePortAddressingRules(deviceId);
Charles Chan82f19972016-05-17 13:13:55 -07001197 xConnectHandler.init(deviceId);
Charles Chan72779502016-04-23 17:36:10 -07001198 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
Charles Chan10b0fb72017-02-02 16:20:42 -08001199 groupHandler.createGroupsFromVlanConfig();
Charles Chan72779502016-04-23 17:36:10 -07001200 routingRulePopulator.populateSubnetBroadcastRule(deviceId);
Charles Chan77277672015-10-20 16:24:19 -07001201 }
Charles Chan82ab1932016-01-30 23:22:37 -08001202
Charles Chandebfea32016-10-24 14:52:01 -07001203 appCfgHandler.init(deviceId);
Charles Chand66d6712018-03-29 16:03:41 -07001204 hostHandler.init(deviceId);
Charles Chandebfea32016-10-24 14:52:01 -07001205 routeHandler.init(deviceId);
sangho80f11cb2015-04-01 13:05:26 -07001206 }
1207
Saurav Dasc3604f12016-03-23 11:22:49 -07001208 private void processDeviceRemoved(Device device) {
Saurav Das261c3002017-06-13 15:35:54 -07001209 dsNextObjStore.entrySet().stream()
Saurav Dasc3604f12016-03-23 11:22:49 -07001210 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
Charles Chan873661e2017-11-30 15:37:50 -08001211 .forEach(entry -> dsNextObjStore.remove(entry.getKey()));
Charles Chan10b0fb72017-02-02 16:20:42 -08001212 vlanNextObjStore.entrySet().stream()
Saurav Dasc3604f12016-03-23 11:22:49 -07001213 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
Charles Chan3ed34d82017-06-22 18:03:14 -07001214 .forEach(entry -> vlanNextObjStore.remove(entry.getKey()));
Saurav Dasc3604f12016-03-23 11:22:49 -07001215 portNextObjStore.entrySet().stream()
1216 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
Charles Chan3ed34d82017-06-22 18:03:14 -07001217 .forEach(entry -> portNextObjStore.remove(entry.getKey()));
Saurav Dase6c448a2018-01-18 12:07:33 -08001218 linkHandler.processDeviceRemoved(device);
Charles Chan17d75d82017-06-15 00:44:51 -07001219
Saurav Dasfbe74572017-08-03 18:30:35 -07001220 DefaultGroupHandler gh = groupHandlerMap.remove(device.id());
1221 if (gh != null) {
1222 gh.shutdown();
1223 }
Saurav Das62ae6792017-05-15 15:34:25 -07001224 // Note that a switch going down is associated with all of its links
1225 // going down as well, but it is treated as a single switch down event
1226 // while the link-downs are ignored.
1227 defaultRoutingHandler
Saurav Dasdc7f2752018-03-18 21:28:15 -07001228 .populateRoutingRulesForLinkStatusChange(null, null, device.id(), true);
Saurav Das6430f412018-01-25 09:49:01 -08001229 defaultRoutingHandler.purgeEcmpGraph(device.id());
Charles Chan82f19972016-05-17 13:13:55 -07001230 xConnectHandler.removeDevice(device.id());
Saurav Das97241862018-02-14 14:14:54 -08001231
1232 // Cleanup all internal groupHandler stores for this device. Should be
1233 // done after all rerouting or rehashing has been completed
1234 groupHandlerMap.entrySet()
1235 .forEach(entry -> entry.getValue().cleanUpForNeighborDown(device.id()));
Saurav Dasc3604f12016-03-23 11:22:49 -07001236 }
1237
Saurav Dasf0f592d2016-11-18 15:21:57 -08001238 private void processPortUpdated(Device device, Port port) {
1239 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
1240 log.warn("Device configuration uploading. Not handling port event for"
1241 + "dev: {} port: {}", device.id(), port.number());
1242 return;
1243 }
Saurav Dasf9332192017-02-18 14:05:44 -08001244
1245 if (!mastershipService.isLocalMaster(device.id())) {
1246 log.debug("Not master for dev:{} .. not handling port updated event"
1247 + "for port {}", device.id(), port.number());
1248 return;
1249 }
1250
1251 // first we handle filtering rules associated with the port
1252 if (port.isEnabled()) {
1253 log.info("Switchport {}/{} enabled..programming filters",
1254 device.id(), port.number());
Charles Chan43be46b2017-02-26 22:59:35 -08001255 routingRulePopulator.processSinglePortFilters(device.id(), port.number(), true);
Saurav Dasf9332192017-02-18 14:05:44 -08001256 } else {
1257 log.info("Switchport {}/{} disabled..removing filters",
1258 device.id(), port.number());
Charles Chan43be46b2017-02-26 22:59:35 -08001259 routingRulePopulator.processSinglePortFilters(device.id(), port.number(), false);
Saurav Dasf9332192017-02-18 14:05:44 -08001260 }
Saurav Dasf0f592d2016-11-18 15:21:57 -08001261
1262 // portUpdated calls are for ports that have gone down or up. For switch
1263 // to switch ports, link-events should take care of any re-routing or
1264 // group editing necessary for port up/down. Here we only process edge ports
1265 // that are already configured.
Saurav Das3fb28272017-03-04 16:08:47 -08001266 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
1267 VlanId untaggedVlan = getUntaggedVlanId(cp);
1268 VlanId nativeVlan = getNativeVlanId(cp);
1269 Set<VlanId> taggedVlans = getTaggedVlanId(cp);
Charles Chan10b0fb72017-02-02 16:20:42 -08001270
Saurav Das3fb28272017-03-04 16:08:47 -08001271 if (untaggedVlan == null && nativeVlan == null && taggedVlans.isEmpty()) {
Saurav Das62ae6792017-05-15 15:34:25 -07001272 log.debug("Not handling port updated event for non-edge port (unconfigured) "
Saurav Dasf0f592d2016-11-18 15:21:57 -08001273 + "dev/port: {}/{}", device.id(), port.number());
1274 return;
1275 }
Saurav Das3fb28272017-03-04 16:08:47 -08001276 if (untaggedVlan != null) {
1277 processEdgePort(device, port, untaggedVlan, true);
1278 }
1279 if (nativeVlan != null) {
1280 processEdgePort(device, port, nativeVlan, true);
1281 }
1282 if (!taggedVlans.isEmpty()) {
1283 taggedVlans.forEach(tag -> processEdgePort(device, port, tag, false));
1284 }
Saurav Dasf0f592d2016-11-18 15:21:57 -08001285 }
1286
Saurav Das3fb28272017-03-04 16:08:47 -08001287 private void processEdgePort(Device device, Port port, VlanId vlanId,
1288 boolean popVlan) {
Saurav Dasf0f592d2016-11-18 15:21:57 -08001289 boolean portUp = port.isEnabled();
1290 if (portUp) {
Saurav Das3fb28272017-03-04 16:08:47 -08001291 log.info("Device:EdgePort {}:{} is enabled in vlan: {}", device.id(),
Charles Chan10b0fb72017-02-02 16:20:42 -08001292 port.number(), vlanId);
Charles Chan873661e2017-11-30 15:37:50 -08001293 hostHandler.processPortUp(new ConnectPoint(device.id(), port.number()));
Saurav Dasf0f592d2016-11-18 15:21:57 -08001294 } else {
Saurav Das3fb28272017-03-04 16:08:47 -08001295 log.info("Device:EdgePort {}:{} is disabled in vlan: {}", device.id(),
Charles Chan10b0fb72017-02-02 16:20:42 -08001296 port.number(), vlanId);
Saurav Dasf0f592d2016-11-18 15:21:57 -08001297 }
1298
Srikanth Vavilapalli64505482015-04-21 13:04:13 -07001299 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sangho80f11cb2015-04-01 13:05:26 -07001300 if (groupHandler != null) {
Saurav Das3fb28272017-03-04 16:08:47 -08001301 groupHandler.processEdgePort(port.number(), vlanId, popVlan, portUp);
Saurav Dasf0f592d2016-11-18 15:21:57 -08001302 } else {
1303 log.warn("Group handler not found for dev:{}. Not handling edge port"
1304 + " {} event for port:{}", device.id(),
1305 (portUp) ? "UP" : "DOWN", port.number());
sangho80f11cb2015-04-01 13:05:26 -07001306 }
1307 }
sangho27462c62015-05-14 00:39:53 -07001308
Charles Chan8ca5a122017-10-20 16:06:55 -07001309 private void createOrUpdateDeviceConfiguration() {
1310 if (deviceConfiguration == null) {
Saurav Dase321cff2018-02-09 17:26:45 -08001311 log.info("Creating new DeviceConfiguration");
Charles Chan8ca5a122017-10-20 16:06:55 -07001312 deviceConfiguration = new DeviceConfiguration(this);
1313 } else {
Saurav Dase321cff2018-02-09 17:26:45 -08001314 log.info("Updating DeviceConfiguration");
Charles Chan8ca5a122017-10-20 16:06:55 -07001315 deviceConfiguration.updateConfig();
1316 }
1317 }
1318
Pier Ventreb6a7f342016-11-26 21:05:22 -08001319 /**
1320 * Registers the given connect point with the NRS, this is necessary
1321 * to receive the NDP and ARP packets from the NRS.
1322 *
1323 * @param portToRegister connect point to register
1324 */
1325 public void registerConnectPoint(ConnectPoint portToRegister) {
Charles Chan2e71ef32017-02-23 15:44:08 -08001326 neighbourResolutionService.registerNeighbourHandler(
Pier Ventreb6a7f342016-11-26 21:05:22 -08001327 portToRegister,
1328 neighbourHandler,
1329 appId
1330 );
1331 }
1332
Charles Chan72f556a2015-10-05 17:50:33 -07001333 private class InternalConfigListener implements NetworkConfigListener {
Saurav Das261c3002017-06-13 15:35:54 -07001334 private static final long PROGRAM_DELAY = 2;
Charles Chan46fdfaf2016-11-09 20:51:44 -08001335 SegmentRoutingManager srManager;
Charles Chane7c61022015-10-07 14:21:45 -07001336
Charles Chanb7f75ac2016-01-11 18:28:54 -08001337 /**
1338 * Constructs the internal network config listener.
1339 *
Charles Chan46fdfaf2016-11-09 20:51:44 -08001340 * @param srManager segment routing manager
Charles Chanb7f75ac2016-01-11 18:28:54 -08001341 */
Charles Chan3ed34d82017-06-22 18:03:14 -07001342 InternalConfigListener(SegmentRoutingManager srManager) {
Charles Chan46fdfaf2016-11-09 20:51:44 -08001343 this.srManager = srManager;
Charles Chane7c61022015-10-07 14:21:45 -07001344 }
1345
Charles Chanb7f75ac2016-01-11 18:28:54 -08001346 /**
1347 * Reads network config and initializes related data structure accordingly.
1348 */
Charles Chan873661e2017-11-30 15:37:50 -08001349 void configureNetwork() {
Saurav Dase321cff2018-02-09 17:26:45 -08001350 log.info("Configuring network ...");
Charles Chan8ca5a122017-10-20 16:06:55 -07001351 createOrUpdateDeviceConfiguration();
Charles Chane7c61022015-10-07 14:21:45 -07001352
Charles Chan46fdfaf2016-11-09 20:51:44 -08001353 arpHandler = new ArpHandler(srManager);
1354 icmpHandler = new IcmpHandler(srManager);
1355 ipHandler = new IpHandler(srManager);
1356 routingRulePopulator = new RoutingRulePopulator(srManager);
1357 defaultRoutingHandler = new DefaultRoutingHandler(srManager);
Charles Chane7c61022015-10-07 14:21:45 -07001358
1359 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
1360 groupHandlerMap, tunnelStore);
1361 policyHandler = new PolicyHandler(appId, deviceConfiguration,
1362 flowObjectiveService,
1363 tunnelHandler, policyStore);
Saurav Das261c3002017-06-13 15:35:54 -07001364 // add a small delay to absorb multiple network config added notifications
1365 if (!programmingScheduled.get()) {
Saurav Dase321cff2018-02-09 17:26:45 -08001366 log.info("Buffering config calls for {} secs", PROGRAM_DELAY);
Saurav Das261c3002017-06-13 15:35:54 -07001367 programmingScheduled.set(true);
Charles Chan52003922018-04-05 16:31:15 -07001368 mainEventExecutor.schedule(new ConfigChange(), PROGRAM_DELAY, TimeUnit.SECONDS);
Charles Chane7c61022015-10-07 14:21:45 -07001369 }
Charles Chan72779502016-04-23 17:36:10 -07001370 mcastHandler.init();
Charles Chane7c61022015-10-07 14:21:45 -07001371 }
1372
Charles Chan72f556a2015-10-05 17:50:33 -07001373 @Override
1374 public void event(NetworkConfigEvent event) {
Charles Chan3f4aca62018-03-21 16:57:47 -07001375 checkState(appCfgHandler != null, "NetworkConfigEventHandler is not initialized");
1376 checkState(xConnectHandler != null, "XConnectHandler is not initialized");
1377 switch (event.type()) {
1378 case CONFIG_ADDED:
1379 case CONFIG_UPDATED:
1380 case CONFIG_REMOVED:
1381 log.trace("Schedule Network Config event {}", event);
Charles Chan52003922018-04-05 16:31:15 -07001382 mainEventExecutor.schedule(new InternalEventHandler(event), 100, TimeUnit.MILLISECONDS);
Charles Chan3f4aca62018-03-21 16:57:47 -07001383 break;
1384 default:
1385 break;
Charles Chan72f556a2015-10-05 17:50:33 -07001386 }
1387 }
Saurav Das261c3002017-06-13 15:35:54 -07001388
Charles Chanc4a68c32018-01-03 16:26:32 -08001389 @Override
1390 public boolean isRelevant(NetworkConfigEvent event) {
Saurav Dase321cff2018-02-09 17:26:45 -08001391 if (event.type() == CONFIG_REGISTERED ||
1392 event.type() == CONFIG_UNREGISTERED) {
1393 log.debug("Ignore event {} due to type mismatch", event);
1394 return false;
Charles Chanc4a68c32018-01-03 16:26:32 -08001395 }
Saurav Dase321cff2018-02-09 17:26:45 -08001396
1397 if (!event.configClass().equals(SegmentRoutingDeviceConfig.class) &&
1398 !event.configClass().equals(SegmentRoutingAppConfig.class) &&
1399 !event.configClass().equals(InterfaceConfig.class) &&
Andreas Pantelopouloscdbb22c2018-02-23 14:18:00 -08001400 !event.configClass().equals(XConnectConfig.class)) {
Saurav Dase321cff2018-02-09 17:26:45 -08001401 log.debug("Ignore event {} due to class mismatch", event);
1402 return false;
1403 }
1404
1405 return true;
Charles Chanc4a68c32018-01-03 16:26:32 -08001406 }
1407
Saurav Das261c3002017-06-13 15:35:54 -07001408 private final class ConfigChange implements Runnable {
1409 @Override
1410 public void run() {
1411 programmingScheduled.set(false);
Saurav Dase321cff2018-02-09 17:26:45 -08001412 log.info("Reacting to config changes after buffer delay");
Saurav Das261c3002017-06-13 15:35:54 -07001413 for (Device device : deviceService.getDevices()) {
1414 processDeviceAdded(device);
1415 }
1416 defaultRoutingHandler.startPopulationProcess();
1417 }
1418 }
Charles Chan72f556a2015-10-05 17:50:33 -07001419 }
Charles Chanf4586112015-11-09 16:37:23 -08001420
Charles Chan3f4aca62018-03-21 16:57:47 -07001421 private class InternalLinkListener implements LinkListener {
1422 @Override
1423 public void event(LinkEvent event) {
1424 if (event.type() == LinkEvent.Type.LINK_ADDED ||
1425 event.type() == LinkEvent.Type.LINK_UPDATED ||
1426 event.type() == LinkEvent.Type.LINK_REMOVED) {
1427 log.trace("Schedule Link event {}", event);
Charles Chan52003922018-04-05 16:31:15 -07001428 mainEventExecutor.schedule(new InternalEventHandler(event), 100, TimeUnit.MILLISECONDS);
Charles Chan3f4aca62018-03-21 16:57:47 -07001429 }
1430 }
1431 }
1432
1433 private class InternalDeviceListener implements DeviceListener {
1434 @Override
1435 public void event(DeviceEvent event) {
1436 switch (event.type()) {
1437 case DEVICE_ADDED:
1438 case PORT_UPDATED:
1439 case PORT_ADDED:
1440 case DEVICE_UPDATED:
1441 case DEVICE_AVAILABILITY_CHANGED:
1442 log.trace("Schedule Device event {}", event);
Charles Chan52003922018-04-05 16:31:15 -07001443 mainEventExecutor.schedule(new InternalEventHandler(event), 100, TimeUnit.MILLISECONDS);
Charles Chan3f4aca62018-03-21 16:57:47 -07001444 break;
1445 default:
1446 }
1447 }
1448 }
1449
1450 private class InternalTopologyListener implements TopologyListener {
1451 @Override
1452 public void event(TopologyEvent event) {
1453 switch (event.type()) {
1454 case TOPOLOGY_CHANGED:
1455 log.trace("Schedule Topology event {}", event);
Charles Chan52003922018-04-05 16:31:15 -07001456 mainEventExecutor.schedule(new InternalEventHandler(event), 100, TimeUnit.MILLISECONDS);
Charles Chan3f4aca62018-03-21 16:57:47 -07001457 break;
1458 default:
1459 }
1460 }
1461 }
1462
Charles Chanf4586112015-11-09 16:37:23 -08001463 private class InternalHostListener implements HostListener {
Charles Chanf4586112015-11-09 16:37:23 -08001464 @Override
1465 public void event(HostEvent event) {
Charles Chanf4586112015-11-09 16:37:23 -08001466 switch (event.type()) {
1467 case HOST_ADDED:
Charles Chanf4586112015-11-09 16:37:23 -08001468 case HOST_MOVED:
Charles Chanf4586112015-11-09 16:37:23 -08001469 case HOST_REMOVED:
Charles Chanf4586112015-11-09 16:37:23 -08001470 case HOST_UPDATED:
Charles Chan3f4aca62018-03-21 16:57:47 -07001471 log.trace("Schedule Host event {}", event);
Charles Chan52003922018-04-05 16:31:15 -07001472 hostEventExecutor.schedule(new InternalEventHandler(event), 100, TimeUnit.MILLISECONDS);
Charles Chanf4586112015-11-09 16:37:23 -08001473 break;
1474 default:
1475 log.warn("Unsupported host event type: {}", event.type());
1476 break;
1477 }
1478 }
1479 }
1480
Charles Chanc91c8782016-03-30 17:54:24 -07001481 private class InternalMcastListener implements McastListener {
1482 @Override
1483 public void event(McastEvent event) {
1484 switch (event.type()) {
Pier1f87aca2018-03-14 16:47:32 -07001485 case SOURCES_ADDED:
1486 case SOURCES_REMOVED:
1487 case SINKS_ADDED:
1488 case SINKS_REMOVED:
Charles Chanc91c8782016-03-30 17:54:24 -07001489 case ROUTE_REMOVED:
Charles Chan3f4aca62018-03-21 16:57:47 -07001490 log.trace("Schedule Mcast event {}", event);
Charles Chan52003922018-04-05 16:31:15 -07001491 mcastEventExecutor.schedule(new InternalEventHandler(event), 100, TimeUnit.MILLISECONDS);
Pier Luigi6786b922018-02-02 16:19:11 +01001492 break;
1493 case ROUTE_ADDED:
Charles Chanc91c8782016-03-30 17:54:24 -07001494 default:
Charles Chan3f4aca62018-03-21 16:57:47 -07001495 log.warn("Unsupported mcast event type: {}", event.type());
Charles Chanc91c8782016-03-30 17:54:24 -07001496 break;
1497 }
1498 }
1499 }
Charles Chan41f5ec02016-06-13 18:54:31 -07001500
Charles Chandebfea32016-10-24 14:52:01 -07001501 private class InternalRouteEventListener implements RouteListener {
1502 @Override
1503 public void event(RouteEvent event) {
1504 switch (event.type()) {
1505 case ROUTE_ADDED:
Charles Chandebfea32016-10-24 14:52:01 -07001506 case ROUTE_UPDATED:
Charles Chandebfea32016-10-24 14:52:01 -07001507 case ROUTE_REMOVED:
Charles Chan910be6a2017-08-23 14:46:43 -07001508 case ALTERNATIVE_ROUTES_CHANGED:
Charles Chan3f4aca62018-03-21 16:57:47 -07001509 log.trace("Schedule Route event {}", event);
Charles Chan52003922018-04-05 16:31:15 -07001510 routeEventExecutor.schedule(new InternalEventHandler(event), 100, TimeUnit.MILLISECONDS);
Charles Chan910be6a2017-08-23 14:46:43 -07001511 break;
Charles Chandebfea32016-10-24 14:52:01 -07001512 default:
Charles Chan3f4aca62018-03-21 16:57:47 -07001513 log.warn("Unsupported route event type: {}", event.type());
Charles Chandebfea32016-10-24 14:52:01 -07001514 break;
1515 }
1516 }
1517 }
Saurav Das62ae6792017-05-15 15:34:25 -07001518
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001519 private void updateInterface(InterfaceConfig conf, InterfaceConfig prevConf) {
1520 try {
1521 Set<Interface> intfs = conf.getInterfaces();
1522 Set<Interface> prevIntfs = prevConf.getInterfaces();
1523
1524 // Now we only handle one interface config at each port.
1525 if (intfs.size() != 1 || prevIntfs.size() != 1) {
1526 log.warn("Interface update aborted - one at a time is allowed, " +
1527 "but {} / {}(prev) received.", intfs.size(), prevIntfs.size());
1528 return;
1529 }
1530
1531 Interface intf = intfs.stream().findFirst().get();
1532 Interface prevIntf = prevIntfs.stream().findFirst().get();
1533
1534 DeviceId deviceId = intf.connectPoint().deviceId();
1535 PortNumber portNum = intf.connectPoint().port();
1536
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001537 removeSubnetConfig(prevIntf.connectPoint(),
1538 Sets.difference(new HashSet<>(prevIntf.ipAddressesList()),
1539 new HashSet<>(intf.ipAddressesList())));
1540
Jonghwan Hyuna4ce0aa2018-02-12 16:43:45 +09001541 if (!prevIntf.vlanNative().equals(VlanId.NONE)
1542 && !prevIntf.vlanNative().equals(intf.vlanUntagged())
1543 && !prevIntf.vlanNative().equals(intf.vlanNative())) {
1544 if (intf.vlanTagged().contains(prevIntf.vlanNative())) {
1545 // Update filtering objective and L2IG group bucket
1546 updatePortVlanTreatment(deviceId, portNum, prevIntf.vlanNative(), false);
1547 } else {
1548 // RemoveVlanNative
1549 updateVlanConfigInternal(deviceId, portNum, prevIntf.vlanNative(), true, false);
1550 }
1551 }
1552
1553 if (!prevIntf.vlanUntagged().equals(VlanId.NONE)
1554 && !prevIntf.vlanUntagged().equals(intf.vlanUntagged())
1555 && !prevIntf.vlanUntagged().equals(intf.vlanNative())) {
1556 if (intf.vlanTagged().contains(prevIntf.vlanUntagged())) {
1557 // Update filtering objective and L2IG group bucket
1558 updatePortVlanTreatment(deviceId, portNum, prevIntf.vlanUntagged(), false);
1559 } else {
1560 // RemoveVlanUntagged
1561 updateVlanConfigInternal(deviceId, portNum, prevIntf.vlanUntagged(), true, false);
1562 }
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001563 }
1564
1565 if (!prevIntf.vlanTagged().isEmpty() && !intf.vlanTagged().equals(prevIntf.vlanTagged())) {
1566 // RemoveVlanTagged
Jonghwan Hyuna4ce0aa2018-02-12 16:43:45 +09001567 Sets.difference(prevIntf.vlanTagged(), intf.vlanTagged()).stream()
1568 .filter(i -> !intf.vlanUntagged().equals(i))
1569 .filter(i -> !intf.vlanNative().equals(i))
1570 .forEach(vlanId -> updateVlanConfigInternal(
1571 deviceId, portNum, vlanId, false, false));
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001572 }
1573
Jonghwan Hyuna4ce0aa2018-02-12 16:43:45 +09001574 if (!intf.vlanNative().equals(VlanId.NONE)
1575 && !prevIntf.vlanNative().equals(intf.vlanNative())
1576 && !prevIntf.vlanUntagged().equals(intf.vlanNative())) {
1577 if (prevIntf.vlanTagged().contains(intf.vlanNative())) {
1578 // Update filtering objective and L2IG group bucket
1579 updatePortVlanTreatment(deviceId, portNum, intf.vlanNative(), true);
1580 } else {
1581 // AddVlanNative
1582 updateVlanConfigInternal(deviceId, portNum, intf.vlanNative(), true, true);
1583 }
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001584 }
1585
1586 if (!intf.vlanTagged().isEmpty() && !intf.vlanTagged().equals(prevIntf.vlanTagged())) {
1587 // AddVlanTagged
Jonghwan Hyuna4ce0aa2018-02-12 16:43:45 +09001588 Sets.difference(intf.vlanTagged(), prevIntf.vlanTagged()).stream()
1589 .filter(i -> !prevIntf.vlanUntagged().equals(i))
1590 .filter(i -> !prevIntf.vlanNative().equals(i))
1591 .forEach(vlanId -> updateVlanConfigInternal(
1592 deviceId, portNum, vlanId, false, true)
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001593 );
1594 }
1595
Jonghwan Hyuna4ce0aa2018-02-12 16:43:45 +09001596 if (!intf.vlanUntagged().equals(VlanId.NONE)
1597 && !prevIntf.vlanUntagged().equals(intf.vlanUntagged())
1598 && !prevIntf.vlanNative().equals(intf.vlanUntagged())) {
1599 if (prevIntf.vlanTagged().contains(intf.vlanUntagged())) {
1600 // Update filtering objective and L2IG group bucket
1601 updatePortVlanTreatment(deviceId, portNum, intf.vlanUntagged(), true);
1602 } else {
1603 // AddVlanUntagged
1604 updateVlanConfigInternal(deviceId, portNum, intf.vlanUntagged(), true, true);
1605 }
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001606 }
1607 addSubnetConfig(prevIntf.connectPoint(),
1608 Sets.difference(new HashSet<>(intf.ipAddressesList()),
1609 new HashSet<>(prevIntf.ipAddressesList())));
1610 } catch (ConfigException e) {
1611 log.error("Error in configuration");
1612 }
1613 }
1614
Jonghwan Hyuna4ce0aa2018-02-12 16:43:45 +09001615 private void updatePortVlanTreatment(DeviceId deviceId, PortNumber portNum,
1616 VlanId vlanId, boolean pushVlan) {
1617 DefaultGroupHandler grpHandler = getGroupHandler(deviceId);
1618 if (grpHandler == null) {
1619 log.warn("Failed to retrieve group handler for device {}", deviceId);
1620 return;
1621 }
1622
1623 // Update filtering objective for a single port
1624 routingRulePopulator.updateSinglePortFilters(deviceId, portNum, !pushVlan, vlanId, false);
1625 routingRulePopulator.updateSinglePortFilters(deviceId, portNum, pushVlan, vlanId, true);
1626
1627 if (getVlanNextObjectiveId(deviceId, vlanId) != -1) {
1628 // Update L2IG bucket of the port
1629 grpHandler.updateL2InterfaceGroupBucket(portNum, vlanId, pushVlan);
1630 } else {
1631 log.warn("Failed to retrieve next objective for vlan {} in device {}:{}", vlanId, deviceId, portNum);
1632 }
1633 }
1634
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001635 private void updateVlanConfigInternal(DeviceId deviceId, PortNumber portNum,
1636 VlanId vlanId, boolean pushVlan, boolean install) {
1637 DefaultGroupHandler grpHandler = getGroupHandler(deviceId);
1638 if (grpHandler == null) {
1639 log.warn("Failed to retrieve group handler for device {}", deviceId);
1640 return;
1641 }
1642
1643 // Update filtering objective for a single port
1644 routingRulePopulator.updateSinglePortFilters(deviceId, portNum, pushVlan, vlanId, install);
1645
1646 // Update filtering objective for multicast ingress port
1647 mcastHandler.updateFilterToDevice(deviceId, portNum, vlanId, install);
1648
1649 int nextId = getVlanNextObjectiveId(deviceId, vlanId);
1650
1651 if (nextId != -1 && !install) {
1652 // Update next objective for a single port as an output port
1653 // Remove a single port from L2FG
Jonghwan Hyuna4ce0aa2018-02-12 16:43:45 +09001654 grpHandler.updateGroupFromVlanConfiguration(vlanId, portNum, nextId, install);
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001655 // Remove L2 Bridging rule and L3 Unicast rule to the host
1656 hostHandler.processIntfVlanUpdatedEvent(deviceId, portNum, vlanId, pushVlan, install);
1657 // Remove broadcast forwarding rule and corresponding L2FG for VLAN
1658 // only if there is no port configured on that VLAN ID
1659 if (!getVlanPortMap(deviceId).containsKey(vlanId)) {
1660 // Remove broadcast forwarding rule for the VLAN
1661 routingRulePopulator.updateSubnetBroadcastRule(deviceId, vlanId, install);
1662 // Remove L2FG for VLAN
1663 grpHandler.removeBcastGroupFromVlan(deviceId, portNum, vlanId, pushVlan);
1664 } else {
1665 // Remove L2IG of the port
1666 grpHandler.removePortNextObjective(deviceId, portNum, vlanId, pushVlan);
1667 }
1668 } else if (install) {
1669 if (nextId != -1) {
1670 // Add a single port to L2FG
Jonghwan Hyuna4ce0aa2018-02-12 16:43:45 +09001671 grpHandler.updateGroupFromVlanConfiguration(vlanId, portNum, nextId, install);
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001672 } else {
1673 // Create L2FG for VLAN
1674 grpHandler.createBcastGroupFromVlan(vlanId, Collections.singleton(portNum));
1675 routingRulePopulator.updateSubnetBroadcastRule(deviceId, vlanId, install);
1676 }
1677 hostHandler.processIntfVlanUpdatedEvent(deviceId, portNum, vlanId, pushVlan, install);
1678 } else {
1679 log.warn("Failed to retrieve next objective for vlan {} in device {}:{}", vlanId, deviceId, portNum);
1680 }
1681 }
1682
1683 private void removeSubnetConfig(ConnectPoint cp, Set<InterfaceIpAddress> ipAddressSet) {
1684 Set<IpPrefix> ipPrefixSet = ipAddressSet.stream().
1685 map(InterfaceIpAddress::subnetAddress).collect(Collectors.toSet());
1686
1687 Set<InterfaceIpAddress> deviceIntfIpAddrs = interfaceService.getInterfaces().stream()
1688 .filter(intf -> intf.connectPoint().deviceId().equals(cp.deviceId()))
1689 .filter(intf -> !intf.connectPoint().equals(cp))
1690 .flatMap(intf -> intf.ipAddressesList().stream())
1691 .collect(Collectors.toSet());
1692 // 1. Partial subnet population
1693 // Remove routing rules for removed subnet from previous configuration,
1694 // which does not also exist in other interfaces in the same device
1695 Set<IpPrefix> deviceIpPrefixSet = deviceIntfIpAddrs.stream()
1696 .map(InterfaceIpAddress::subnetAddress)
1697 .collect(Collectors.toSet());
1698
1699 defaultRoutingHandler.revokeSubnet(
1700 ipPrefixSet.stream()
1701 .filter(ipPrefix -> !deviceIpPrefixSet.contains(ipPrefix))
1702 .collect(Collectors.toSet()));
1703
1704 // 2. Interface IP punts
1705 // Remove IP punts for old Intf address
1706 Set<IpAddress> deviceIpAddrs = deviceIntfIpAddrs.stream()
1707 .map(InterfaceIpAddress::ipAddress)
1708 .collect(Collectors.toSet());
1709 ipAddressSet.stream()
1710 .map(InterfaceIpAddress::ipAddress)
1711 .filter(interfaceIpAddress -> !deviceIpAddrs.contains(interfaceIpAddress))
1712 .forEach(interfaceIpAddress ->
1713 routingRulePopulator.revokeSingleIpPunts(
1714 cp.deviceId(), interfaceIpAddress));
1715
1716 // 3. Host unicast routing rule
1717 // Remove unicast routing rule
1718 hostHandler.processIntfIpUpdatedEvent(cp, ipPrefixSet, false);
1719 }
1720
1721 private void addSubnetConfig(ConnectPoint cp, Set<InterfaceIpAddress> ipAddressSet) {
1722 Set<IpPrefix> ipPrefixSet = ipAddressSet.stream().
1723 map(InterfaceIpAddress::subnetAddress).collect(Collectors.toSet());
1724
1725 Set<InterfaceIpAddress> deviceIntfIpAddrs = interfaceService.getInterfaces().stream()
1726 .filter(intf -> intf.connectPoint().deviceId().equals(cp.deviceId()))
1727 .filter(intf -> !intf.connectPoint().equals(cp))
1728 .flatMap(intf -> intf.ipAddressesList().stream())
1729 .collect(Collectors.toSet());
1730 // 1. Partial subnet population
1731 // Add routing rules for newly added subnet, which does not also exist in
1732 // other interfaces in the same device
1733 Set<IpPrefix> deviceIpPrefixSet = deviceIntfIpAddrs.stream()
1734 .map(InterfaceIpAddress::subnetAddress)
1735 .collect(Collectors.toSet());
1736
1737 defaultRoutingHandler.populateSubnet(
1738 Collections.singleton(cp),
1739 ipPrefixSet.stream()
1740 .filter(ipPrefix -> !deviceIpPrefixSet.contains(ipPrefix))
1741 .collect(Collectors.toSet()));
1742
1743 // 2. Interface IP punts
1744 // Add IP punts for new Intf address
1745 Set<IpAddress> deviceIpAddrs = deviceIntfIpAddrs.stream()
1746 .map(InterfaceIpAddress::ipAddress)
1747 .collect(Collectors.toSet());
1748 ipAddressSet.stream()
1749 .map(InterfaceIpAddress::ipAddress)
1750 .filter(interfaceIpAddress -> !deviceIpAddrs.contains(interfaceIpAddress))
1751 .forEach(interfaceIpAddress ->
1752 routingRulePopulator.populateSingleIpPunts(
1753 cp.deviceId(), interfaceIpAddress));
1754
1755 // 3. Host unicast routing rule
1756 // Add unicast routing rule
1757 hostHandler.processIntfIpUpdatedEvent(cp, ipPrefixSet, true);
1758 }
sangho80f11cb2015-04-01 13:05:26 -07001759}