blob: ac9b291c456a13cd2e7de55eabe5f036a0f6f91e [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.segmentrouting;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
sangho1e575652015-05-14 00:39:53 -070023import org.apache.felix.scr.annotations.Service;
sanghob35a6192015-04-01 13:05:26 -070024import org.onlab.packet.Ethernet;
Charles Chan68aa62d2015-11-09 16:37:23 -080025import org.onlab.packet.MacAddress;
Saurav Das0e99e2b2015-10-28 12:39:42 -070026import org.onlab.packet.VlanId;
Charles Chanc42e84e2015-10-20 16:24:19 -070027import org.onlab.packet.IPv4;
28import org.onlab.packet.Ip4Address;
29import org.onlab.packet.Ip4Prefix;
30import org.onlab.packet.IpAddress;
31import org.onlab.packet.IpPrefix;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070032import org.onlab.util.KryoNamespace;
sanghob35a6192015-04-01 13:05:26 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.event.Event;
Charles Chanc42e84e2015-10-20 16:24:19 -070036import org.onosproject.net.ConnectPoint;
Charles Chan68aa62d2015-11-09 16:37:23 -080037import org.onosproject.net.PortNumber;
Charles Chand6832882015-10-05 17:50:33 -070038import org.onosproject.net.config.ConfigFactory;
39import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigRegistry;
41import org.onosproject.net.config.NetworkConfigListener;
42import org.onosproject.net.config.basics.SubjectFactories;
Charles Chan68aa62d2015-11-09 16:37:23 -080043import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.TrafficSelector;
46import org.onosproject.net.flow.TrafficTreatment;
47import org.onosproject.net.flowobjective.DefaultForwardingObjective;
48import org.onosproject.net.flowobjective.ForwardingObjective;
49import org.onosproject.net.flowobjective.Objective;
50import org.onosproject.net.flowobjective.ObjectiveContext;
51import org.onosproject.net.flowobjective.ObjectiveError;
52import org.onosproject.net.host.HostEvent;
53import org.onosproject.net.host.HostListener;
Charles Chan188ebf52015-12-23 00:15:11 -080054import org.onosproject.net.packet.PacketPriority;
Charles Chan0b4e6182015-11-03 10:42:14 -080055import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
56import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan5270ed02016-01-30 23:22:37 -080057import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
58import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070059import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
60import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070061import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
Saurav Das4ce45962015-11-24 23:21:05 -080062import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
sanghob35a6192015-04-01 13:05:26 -070063import org.onosproject.mastership.MastershipService;
64import org.onosproject.net.Device;
65import org.onosproject.net.DeviceId;
66import org.onosproject.net.Link;
sanghob35a6192015-04-01 13:05:26 -070067import org.onosproject.net.Port;
68import org.onosproject.net.device.DeviceEvent;
69import org.onosproject.net.device.DeviceListener;
70import org.onosproject.net.device.DeviceService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070071import org.onosproject.net.flowobjective.FlowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -070072import org.onosproject.net.host.HostService;
sanghob35a6192015-04-01 13:05:26 -070073import org.onosproject.net.link.LinkEvent;
74import org.onosproject.net.link.LinkListener;
75import org.onosproject.net.link.LinkService;
76import org.onosproject.net.packet.InboundPacket;
77import org.onosproject.net.packet.PacketContext;
78import org.onosproject.net.packet.PacketProcessor;
79import org.onosproject.net.packet.PacketService;
Charles Chanc42e84e2015-10-20 16:24:19 -070080import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
Charles Chane849c192016-01-11 18:28:54 -080081import org.onosproject.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070082import org.onosproject.store.service.EventuallyConsistentMap;
83import org.onosproject.store.service.EventuallyConsistentMapBuilder;
84import org.onosproject.store.service.StorageService;
85import org.onosproject.store.service.WallClockTimestamp;
sanghob35a6192015-04-01 13:05:26 -070086import org.slf4j.Logger;
87import org.slf4j.LoggerFactory;
88
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070089import java.net.URI;
Saurav Das0e99e2b2015-10-28 12:39:42 -070090import java.util.Collections;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070091import java.util.HashSet;
sangho1e575652015-05-14 00:39:53 -070092import java.util.List;
sanghob35a6192015-04-01 13:05:26 -070093import java.util.Map;
Charles Chan188ebf52015-12-23 00:15:11 -080094import java.util.Optional;
Saurav Das0e99e2b2015-10-28 12:39:42 -070095import java.util.Set;
sanghob35a6192015-04-01 13:05:26 -070096import java.util.concurrent.ConcurrentHashMap;
97import java.util.concurrent.ConcurrentLinkedQueue;
98import java.util.concurrent.Executors;
99import java.util.concurrent.ScheduledExecutorService;
100import java.util.concurrent.ScheduledFuture;
101import java.util.concurrent.TimeUnit;
102
sangho1e575652015-05-14 00:39:53 -0700103@Service
sanghob35a6192015-04-01 13:05:26 -0700104@Component(immediate = true)
Charles Chane849c192016-01-11 18:28:54 -0800105/**
106 * Segment routing manager.
107 */
sangho1e575652015-05-14 00:39:53 -0700108public class SegmentRoutingManager implements SegmentRoutingService {
sanghob35a6192015-04-01 13:05:26 -0700109
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700110 private static Logger log = LoggerFactory
111 .getLogger(SegmentRoutingManager.class);
sanghob35a6192015-04-01 13:05:26 -0700112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected CoreService coreService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700117 protected PacketService packetService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700120 protected HostService hostService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected DeviceService deviceService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700126 protected FlowObjectiveService flowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -0700127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected LinkService linkService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700132 protected MastershipService mastershipService;
sangho1e575652015-05-14 00:39:53 -0700133
Charles Chan5270ed02016-01-30 23:22:37 -0800134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected StorageService storageService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected NetworkConfigRegistry cfgService;
139
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700140 protected ArpHandler arpHandler = null;
141 protected IcmpHandler icmpHandler = null;
142 protected IpHandler ipHandler = null;
143 protected RoutingRulePopulator routingRulePopulator = null;
sanghob35a6192015-04-01 13:05:26 -0700144 protected ApplicationId appId;
sangho666cd6d2015-04-14 16:27:13 -0700145 protected DeviceConfiguration deviceConfiguration = null;
sanghob35a6192015-04-01 13:05:26 -0700146
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700147 private DefaultRoutingHandler defaultRoutingHandler = null;
sangho1e575652015-05-14 00:39:53 -0700148 private TunnelHandler tunnelHandler = null;
149 private PolicyHandler policyHandler = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700150 private InternalPacketProcessor processor = null;
151 private InternalLinkListener linkListener = null;
152 private InternalDeviceListener deviceListener = null;
Charles Chan5270ed02016-01-30 23:22:37 -0800153 private NetworkConfigEventHandler netcfgHandler = null;
sanghob35a6192015-04-01 13:05:26 -0700154 private InternalEventHandler eventHandler = new InternalEventHandler();
Charles Chan5270ed02016-01-30 23:22:37 -0800155 private final InternalHostListener hostListener = new InternalHostListener();
sanghob35a6192015-04-01 13:05:26 -0700156
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700157 private ScheduledExecutorService executorService = Executors
158 .newScheduledThreadPool(1);
sanghob35a6192015-04-01 13:05:26 -0700159
Saurav Das4ce45962015-11-24 23:21:05 -0800160 @SuppressWarnings("unused")
sanghob35a6192015-04-01 13:05:26 -0700161 private static ScheduledFuture<?> eventHandlerFuture = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800162 @SuppressWarnings("rawtypes")
sanghob35a6192015-04-01 13:05:26 -0700163 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Charles Chan68aa62d2015-11-09 16:37:23 -0800164 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
Charles Chane849c192016-01-11 18:28:54 -0800165 new ConcurrentHashMap<>();
166 /**
167 * Per device next objective ID store with (device id + neighbor set) as key.
168 */
169 public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
Charles Chan68aa62d2015-11-09 16:37:23 -0800170 nsNextObjStore = null;
Charles Chane849c192016-01-11 18:28:54 -0800171 /**
172 * Per device next objective ID store with (device id + subnet) as key.
173 */
174 public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
Charles Chan68aa62d2015-11-09 16:37:23 -0800175 subnetNextObjStore = null;
Charles Chane849c192016-01-11 18:28:54 -0800176 /**
177 * Per device next objective ID store with (device id + port) as key.
178 */
179 public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
Saurav Das4ce45962015-11-24 23:21:05 -0800180 portNextObjStore = null;
Charles Chane849c192016-01-11 18:28:54 -0800181 /**
182 * Per cross-connect objective ID store with VLAN ID as key.
183 */
184 public EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer>
185 xConnectNextObjStore = null;
Saurav Das0e99e2b2015-10-28 12:39:42 -0700186 // Per device, per-subnet assigned-vlans store, with (device id + subnet
187 // IPv4 prefix) as key
188 private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
Charles Chane849c192016-01-11 18:28:54 -0800189 subnetVidStore = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800190 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
191 private EventuallyConsistentMap<String, Policy> policyStore = null;
sangho0b2b6d12015-05-20 22:16:38 -0700192
Charles Chan4636be02015-10-07 14:21:45 -0700193 private final InternalConfigListener cfgListener =
194 new InternalConfigListener(this);
195
Charles Chan5270ed02016-01-30 23:22:37 -0800196 private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> cfgDeviceFactory =
197 new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
198 SegmentRoutingDeviceConfig.class,
Charles Chand6832882015-10-05 17:50:33 -0700199 "segmentrouting") {
200 @Override
Charles Chan5270ed02016-01-30 23:22:37 -0800201 public SegmentRoutingDeviceConfig createConfig() {
202 return new SegmentRoutingDeviceConfig();
Charles Chand6832882015-10-05 17:50:33 -0700203 }
204 };
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700205
Charles Chan5270ed02016-01-30 23:22:37 -0800206 private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> cfgAppFactory =
207 new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
208 SegmentRoutingAppConfig.class,
209 "segmentrouting") {
210 @Override
211 public SegmentRoutingAppConfig createConfig() {
212 return new SegmentRoutingAppConfig();
213 }
214 };
Charles Chan68aa62d2015-11-09 16:37:23 -0800215
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700216 private Object threadSchedulerLock = new Object();
217 private static int numOfEventsQueued = 0;
218 private static int numOfEventsExecuted = 0;
sanghob35a6192015-04-01 13:05:26 -0700219 private static int numOfHandlerExecution = 0;
220 private static int numOfHandlerScheduled = 0;
221
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700222 private KryoNamespace.Builder kryoBuilder = null;
Charles Chan116188d2016-02-18 14:22:42 -0800223 /**
224 * Segment Routing App ID.
225 */
226 public static final String SR_APP_ID = "org.onosproject.segmentrouting";
Charles Chane849c192016-01-11 18:28:54 -0800227 /**
228 * The starting value of per-subnet VLAN ID assignment.
229 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700230 private static final short ASSIGNED_VLAN_START = 4093;
Charles Chane849c192016-01-11 18:28:54 -0800231 /**
232 * The default VLAN ID assigned to the interfaces without subnet config.
233 */
Saurav Das0e99e2b2015-10-28 12:39:42 -0700234 public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
235
sanghob35a6192015-04-01 13:05:26 -0700236 @Activate
237 protected void activate() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700238 appId = coreService
Charles Chan5270ed02016-01-30 23:22:37 -0800239 .registerApplication(SR_APP_ID);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700240
241 kryoBuilder = new KryoNamespace.Builder()
242 .register(NeighborSetNextObjectiveStoreKey.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700243 SubnetNextObjectiveStoreKey.class,
244 SubnetAssignedVidStoreKey.class,
sangho0b2b6d12015-05-20 22:16:38 -0700245 NeighborSet.class,
246 DeviceId.class,
247 URI.class,
248 WallClockTimestamp.class,
249 org.onosproject.cluster.NodeId.class,
250 HashSet.class,
251 Tunnel.class,
252 DefaultTunnel.class,
253 Policy.class,
254 TunnelPolicy.class,
Saurav Das0e99e2b2015-10-28 12:39:42 -0700255 Policy.Type.class,
Charles Chanc42e84e2015-10-20 16:24:19 -0700256 VlanId.class,
257 Ip4Address.class,
258 Ip4Prefix.class,
259 IpAddress.Version.class,
260 ConnectPoint.class
sangho0b2b6d12015-05-20 22:16:38 -0700261 );
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700262
263 log.debug("Creating EC map nsnextobjectivestore");
264 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
265 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700266 nsNextObjStore = nsNextObjMapBuilder
267 .withName("nsnextobjectivestore")
268 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700269 .withTimestampProvider((k, v) -> new WallClockTimestamp())
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700270 .build();
271 log.trace("Current size {}", nsNextObjStore.size());
272
Charles Chanc42e84e2015-10-20 16:24:19 -0700273 log.debug("Creating EC map subnetnextobjectivestore");
274 EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
275 subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
Charles Chanc42e84e2015-10-20 16:24:19 -0700276 subnetNextObjStore = subnetNextObjMapBuilder
277 .withName("subnetnextobjectivestore")
278 .withSerializer(kryoBuilder)
279 .withTimestampProvider((k, v) -> new WallClockTimestamp())
280 .build();
281
Saurav Das4ce45962015-11-24 23:21:05 -0800282 log.debug("Creating EC map subnetnextobjectivestore");
283 EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
284 portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
285 portNextObjStore = portNextObjMapBuilder
286 .withName("portnextobjectivestore")
287 .withSerializer(kryoBuilder)
288 .withTimestampProvider((k, v) -> new WallClockTimestamp())
289 .build();
290
Charles Chane849c192016-01-11 18:28:54 -0800291 log.debug("Creating EC map xconnectnextobjectivestore");
292 EventuallyConsistentMapBuilder<XConnectNextObjectiveStoreKey, Integer>
293 xConnectNextObjStoreBuilder = storageService.eventuallyConsistentMapBuilder();
294 xConnectNextObjStore = xConnectNextObjStoreBuilder
295 .withName("xconnectnextobjectivestore")
296 .withSerializer(kryoBuilder)
297 .withTimestampProvider((k, v) -> new WallClockTimestamp())
298 .build();
299
sangho0b2b6d12015-05-20 22:16:38 -0700300 EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
301 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700302 tunnelStore = tunnelMapBuilder
303 .withName("tunnelstore")
304 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700305 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700306 .build();
307
308 EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
309 storageService.eventuallyConsistentMapBuilder();
sangho0b2b6d12015-05-20 22:16:38 -0700310 policyStore = policyMapBuilder
311 .withName("policystore")
312 .withSerializer(kryoBuilder)
Madan Jampanibcf1a482015-06-24 19:05:56 -0700313 .withTimestampProvider((k, v) -> new WallClockTimestamp())
sangho0b2b6d12015-05-20 22:16:38 -0700314 .build();
315
Saurav Das0e99e2b2015-10-28 12:39:42 -0700316 EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
317 subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
Saurav Das0e99e2b2015-10-28 12:39:42 -0700318 subnetVidStore = subnetVidStoreMapBuilder
319 .withName("subnetvidstore")
320 .withSerializer(kryoBuilder)
321 .withTimestampProvider((k, v) -> new WallClockTimestamp())
322 .build();
323
Charles Chand6832882015-10-05 17:50:33 -0700324 cfgService.addListener(cfgListener);
Charles Chan5270ed02016-01-30 23:22:37 -0800325 cfgService.registerConfigFactory(cfgDeviceFactory);
326 cfgService.registerConfigFactory(cfgAppFactory);
Charles Chan68aa62d2015-11-09 16:37:23 -0800327
Charles Chanb8e10c82015-10-14 11:24:40 -0700328 processor = new InternalPacketProcessor();
329 linkListener = new InternalLinkListener();
330 deviceListener = new InternalDeviceListener();
Charles Chan5270ed02016-01-30 23:22:37 -0800331 netcfgHandler = new NetworkConfigEventHandler(this);
Charles Chanb8e10c82015-10-14 11:24:40 -0700332
Charles Chan5270ed02016-01-30 23:22:37 -0800333 hostService.addListener(hostListener);
Charles Chanb8e10c82015-10-14 11:24:40 -0700334 packetService.addProcessor(processor, PacketProcessor.director(2));
335 linkService.addListener(linkListener);
336 deviceService.addListener(deviceListener);
337
Charles Chan188ebf52015-12-23 00:15:11 -0800338 // Request ARP packet-in
339 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
340 selector.matchEthType(Ethernet.TYPE_ARP);
341 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
342
Charles Chanb8e10c82015-10-14 11:24:40 -0700343 cfgListener.configureNetwork();
344
sanghob35a6192015-04-01 13:05:26 -0700345 log.info("Started");
346 }
347
348 @Deactivate
349 protected void deactivate() {
Charles Chand6832882015-10-05 17:50:33 -0700350 cfgService.removeListener(cfgListener);
Charles Chan5270ed02016-01-30 23:22:37 -0800351 cfgService.unregisterConfigFactory(cfgDeviceFactory);
352 cfgService.unregisterConfigFactory(cfgAppFactory);
Charles Chand6832882015-10-05 17:50:33 -0700353
Charles Chan188ebf52015-12-23 00:15:11 -0800354 // Withdraw ARP packet-in
355 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
356 selector.matchEthType(Ethernet.TYPE_ARP);
357 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId, Optional.empty());
358
sanghob35a6192015-04-01 13:05:26 -0700359 packetService.removeProcessor(processor);
Charles Chanb8e10c82015-10-14 11:24:40 -0700360 linkService.removeListener(linkListener);
361 deviceService.removeListener(deviceListener);
sanghob35a6192015-04-01 13:05:26 -0700362 processor = null;
Charles Chanb8e10c82015-10-14 11:24:40 -0700363 linkListener = null;
364 deviceService = null;
365
366 groupHandlerMap.clear();
367
sanghob35a6192015-04-01 13:05:26 -0700368 log.info("Stopped");
369 }
370
sangho1e575652015-05-14 00:39:53 -0700371
372 @Override
373 public List<Tunnel> getTunnels() {
374 return tunnelHandler.getTunnels();
375 }
376
377 @Override
sangho71abe1b2015-06-29 14:58:47 -0700378 public TunnelHandler.Result createTunnel(Tunnel tunnel) {
379 return tunnelHandler.createTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700380 }
381
382 @Override
sangho71abe1b2015-06-29 14:58:47 -0700383 public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
sangho1e575652015-05-14 00:39:53 -0700384 for (Policy policy: policyHandler.getPolicies()) {
385 if (policy.type() == Policy.Type.TUNNEL_FLOW) {
386 TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
387 if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
388 log.warn("Cannot remove the tunnel used by a policy");
sangho71abe1b2015-06-29 14:58:47 -0700389 return TunnelHandler.Result.TUNNEL_IN_USE;
sangho1e575652015-05-14 00:39:53 -0700390 }
391 }
392 }
sangho71abe1b2015-06-29 14:58:47 -0700393 return tunnelHandler.removeTunnel(tunnel);
sangho1e575652015-05-14 00:39:53 -0700394 }
395
396 @Override
sangho71abe1b2015-06-29 14:58:47 -0700397 public PolicyHandler.Result removePolicy(Policy policy) {
398 return policyHandler.removePolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700399 }
400
401 @Override
sangho71abe1b2015-06-29 14:58:47 -0700402 public PolicyHandler.Result createPolicy(Policy policy) {
403 return policyHandler.createPolicy(policy);
sangho1e575652015-05-14 00:39:53 -0700404 }
405
406 @Override
407 public List<Policy> getPolicies() {
408 return policyHandler.getPolicies();
409 }
410
sanghof9d0bf12015-05-19 11:57:42 -0700411 /**
412 * Returns the tunnel object with the tunnel ID.
413 *
414 * @param tunnelId Tunnel ID
415 * @return Tunnel reference
416 */
sangho1e575652015-05-14 00:39:53 -0700417 public Tunnel getTunnel(String tunnelId) {
418 return tunnelHandler.getTunnel(tunnelId);
419 }
420
sanghob35a6192015-04-01 13:05:26 -0700421 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700422 * Returns the vlan-id assigned to the subnet configured for a device.
423 * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
424 * if and only if this controller instance is the master for the device.
425 * <p>
426 * USAGE: The assigned vlans are meant to be applied to untagged packets on those
427 * switches/pipelines that need this functionality. These vids are meant
428 * to be used internally within a switch, and thus need to be unique only
429 * on a switch level. Note that packets never go out on the wire with these
430 * vlans. Currently, vlan ids are assigned from value 4093 down.
431 * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
432 * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
433 * per subnet.
sanghob35a6192015-04-01 13:05:26 -0700434 *
Saurav Das0e99e2b2015-10-28 12:39:42 -0700435 * @param deviceId switch dpid
436 * @param subnet IPv4 prefix for which assigned vlan is desired
437 * @return VlanId assigned for the subnet on the device, or
438 * null if no vlan assignment was found and this instance is not
439 * the master for the device.
sanghob35a6192015-04-01 13:05:26 -0700440 */
Charles Chane849c192016-01-11 18:28:54 -0800441 // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700442 public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
443 VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
444 deviceId, subnet));
445 if (assignedVid != null) {
446 log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
447 + "{}", subnet, deviceId, assignedVid);
448 return assignedVid;
449 }
450 //check mastership for the right to assign a vlan
451 if (!mastershipService.isLocalMaster(deviceId)) {
452 log.warn("This controller instance is not the master for device {}. "
453 + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
454 return null;
455 }
456 // vlan assignment is expensive but done only once
Charles Chan9f676b62015-10-29 14:58:10 -0700457 Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
Saurav Das0e99e2b2015-10-28 12:39:42 -0700458 Set<Short> assignedVlans = new HashSet<>();
459 Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
460 for (Ip4Prefix sub : configuredSubnets) {
461 VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
462 sub));
463 if (v != null) {
464 assignedVlans.add(v.toShort());
465 } else {
466 unassignedSubnets.add(sub);
467 }
468 }
469 short nextAssignedVlan = ASSIGNED_VLAN_START;
470 if (!assignedVlans.isEmpty()) {
471 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
472 }
473 for (Ip4Prefix unsub : unassignedSubnets) {
Charles Chan5270ed02016-01-30 23:22:37 -0800474 // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
475 if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
476 unsub.prefixLength() == 0) {
477 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
478 VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
479 } else {
480 subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
481 VlanId.vlanId(nextAssignedVlan--));
482 log.info("Assigned vlan: {} to subnet: {} on device: {}",
483 nextAssignedVlan + 1, unsub, deviceId);
484 }
sanghob35a6192015-04-01 13:05:26 -0700485 }
486
Saurav Das0e99e2b2015-10-28 12:39:42 -0700487 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
sanghob35a6192015-04-01 13:05:26 -0700488 }
489
sangho1e575652015-05-14 00:39:53 -0700490 /**
Saurav Das0e99e2b2015-10-28 12:39:42 -0700491 * Returns the next objective ID for the given NeighborSet.
Saurav Das8a0732e2015-11-20 15:27:53 -0800492 * If the nextObjective does not exist, a new one is created and
Saurav Das4ce45962015-11-24 23:21:05 -0800493 * its id is returned.
sangho1e575652015-05-14 00:39:53 -0700494 *
sanghof9d0bf12015-05-19 11:57:42 -0700495 * @param deviceId Device ID
496 * @param ns NegighborSet
Saurav Das8a0732e2015-11-20 15:27:53 -0800497 * @param meta metadata passed into the creation of a Next Objective
498 * @return next objective ID or -1 if an error was encountered during the
499 * creation of the nextObjective
sangho1e575652015-05-14 00:39:53 -0700500 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800501 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
502 TrafficSelector meta) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700503 if (groupHandlerMap.get(deviceId) != null) {
504 log.trace("getNextObjectiveId query in device {}", deviceId);
505 return groupHandlerMap
Saurav Das8a0732e2015-11-20 15:27:53 -0800506 .get(deviceId).getNextObjectiveId(ns, meta);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700507 } else {
Saurav Das4ce45962015-11-24 23:21:05 -0800508 log.warn("getNextObjectiveId query - groupHandler for device {} "
509 + "not found", deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700510 return -1;
511 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700512 }
513
Charles Chanc42e84e2015-10-20 16:24:19 -0700514 /**
Saurav Das4ce45962015-11-24 23:21:05 -0800515 * Returns the next objective ID for the given subnet prefix. It is expected
516 * that the next-objective has been pre-created from configuration.
Charles Chanc42e84e2015-10-20 16:24:19 -0700517 *
518 * @param deviceId Device ID
519 * @param prefix Subnet
Saurav Das4ce45962015-11-24 23:21:05 -0800520 * @return next objective ID or -1 if it was not found
Charles Chanc42e84e2015-10-20 16:24:19 -0700521 */
522 public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
523 if (groupHandlerMap.get(deviceId) != null) {
524 log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
525 return groupHandlerMap
526 .get(deviceId).getSubnetNextObjectiveId(prefix);
527 } else {
Saurav Das4ce45962015-11-24 23:21:05 -0800528 log.warn("getSubnetNextObjectiveId query - groupHandler for "
529 + "device {} not found", deviceId);
530 return -1;
531 }
532 }
533
534 /**
535 * Returns the next objective ID for the given portNumber, given the treatment.
536 * There could be multiple different treatments to the same outport, which
537 * would result in different objectives. If the next object
538 * does not exist, a new one is created and its id is returned.
539 *
540 * @param deviceId Device ID
541 * @param portNum port number on device for which NextObjective is queried
542 * @param treatment the actions to apply on the packets (should include outport)
543 * @param meta metadata passed into the creation of a Next Objective if necessary
544 * @return next objective ID or -1 if it was not found
545 */
546 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
547 TrafficTreatment treatment,
548 TrafficSelector meta) {
549 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
550 if (ghdlr != null) {
551 return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
552 } else {
Charles Chane849c192016-01-11 18:28:54 -0800553 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
554 + " not found", deviceId);
555 return -1;
556 }
557 }
558
559 /**
560 * Returns the next objective ID of type broadcast associated with the VLAN
561 * cross-connection.
562 *
563 * @param deviceId Device ID for the cross-connection
564 * @param vlanId VLAN ID for the cross-connection
565 * @return next objective ID or -1 if it was not found
566 */
567 public int getXConnectNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
568 DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
569 if (ghdlr != null) {
570 return ghdlr.getXConnectNextObjectiveId(vlanId);
571 } else {
572 log.warn("getPortNextObjectiveId query - groupHandler for device {}"
Saurav Das4ce45962015-11-24 23:21:05 -0800573 + " not found", deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700574 return -1;
575 }
576 }
577
sanghob35a6192015-04-01 13:05:26 -0700578 private class InternalPacketProcessor implements PacketProcessor {
sanghob35a6192015-04-01 13:05:26 -0700579 @Override
580 public void process(PacketContext context) {
581
582 if (context.isHandled()) {
583 return;
584 }
585
586 InboundPacket pkt = context.inPacket();
587 Ethernet ethernet = pkt.parsed();
Saurav Das4ce45962015-11-24 23:21:05 -0800588 log.trace("Rcvd pktin: {}", ethernet);
sanghob35a6192015-04-01 13:05:26 -0700589 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
590 arpHandler.processPacketIn(pkt);
591 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
592 IPv4 ipPacket = (IPv4) ethernet.getPayload();
593 ipHandler.addToPacketBuffer(ipPacket);
594 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
595 icmpHandler.processPacketIn(pkt);
596 } else {
597 ipHandler.processPacketIn(pkt);
598 }
599 }
600 }
601 }
602
603 private class InternalLinkListener implements LinkListener {
604 @Override
605 public void event(LinkEvent event) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700606 if (event.type() == LinkEvent.Type.LINK_ADDED
607 || event.type() == LinkEvent.Type.LINK_REMOVED) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700608 log.debug("Event {} received from Link Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700609 scheduleEventHandlerIfNotScheduled(event);
610 }
611 }
612 }
613
614 private class InternalDeviceListener implements DeviceListener {
sanghob35a6192015-04-01 13:05:26 -0700615 @Override
616 public void event(DeviceEvent event) {
sanghob35a6192015-04-01 13:05:26 -0700617 switch (event.type()) {
618 case DEVICE_ADDED:
619 case PORT_REMOVED:
sangho20eff1d2015-04-13 15:15:58 -0700620 case DEVICE_UPDATED:
621 case DEVICE_AVAILABILITY_CHANGED:
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700622 log.debug("Event {} received from Device Service", event.type());
sanghob35a6192015-04-01 13:05:26 -0700623 scheduleEventHandlerIfNotScheduled(event);
624 break;
625 default:
626 }
627 }
628 }
629
Saurav Das4ce45962015-11-24 23:21:05 -0800630 @SuppressWarnings("rawtypes")
sanghob35a6192015-04-01 13:05:26 -0700631 private void scheduleEventHandlerIfNotScheduled(Event event) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700632 synchronized (threadSchedulerLock) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700633 eventQueue.add(event);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700634 numOfEventsQueued++;
635
636 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
637 //No pending scheduled event handling threads. So start a new one.
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700638 eventHandlerFuture = executorService
639 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
640 numOfHandlerScheduled++;
641 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700642 log.trace("numOfEventsQueued {}, numOfEventHanlderScheduled {}",
643 numOfEventsQueued,
644 numOfHandlerScheduled);
sanghob35a6192015-04-01 13:05:26 -0700645 }
sanghob35a6192015-04-01 13:05:26 -0700646 }
647
648 private class InternalEventHandler implements Runnable {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700649 @Override
sanghob35a6192015-04-01 13:05:26 -0700650 public void run() {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700651 try {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700652 while (true) {
Saurav Das4ce45962015-11-24 23:21:05 -0800653 @SuppressWarnings("rawtypes")
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700654 Event event = null;
655 synchronized (threadSchedulerLock) {
656 if (!eventQueue.isEmpty()) {
657 event = eventQueue.poll();
658 numOfEventsExecuted++;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700659 } else {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700660 numOfHandlerExecution++;
661 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
662 numOfHandlerExecution, numOfEventsExecuted);
663 break;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700664 }
sangho20eff1d2015-04-13 15:15:58 -0700665 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700666 if (event.type() == LinkEvent.Type.LINK_ADDED) {
667 processLinkAdded((Link) event.subject());
668 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
669 processLinkRemoved((Link) event.subject());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700670 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
671 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
672 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800673 DeviceId deviceId = ((Device) event.subject()).id();
674 if (deviceService.isAvailable(deviceId)) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700675 log.info("Processing device event {} for available device {}",
676 event.type(), ((Device) event.subject()).id());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700677 processDeviceAdded((Device) event.subject());
Saurav Das423fe2b2015-12-04 10:52:59 -0800678 } /* else {
679 if (event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED) {
680 // availability changed and not available - dev gone
681 DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
682 if (groupHandler != null) {
683 groupHandler.removeAllGroups();
684 }
685 }
686 }*/
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700687 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
688 processPortRemoved((Device) event.subject(),
689 ((DeviceEvent) event).port());
690 } else {
691 log.warn("Unhandled event type: {}", event.type());
692 }
sanghob35a6192015-04-01 13:05:26 -0700693 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700694 } catch (Exception e) {
695 log.error("SegmentRouting event handler "
696 + "thread thrown an exception: {}", e);
sanghob35a6192015-04-01 13:05:26 -0700697 }
sanghob35a6192015-04-01 13:05:26 -0700698 }
699 }
700
sanghob35a6192015-04-01 13:05:26 -0700701 private void processLinkAdded(Link link) {
702 log.debug("A new link {} was added", link.toString());
Charles Chan0b4e6182015-11-03 10:42:14 -0800703 if (!deviceConfiguration.isConfigured(link.src().deviceId())) {
704 log.warn("Source device of this link is not configured.");
705 return;
706 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700707 //Irrespective whether the local is a MASTER or not for this device,
708 //create group handler instance and push default TTP flow rules.
709 //Because in a multi-instance setup, instances can initiate
710 //groups for any devices. Also the default TTP rules are needed
711 //to be pushed before inserting any IP table entries for any device
712 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
713 .deviceId());
714 if (groupHandler != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800715 groupHandler.linkUp(link, mastershipService.isLocalMaster(
716 link.src().deviceId()));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700717 } else {
718 Device device = deviceService.getDevice(link.src().deviceId());
719 if (device != null) {
720 log.warn("processLinkAdded: Link Added "
721 + "Notification without Device Added "
722 + "event, still handling it");
723 processDeviceAdded(device);
724 groupHandler = groupHandlerMap.get(link.src()
725 .deviceId());
Saurav Das8a0732e2015-11-20 15:27:53 -0800726 groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700727 }
728 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700729
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700730 log.trace("Starting optimized route population process");
731 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
732 //log.trace("processLinkAdded: re-starting route population process");
733 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700734 }
735
736 private void processLinkRemoved(Link link) {
737 log.debug("A link {} was removed", link.toString());
sangho834e4b02015-05-01 09:38:25 -0700738 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
739 if (groupHandler != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800740 groupHandler.portDown(link.src().port(),
741 mastershipService.isLocalMaster(link.src().deviceId()));
sangho834e4b02015-05-01 09:38:25 -0700742 }
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700743 log.trace("Starting optimized route population process");
744 defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
745 //log.trace("processLinkRemoved: re-starting route population process");
746 //defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700747 }
748
749 private void processDeviceAdded(Device device) {
750 log.debug("A new device with ID {} was added", device.id());
Charles Chan0b4e6182015-11-03 10:42:14 -0800751 if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800752 log.warn("Device configuration uploading. Device {} will be "
753 + "processed after config completes.", device.id());
754 return;
755 }
Saurav Das837e0bb2015-10-30 17:45:38 -0700756 // Irrespective of whether the local is a MASTER or not for this device,
757 // we need to create a SR-group-handler instance. This is because in a
758 // multi-instance setup, any instance can initiate forwarding/next-objectives
759 // for any switch (even if this instance is a SLAVE or not even connected
760 // to the switch). To handle this, a default-group-handler instance is necessary
761 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800762 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800763 DefaultGroupHandler groupHandler;
764 try {
765 groupHandler = DefaultGroupHandler.
766 createGroupHandler(device.id(),
767 appId,
768 deviceConfiguration,
769 linkService,
770 flowObjectiveService,
Charles Chan188ebf52015-12-23 00:15:11 -0800771 this);
Charles Chan0b4e6182015-11-03 10:42:14 -0800772 } catch (DeviceConfigNotFoundException e) {
773 log.warn(e.getMessage() + " Aborting processDeviceAdded.");
774 return;
775 }
Saurav Das2857f382015-11-03 14:39:27 -0800776 groupHandlerMap.put(device.id(), groupHandler);
777 // Also, in some cases, drivers may need extra
778 // information to process rules (eg. Router IP/MAC); and so, we send
779 // port addressing rules to the driver as well irrespective of whether
780 // this instance is the master or not.
781 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand6d581a2015-11-18 16:51:08 -0800782 hostListener.readInitialHosts();
Saurav Das2857f382015-11-03 14:39:27 -0800783 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700784 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800785 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700786 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800787 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chane849c192016-01-11 18:28:54 -0800788 groupHandler.createGroupsForXConnect(device.id());
789 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700790 }
Charles Chan5270ed02016-01-30 23:22:37 -0800791
792 netcfgHandler.initVRouters(device.id());
sanghob35a6192015-04-01 13:05:26 -0700793 }
794
795 private void processPortRemoved(Device device, Port port) {
796 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700797 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sanghob35a6192015-04-01 13:05:26 -0700798 if (groupHandler != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800799 groupHandler.portDown(port.number(),
800 mastershipService.isLocalMaster(device.id()));
sanghob35a6192015-04-01 13:05:26 -0700801 }
802 }
sangho1e575652015-05-14 00:39:53 -0700803
Charles Chand6832882015-10-05 17:50:33 -0700804 private class InternalConfigListener implements NetworkConfigListener {
Charles Chan4636be02015-10-07 14:21:45 -0700805 SegmentRoutingManager segmentRoutingManager;
806
Charles Chane849c192016-01-11 18:28:54 -0800807 /**
808 * Constructs the internal network config listener.
809 *
810 * @param srMgr segment routing manager
811 */
Charles Chan4636be02015-10-07 14:21:45 -0700812 public InternalConfigListener(SegmentRoutingManager srMgr) {
813 this.segmentRoutingManager = srMgr;
814 }
815
Charles Chane849c192016-01-11 18:28:54 -0800816 /**
817 * Reads network config and initializes related data structure accordingly.
818 */
Charles Chan4636be02015-10-07 14:21:45 -0700819 public void configureNetwork() {
Charles Chanf2565a92016-02-10 20:46:58 -0800820 deviceConfiguration = new DeviceConfiguration(appId,
821 segmentRoutingManager.cfgService);
Charles Chan4636be02015-10-07 14:21:45 -0700822
823 arpHandler = new ArpHandler(segmentRoutingManager);
824 icmpHandler = new IcmpHandler(segmentRoutingManager);
825 ipHandler = new IpHandler(segmentRoutingManager);
826 routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
827 defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
828
829 tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
830 groupHandlerMap, tunnelStore);
831 policyHandler = new PolicyHandler(appId, deviceConfiguration,
832 flowObjectiveService,
833 tunnelHandler, policyStore);
834
Charles Chan4636be02015-10-07 14:21:45 -0700835 for (Device device : deviceService.getDevices()) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700836 // Irrespective of whether the local is a MASTER or not for this device,
837 // we need to create a SR-group-handler instance. This is because in a
838 // multi-instance setup, any instance can initiate forwarding/next-objectives
839 // for any switch (even if this instance is a SLAVE or not even connected
840 // to the switch). To handle this, a default-group-handler instance is necessary
841 // per switch.
Saurav Das2857f382015-11-03 14:39:27 -0800842 if (groupHandlerMap.get(device.id()) == null) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800843 DefaultGroupHandler groupHandler;
844 try {
845 groupHandler = DefaultGroupHandler.
846 createGroupHandler(device.id(),
847 appId,
848 deviceConfiguration,
849 linkService,
850 flowObjectiveService,
Charles Chan188ebf52015-12-23 00:15:11 -0800851 segmentRoutingManager);
Charles Chan0b4e6182015-11-03 10:42:14 -0800852 } catch (DeviceConfigNotFoundException e) {
853 log.warn(e.getMessage() + " Aborting configureNetwork.");
854 return;
855 }
Saurav Das2857f382015-11-03 14:39:27 -0800856 groupHandlerMap.put(device.id(), groupHandler);
Saurav Das837e0bb2015-10-30 17:45:38 -0700857
Saurav Das2857f382015-11-03 14:39:27 -0800858 // Also, in some cases, drivers may need extra
859 // information to process rules (eg. Router IP/MAC); and so, we send
860 // port addressing rules to the driver as well, irrespective of whether
861 // this instance is the master or not.
862 defaultRoutingHandler.populatePortAddressingRules(device.id());
Charles Chand6d581a2015-11-18 16:51:08 -0800863 hostListener.readInitialHosts();
Saurav Das2857f382015-11-03 14:39:27 -0800864 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700865 if (mastershipService.isLocalMaster(device.id())) {
Saurav Das2857f382015-11-03 14:39:27 -0800866 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700867 groupHandler.createGroupsFromSubnetConfig();
Charles Chan68aa62d2015-11-09 16:37:23 -0800868 routingRulePopulator.populateSubnetBroadcastRule(device.id());
Charles Chane849c192016-01-11 18:28:54 -0800869 groupHandler.createGroupsForXConnect(device.id());
870 routingRulePopulator.populateXConnectBroadcastRule(device.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700871 }
Charles Chan4636be02015-10-07 14:21:45 -0700872 }
873
874 defaultRoutingHandler.startPopulationProcess();
875 }
876
Charles Chand6832882015-10-05 17:50:33 -0700877 @Override
878 public void event(NetworkConfigEvent event) {
Charles Chan5270ed02016-01-30 23:22:37 -0800879 // TODO move this part to NetworkConfigEventHandler
880 if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
881 switch (event.type()) {
882 case CONFIG_ADDED:
883 log.info("Segment Routing Config added.");
884 configureNetwork();
885 break;
886 case CONFIG_UPDATED:
887 log.info("Segment Routing Config updated.");
888 // TODO support dynamic configuration
889 break;
890 default:
891 break;
Charles Chanb8e10c82015-10-14 11:24:40 -0700892 }
Charles Chan5270ed02016-01-30 23:22:37 -0800893 } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
894 switch (event.type()) {
895 case CONFIG_ADDED:
896 netcfgHandler.processVRouterConfigAdded(event);
897 break;
898 case CONFIG_UPDATED:
899 netcfgHandler.processVRouterConfigUpdated(event);
900 break;
901 case CONFIG_REMOVED:
902 netcfgHandler.processVRouterConfigRemoved(event);
903 break;
904 default:
905 break;
Charles Chanb8e10c82015-10-14 11:24:40 -0700906 }
Charles Chand6832882015-10-05 17:50:33 -0700907 }
908 }
909 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800910
Charles Chand6d581a2015-11-18 16:51:08 -0800911 // TODO Move bridging table population to a separate class
Charles Chan68aa62d2015-11-09 16:37:23 -0800912 private class InternalHostListener implements HostListener {
Charles Chand6d581a2015-11-18 16:51:08 -0800913 private void readInitialHosts() {
914 hostService.getHosts().forEach(host -> {
915 MacAddress mac = host.mac();
916 VlanId vlanId = host.vlan();
917 DeviceId deviceId = host.location().deviceId();
918 PortNumber port = host.location().port();
919 Set<IpAddress> ips = host.ipAddresses();
920 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
921
922 // Populate bridging table entry
923 ForwardingObjective.Builder fob =
Saurav Das4ce45962015-11-24 23:21:05 -0800924 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Charles Chand6d581a2015-11-18 16:51:08 -0800925 flowObjectiveService.forward(deviceId, fob.add(
926 new BridgingTableObjectiveContext(mac, vlanId)
927 ));
928
929 // Populate IP table entry
930 ips.forEach(ip -> {
931 if (ip.isIp4()) {
932 routingRulePopulator.populateIpRuleForHost(
933 deviceId, ip.getIp4Address(), mac, port);
934 }
935 });
936 });
937 }
938
Charles Chan68aa62d2015-11-09 16:37:23 -0800939 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Saurav Das4ce45962015-11-24 23:21:05 -0800940 DeviceId deviceId, MacAddress mac, VlanId vlanId,
941 PortNumber outport) {
Charles Chan188ebf52015-12-23 00:15:11 -0800942 // Get assigned VLAN for the subnet
Saurav Das4ce45962015-11-24 23:21:05 -0800943 VlanId outvlan = null;
944 Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
945 if (subnet == null) {
946 outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
947 } else {
948 outvlan = getSubnetAssignedVlanId(deviceId, subnet);
949 }
Charles Chan188ebf52015-12-23 00:15:11 -0800950
951 // match rule
952 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
953 sbuilder.matchEthDst(mac);
954 /*
955 * Note: for untagged packets, match on the assigned VLAN.
956 * for tagged packets, match on its incoming VLAN.
957 */
958 if (vlanId.equals(VlanId.NONE)) {
959 sbuilder.matchVlanId(outvlan);
960 } else {
961 sbuilder.matchVlanId(vlanId);
962 }
963
964 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
965 tbuilder.immediate().popVlan();
966 tbuilder.immediate().setOutput(outport);
967
968 // for switch pipelines that need it, provide outgoing vlan as metadata
Saurav Das4ce45962015-11-24 23:21:05 -0800969 TrafficSelector meta = DefaultTrafficSelector.builder()
970 .matchVlanId(outvlan).build();
971
972 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
973 int portNextObjId = getPortNextObjectiveId(deviceId, outport,
974 tbuilder.build(),
975 meta);
Charles Chan68aa62d2015-11-09 16:37:23 -0800976
977 return DefaultForwardingObjective.builder()
978 .withFlag(ForwardingObjective.Flag.SPECIFIC)
979 .withSelector(sbuilder.build())
Saurav Das4ce45962015-11-24 23:21:05 -0800980 .nextStep(portNextObjId)
Charles Chan68aa62d2015-11-09 16:37:23 -0800981 .withPriority(100)
982 .fromApp(appId)
983 .makePermanent();
984 }
985
986 private void processHostAddedEvent(HostEvent event) {
987 MacAddress mac = event.subject().mac();
988 VlanId vlanId = event.subject().vlan();
989 DeviceId deviceId = event.subject().location().deviceId();
990 PortNumber port = event.subject().location().port();
991 Set<IpAddress> ips = event.subject().ipAddresses();
Saurav Das4ce45962015-11-24 23:21:05 -0800992 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
Charles Chan68aa62d2015-11-09 16:37:23 -0800993
Charles Chanf2565a92016-02-10 20:46:58 -0800994 if (!deviceConfiguration.excludedPorts()
995 .contains(new ConnectPoint(deviceId, port))) {
996 // Populate bridging table entry
997 log.debug("Populate L2 table entry for host {} at {}:{}",
998 mac, deviceId, port);
999 ForwardingObjective.Builder fob =
1000 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
1001 flowObjectiveService.forward(deviceId, fob.add(
1002 new BridgingTableObjectiveContext(mac, vlanId)
1003 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001004
Charles Chanf2565a92016-02-10 20:46:58 -08001005 // Populate IP table entry
1006 ips.forEach(ip -> {
1007 if (ip.isIp4()) {
1008 routingRulePopulator.populateIpRuleForHost(
1009 deviceId, ip.getIp4Address(), mac, port);
1010 }
1011 });
1012 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001013 }
1014
1015 private void processHostRemoveEvent(HostEvent event) {
1016 MacAddress mac = event.subject().mac();
1017 VlanId vlanId = event.subject().vlan();
1018 DeviceId deviceId = event.subject().location().deviceId();
1019 PortNumber port = event.subject().location().port();
1020 Set<IpAddress> ips = event.subject().ipAddresses();
1021 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
1022
Charles Chanf2565a92016-02-10 20:46:58 -08001023 if (!deviceConfiguration.excludedPorts()
1024 .contains(new ConnectPoint(deviceId, port))) {
1025 // Revoke bridging table entry
1026 ForwardingObjective.Builder fob =
1027 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
1028 flowObjectiveService.forward(deviceId, fob.remove(
1029 new BridgingTableObjectiveContext(mac, vlanId)
1030 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001031
Charles Chanf2565a92016-02-10 20:46:58 -08001032 // Revoke IP table entry
1033 ips.forEach(ip -> {
1034 if (ip.isIp4()) {
1035 routingRulePopulator.revokeIpRuleForHost(
1036 deviceId, ip.getIp4Address(), mac, port);
1037 }
1038 });
1039 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001040 }
1041
1042 private void processHostMovedEvent(HostEvent event) {
1043 MacAddress mac = event.subject().mac();
1044 VlanId vlanId = event.subject().vlan();
1045 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1046 PortNumber prevPort = event.prevSubject().location().port();
1047 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1048 DeviceId newDeviceId = event.subject().location().deviceId();
1049 PortNumber newPort = event.subject().location().port();
1050 Set<IpAddress> newIps = event.subject().ipAddresses();
1051 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
1052 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
1053
Charles Chanf2565a92016-02-10 20:46:58 -08001054 if (!deviceConfiguration.excludedPorts()
1055 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
1056 // Revoke previous bridging table entry
1057 ForwardingObjective.Builder prevFob =
1058 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
1059 flowObjectiveService.forward(prevDeviceId, prevFob.remove(
1060 new BridgingTableObjectiveContext(mac, vlanId)
1061 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001062
Charles Chanf2565a92016-02-10 20:46:58 -08001063 // Revoke previous IP table entry
1064 prevIps.forEach(ip -> {
1065 if (ip.isIp4()) {
1066 routingRulePopulator.revokeIpRuleForHost(
1067 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1068 }
1069 });
1070 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001071
Charles Chanf2565a92016-02-10 20:46:58 -08001072 if (!deviceConfiguration.excludedPorts()
1073 .contains(new ConnectPoint(newDeviceId, newPort))) {
1074 // Populate new bridging table entry
1075 ForwardingObjective.Builder newFob =
1076 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
1077 flowObjectiveService.forward(newDeviceId, newFob.add(
1078 new BridgingTableObjectiveContext(mac, vlanId)
1079 ));
Charles Chan68aa62d2015-11-09 16:37:23 -08001080
Charles Chanf2565a92016-02-10 20:46:58 -08001081 // Populate new IP table entry
1082 newIps.forEach(ip -> {
1083 if (ip.isIp4()) {
1084 routingRulePopulator.populateIpRuleForHost(
1085 newDeviceId, ip.getIp4Address(), mac, newPort);
1086 }
1087 });
1088 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001089 }
1090
1091 private void processHostUpdatedEvent(HostEvent event) {
1092 MacAddress mac = event.subject().mac();
1093 VlanId vlanId = event.subject().vlan();
1094 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
1095 PortNumber prevPort = event.prevSubject().location().port();
1096 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
1097 DeviceId newDeviceId = event.subject().location().deviceId();
1098 PortNumber newPort = event.subject().location().port();
1099 Set<IpAddress> newIps = event.subject().ipAddresses();
1100 log.debug("Host {}/{} is updated", mac, vlanId);
1101
Charles Chanf2565a92016-02-10 20:46:58 -08001102 if (!deviceConfiguration.excludedPorts()
1103 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
1104 // Revoke previous IP table entry
1105 prevIps.forEach(ip -> {
1106 if (ip.isIp4()) {
1107 routingRulePopulator.revokeIpRuleForHost(
1108 prevDeviceId, ip.getIp4Address(), mac, prevPort);
1109 }
1110 });
1111 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001112
Charles Chanf2565a92016-02-10 20:46:58 -08001113 if (!deviceConfiguration.excludedPorts()
1114 .contains(new ConnectPoint(newDeviceId, newPort))) {
1115 // Populate new IP table entry
1116 newIps.forEach(ip -> {
1117 if (ip.isIp4()) {
1118 routingRulePopulator.populateIpRuleForHost(
1119 newDeviceId, ip.getIp4Address(), mac, newPort);
1120 }
1121 });
1122 }
Charles Chan68aa62d2015-11-09 16:37:23 -08001123 }
1124
1125 @Override
1126 public void event(HostEvent event) {
1127 // Do not proceed without mastership
1128 DeviceId deviceId = event.subject().location().deviceId();
1129 if (!mastershipService.isLocalMaster(deviceId)) {
1130 return;
1131 }
1132
1133 switch (event.type()) {
1134 case HOST_ADDED:
1135 processHostAddedEvent(event);
1136 break;
1137 case HOST_MOVED:
1138 processHostMovedEvent(event);
1139 break;
1140 case HOST_REMOVED:
1141 processHostRemoveEvent(event);
1142 break;
1143 case HOST_UPDATED:
1144 processHostUpdatedEvent(event);
1145 break;
1146 default:
1147 log.warn("Unsupported host event type: {}", event.type());
1148 break;
1149 }
1150 }
1151 }
1152
1153 private static class BridgingTableObjectiveContext implements ObjectiveContext {
1154 final MacAddress mac;
1155 final VlanId vlanId;
1156
1157 BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) {
1158 this.mac = mac;
1159 this.vlanId = vlanId;
1160 }
1161
1162 @Override
1163 public void onSuccess(Objective objective) {
1164 if (objective.op() == Objective.Operation.ADD) {
1165 log.debug("Successfully populate bridging table entry for {}/{}",
1166 mac, vlanId);
1167 } else {
1168 log.debug("Successfully revoke bridging table entry for {}/{}",
1169 mac, vlanId);
1170 }
1171 }
1172
1173 @Override
1174 public void onError(Objective objective, ObjectiveError error) {
1175 if (objective.op() == Objective.Operation.ADD) {
1176 log.debug("Fail to populate bridging table entry for {}/{}. {}",
1177 mac, vlanId, error);
1178 } else {
1179 log.debug("Fail to revoke bridging table entry for {}/{}. {}",
1180 mac, vlanId, error);
1181 }
1182 }
1183 }
sanghob35a6192015-04-01 13:05:26 -07001184}