blob: f0f29273e89b5640cb96cc355f522e34c4101c9e [file] [log] [blame]
Jonathan Hart6344f572015-12-15 08:26:25 -08001/*
Jonathan Hartf4bd0482017-01-27 15:11:18 -08002 * Copyright 2017-present Open Networking Laboratory
Jonathan Hart6344f572015-12-15 08:26:25 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jonathan Hartf4bd0482017-01-27 15:11:18 -080017package org.onosproject.routing.cpr;
Jonathan Hart6344f572015-12-15 08:26:25 -080018
Jonathan Hartf04b7d92016-03-29 09:39:11 -070019import com.google.common.collect.ImmutableSortedSet;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053020import com.google.common.collect.Lists;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070021import com.google.common.collect.Maps;
Jonathan Hart6344f572015-12-15 08:26:25 -080022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
Charles Chanc6d227e2017-02-28 15:15:17 -080025import org.apache.felix.scr.annotations.Modified;
26import org.apache.felix.scr.annotations.Property;
Jonathan Hart6344f572015-12-15 08:26:25 -080027import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.onlab.packet.EthType;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +053030import org.onlab.packet.Ip4Address;
Pier Luigi2b1ad872017-01-31 09:35:42 -080031import org.onlab.packet.Ip6Address;
Charles Chand0fd5dc2016-02-16 23:14:49 -080032import org.onlab.packet.IpPrefix;
33import org.onlab.packet.MacAddress;
Saurav Das49cb5a12016-01-16 22:54:07 -080034import org.onlab.packet.VlanId;
Charles Chanc6d227e2017-02-28 15:15:17 -080035import org.onlab.util.Tools;
kishore786b7e42016-05-19 16:25:57 +053036import org.onosproject.app.ApplicationService;
Charles Chanc6d227e2017-02-28 15:15:17 -080037import org.onosproject.cfg.ComponentConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -080038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
40import org.onosproject.incubator.net.intf.Interface;
41import org.onosproject.incubator.net.intf.InterfaceService;
Charles Chand0fd5dc2016-02-16 23:14:49 -080042import org.onosproject.mastership.MastershipService;
Jonathan Hart6344f572015-12-15 08:26:25 -080043import org.onosproject.net.DeviceId;
Charles Chand0fd5dc2016-02-16 23:14:49 -080044import org.onosproject.net.Host;
Jonathan Hart6344f572015-12-15 08:26:25 -080045import org.onosproject.net.PortNumber;
46import org.onosproject.net.config.NetworkConfigEvent;
47import org.onosproject.net.config.NetworkConfigListener;
48import org.onosproject.net.config.NetworkConfigService;
Jonathan Hart6344f572015-12-15 08:26:25 -080049import org.onosproject.net.device.DeviceService;
50import org.onosproject.net.flow.DefaultTrafficSelector;
51import org.onosproject.net.flow.DefaultTrafficTreatment;
52import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
54import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080055import org.onosproject.net.flowobjective.DefaultNextObjective;
Jonathan Hart6344f572015-12-15 08:26:25 -080056import org.onosproject.net.flowobjective.FlowObjectiveService;
57import org.onosproject.net.flowobjective.ForwardingObjective;
Saurav Das49cb5a12016-01-16 22:54:07 -080058import org.onosproject.net.flowobjective.NextObjective;
Charles Chand0fd5dc2016-02-16 23:14:49 -080059import org.onosproject.net.host.HostEvent;
60import org.onosproject.net.host.HostListener;
61import org.onosproject.net.host.HostService;
Jonathan Hart6344f572015-12-15 08:26:25 -080062import org.onosproject.net.host.InterfaceIpAddress;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080063import org.onosproject.routing.RouterInfo;
64import org.onosproject.routing.InterfaceProvisionRequest;
65import org.onosproject.routing.Router;
Jonathan Hart6344f572015-12-15 08:26:25 -080066import org.onosproject.routing.RoutingService;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080067import org.onosproject.routing.config.RouterConfigHelper;
68import org.onosproject.routing.config.RoutersConfig;
69import org.onosproject.routing.config.RoutingConfigurationService;
Charles Chanc6d227e2017-02-28 15:15:17 -080070import org.osgi.service.component.ComponentContext;
Jonathan Hart6344f572015-12-15 08:26:25 -080071import org.slf4j.Logger;
72
Charles Chanc6d227e2017-02-28 15:15:17 -080073import java.util.Dictionary;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070074import java.util.Iterator;
75import java.util.List;
76import java.util.Map;
77import java.util.Optional;
78import java.util.Set;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080079import java.util.concurrent.ConcurrentHashMap;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070080
81import static com.google.common.base.Preconditions.checkState;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070082import static org.onlab.packet.Ethernet.TYPE_ARP;
83import static org.onlab.packet.Ethernet.TYPE_IPV4;
84import static org.onlab.packet.Ethernet.TYPE_IPV6;
85import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
86import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
87import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Pier Luigi2b1ad872017-01-31 09:35:42 -080088import static org.onlab.packet.IPv6.getLinkLocalAddress;
89import static org.onlab.packet.IPv6.getSolicitNodeAddress;
Jonathan Hartf04b7d92016-03-29 09:39:11 -070090import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hart6344f572015-12-15 08:26:25 -080091
92/**
93 * Manages connectivity between peers redirecting control traffic to a routing
94 * control plane available on the dataplane.
95 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080096@Component(immediate = true)
Jonathan Hart6344f572015-12-15 08:26:25 -080097public class ControlPlaneRedirectManager {
98
99 private final Logger log = getLogger(getClass());
100
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800101 public static final short ASSIGNED_VLAN = 4094;
102
Charles Chand0fd5dc2016-02-16 23:14:49 -0800103 private static final int MIN_IP_PRIORITY = 10;
kishore36d1c272016-09-21 15:44:10 +0530104 private static final int IPV4_PRIORITY = 2000;
105 private static final int IPV6_PRIORITY = 500;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530106 static final int ACL_PRIORITY = 40001;
Jonathan Hartea492382016-01-13 09:33:13 -0800107 private static final int OSPF_IP_PROTO = 0x59;
Jonathan Hart6344f572015-12-15 08:26:25 -0800108
Jonathan Hart6344f572015-12-15 08:26:25 -0800109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected CoreService coreService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected DeviceService deviceService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected InterfaceService interfaceService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected FlowObjectiveService flowObjectiveService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected NetworkConfigService networkConfigService;
123
Charles Chand0fd5dc2016-02-16 23:14:49 -0800124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected MastershipService mastershipService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected HostService hostService;
129
kishore786b7e42016-05-19 16:25:57 +0530130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected ApplicationService applicationService;
132
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
134 protected RoutingConfigurationService rs;
135
Charles Chanc6d227e2017-02-28 15:15:17 -0800136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected ComponentConfigService cfgService;
138
139 @Property(name = "forceUnprovision", boolValue = false,
140 label = "Force unprovision when the device goes offline")
141 private boolean forceUnprovision = false;
142
Jonathan Harte7327042017-02-02 13:11:25 -0800143 private static final String APP_NAME = "org.onosproject.cpr";
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700144 private ApplicationId appId;
145
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700146 private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
147
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800148 private Map<DeviceId, Router> routers = new ConcurrentHashMap<>();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700149
Jonathan Hart6344f572015-12-15 08:26:25 -0800150 private final InternalNetworkConfigListener networkConfigListener =
151 new InternalNetworkConfigListener();
Charles Chand0fd5dc2016-02-16 23:14:49 -0800152 private final InternalHostListener hostListener = new InternalHostListener();
Jonathan Hart6344f572015-12-15 08:26:25 -0800153
154 @Activate
Charles Chanc6d227e2017-02-28 15:15:17 -0800155 protected void activate(ComponentContext context) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800156 this.appId = coreService.registerApplication(APP_NAME);
157
Charles Chanc6d227e2017-02-28 15:15:17 -0800158 cfgService.registerProperties(getClass());
159 modified(context);
160
Jonathan Hart6344f572015-12-15 08:26:25 -0800161 networkConfigService.addListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800162 hostService.addListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700163
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800164 processRouterConfig();
Charles Chan00d8b5f2016-12-04 17:17:39 -0800165
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800166 applicationService.registerDeactivateHook(this.appId,
167 () -> routers.forEach((d, r) -> r.cleanup()));
Jonathan Hart6344f572015-12-15 08:26:25 -0800168 }
169
170 @Deactivate
Jonathan Harte7327042017-02-02 13:11:25 -0800171 protected void deactivate() {
Charles Chanc6d227e2017-02-28 15:15:17 -0800172 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart6344f572015-12-15 08:26:25 -0800173 networkConfigService.removeListener(networkConfigListener);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800174 hostService.removeListener(hostListener);
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700175 }
176
Charles Chanc6d227e2017-02-28 15:15:17 -0800177 @Modified
178 protected void modified(ComponentContext context) {
179 if (context != null) {
180 readComponentConfiguration(context);
181 processRouterConfig();
182 }
183 }
184
185 private void readComponentConfiguration(ComponentContext context) {
186 Dictionary<?, ?> properties = context.getProperties();
187 Boolean flag;
188
189 flag = Tools.isPropertyEnabled(properties, "forceUnprovision");
190 if (flag == null) {
191 log.info("ForceUnprovision is not configured, " +
192 "using current value of {}", forceUnprovision);
193 } else {
194 forceUnprovision = flag;
195 log.info("Configured. ForceUnprovision is {}",
196 forceUnprovision ? "enabled" : "disabled");
197 }
198 }
199
kishore786b7e42016-05-19 16:25:57 +0530200 /**
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700201 * Sets up the router interfaces if router config is available.
202 */
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800203 private void processRouterConfig() {
Jonathan Hart6344f572015-12-15 08:26:25 -0800204 ApplicationId routingAppId =
205 coreService.registerApplication(RoutingService.ROUTER_APP_ID);
206
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800207 Set<RoutersConfig.Router> routerConfigs =
208 RouterConfigHelper.getRouterConfigurations(networkConfigService, routingAppId);
Jonathan Hart6344f572015-12-15 08:26:25 -0800209
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800210 for (RoutersConfig.Router router : routerConfigs) {
211 DeviceId deviceId = router.controlPlaneConnectPoint().deviceId();
212
213 routers.compute(deviceId, (d, r) -> {
214 if (r == null) {
215 return createRouter(RouterInfo.from(router));
216 } else {
Charles Chanc6d227e2017-02-28 15:15:17 -0800217 r.changeConfiguration(RouterInfo.from(router), forceUnprovision);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800218 return r;
219 }
220 });
Jonathan Hart6344f572015-12-15 08:26:25 -0800221 }
222
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800223 for (DeviceId deviceId : routers.keySet()) {
224 if (!configExists(deviceId, routerConfigs)) {
225 Router router = routers.remove(deviceId);
226 router.cleanup();
227 }
Jonathan Hart6344f572015-12-15 08:26:25 -0800228 }
229 }
230
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800231 private boolean configExists(DeviceId deviceId, Set<RoutersConfig.Router> config) {
232 return config.stream()
233 .anyMatch(r -> r.controlPlaneConnectPoint().deviceId().equals(deviceId));
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800234 }
235
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800236 private Router createRouter(RouterInfo info) {
237 return new Router(info,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800238 interfaceService,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800239 deviceService,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800240 this::provisionInterface,
Charles Chanc6d227e2017-02-28 15:15:17 -0800241 this::unprovisionInterface,
242 forceUnprovision);
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800243 }
244
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800245 private void provisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800246 updateInterfaceObjectives(intf, true);
247 }
248
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800249 private void unprovisionInterface(InterfaceProvisionRequest intf) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800250 updateInterfaceObjectives(intf, false);
251 }
252
253 /**
254 * Installs or removes flow objectives relating to a give interface.
255 *
256 * @param intf interface to change objectives for
257 * @param install true to install the objectives, false to remove them
258 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800259 private void updateInterfaceObjectives(InterfaceProvisionRequest intf, boolean install) {
Jonathan Hartf8035d32016-06-16 16:23:26 -0700260 updateInterfaceForwarding(intf, install);
261 updateOspfForwarding(intf, install);
Jonathan Hart6344f572015-12-15 08:26:25 -0800262 }
263
kishore71a27532016-03-16 20:23:49 +0530264 /**
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800265 * Installs or removes the basic forwarding flows for each interface.
kishore71a27532016-03-16 20:23:49 +0530266 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800267 * @param request provisioning request containing router and interface
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800268 * @param install true to install the objectives, false to remove them
269 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800270 private void updateInterfaceForwarding(InterfaceProvisionRequest request, boolean install) {
271 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800272 log.debug("{} interface objectives for {}", operation(install), intf);
Jonathan Hart6344f572015-12-15 08:26:25 -0800273
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700274 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800275
276 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Jonathan Hart6344f572015-12-15 08:26:25 -0800277 for (InterfaceIpAddress ip : intf.ipAddresses()) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800278 // create nextObjectives for forwarding to this interface and the
279 // controlPlaneConnectPoint
280 int cpNextId, intfNextId;
281 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530282 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800283 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530284 true, install);
285 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800286 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530287 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800288 } else {
kishore71a27532016-03-16 20:23:49 +0530289 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
290 intf.vlan(), false, install);
291 intfNextId = modifyNextObjective(deviceId, intf.connectPoint().port(),
292 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800293 }
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530294 List<ForwardingObjective> fwdToSend = Lists.newArrayList();
295 TrafficSelector selector;
296 // IP traffic toward the router.
297 selector = buildIPDstSelector(
298 ip.ipAddress().toIpPrefix(),
299 intf.connectPoint().port(),
300 null,
301 intf.mac(),
302 intf.vlan()
303 );
304 fwdToSend.add(buildForwardingObjective(selector, null, cpNextId, install, ACL_PRIORITY));
305 // IP traffic from the router.
306 selector = buildIPSrcSelector(
307 ip.ipAddress().toIpPrefix(),
308 controlPlanePort,
309 intf.mac(),
310 null,
311 intf.vlan()
312 );
313 fwdToSend.add(buildForwardingObjective(selector, null, intfNextId, install, ACL_PRIORITY));
314 // We build the punt treatment.
315 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart6344f572015-12-15 08:26:25 -0800316 .punt()
317 .build();
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530318 // Handling of neighbour discovery protocols.
319 // IPv4 traffic - we have to deal with the ARP protocol.
320 // IPv6 traffic - we have to deal with the NDP protocol.
321 if (ip.ipAddress().isIp4()) {
322 // ARP traffic towards the router.
323 selector = buildArpSelector(
324 intf.connectPoint().port(),
325 intf.vlan(),
326 null,
327 null
328 );
329 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
330 // ARP traffic from the router.
331 selector = buildArpSelector(
332 controlPlanePort,
333 intf.vlan(),
334 ip.ipAddress().getIp4Address(),
335 intf.mac()
336 );
337 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
338 } else {
339 // Neighbour solicitation traffic towards the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800340 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530341 selector = buildNdpSelector(
342 intf.connectPoint().port(),
343 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800344 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800345 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800346 NEIGHBOR_SOLICITATION,
347 null
348 );
349 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
350 // Neighbour solicitation traffic towards the router.
351 // This flow is for the link local address.
352 selector = buildNdpSelector(
353 intf.connectPoint().port(),
354 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800355 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800356 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800357 NEIGHBOR_SOLICITATION,
358 null
359 );
360 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
361 // Neighbour solicitation traffic towards the router.
362 // This flow is for the solicitation node address of
363 // the global unicast address.
364 selector = buildNdpSelector(
365 intf.connectPoint().port(),
366 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800367 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800368 Ip6Address.valueOf(getSolicitNodeAddress(ip.ipAddress().toOctets())).toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800369 NEIGHBOR_SOLICITATION,
370 null
371 );
372 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
373 // Neighbour solicitation traffic towards the router.
374 // This flow is for the solicitation node address of
375 // the link local address.
376 selector = buildNdpSelector(
377 intf.connectPoint().port(),
378 intf.vlan(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800379 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800380 Ip6Address.valueOf(
381 getSolicitNodeAddress(getLinkLocalAddress(intf.mac().toBytes()))
382 ).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530383 NEIGHBOR_SOLICITATION,
384 null
385 );
386 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
387 // Neighbour solicitation traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800388 // This flow is for the global unicast address.
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530389 selector = buildNdpSelector(
390 controlPlanePort,
391 intf.vlan(),
392 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800393 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530394 NEIGHBOR_SOLICITATION,
395 intf.mac()
396 );
397 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800398 // Neighbour solicitation traffic from the router.
399 // This flow is for the link local address.
400 selector = buildNdpSelector(
401 controlPlanePort,
402 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800403 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800404 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800405 NEIGHBOR_SOLICITATION,
406 intf.mac()
407 );
408 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
409 // Neighbour advertisement traffic towards the router.
410 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530411 selector = buildNdpSelector(
412 intf.connectPoint().port(),
413 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800414 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800415 ip.ipAddress().toIpPrefix(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800416 NEIGHBOR_ADVERTISEMENT,
417 null
418 );
419 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
420 // Neighbour advertisement traffic towards the router.
421 // This flow is for the link local address
422 selector = buildNdpSelector(
423 intf.connectPoint().port(),
424 intf.vlan(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530425 null,
Pier Luigi9f765dc2017-02-03 13:35:23 -0800426 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530427 NEIGHBOR_ADVERTISEMENT,
428 null
429 );
430 fwdToSend.add(buildForwardingObjective(selector, treatment, cpNextId, install, ACL_PRIORITY + 1));
431 // Neighbour advertisement traffic from the router.
Pier Luigi2b1ad872017-01-31 09:35:42 -0800432 // This flow is for the global unicast address
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530433 selector = buildNdpSelector(
434 controlPlanePort,
435 intf.vlan(),
436 ip.ipAddress().toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800437 null,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530438 NEIGHBOR_ADVERTISEMENT,
439 intf.mac()
440 );
441 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Pier Luigi2b1ad872017-01-31 09:35:42 -0800442 // Neighbour advertisement traffic from the router.
443 // This flow is for the link local address
444 selector = buildNdpSelector(
445 controlPlanePort,
446 intf.vlan(),
Pier Luigi2b1ad872017-01-31 09:35:42 -0800447 Ip6Address.valueOf(getLinkLocalAddress(intf.mac().toBytes())).toIpPrefix(),
Pier Luigi9f765dc2017-02-03 13:35:23 -0800448 null,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800449 NEIGHBOR_ADVERTISEMENT,
450 intf.mac()
451 );
452 fwdToSend.add(buildForwardingObjective(selector, treatment, intfNextId, install, ACL_PRIORITY + 1));
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530453 }
454 // Finally we push the fwd objectives through the flow objective service.
455 fwdToSend.stream().forEach(forwardingObjective ->
456 flowObjectiveService.forward(deviceId, forwardingObjective)
457 );
Jonathan Hart6344f572015-12-15 08:26:25 -0800458 }
459 }
460
kishore71a27532016-03-16 20:23:49 +0530461 /**
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700462 * Installs or removes OSPF forwarding rules.
kishore71a27532016-03-16 20:23:49 +0530463 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800464 * @param request provisioning request containing router and interface
kishore71a27532016-03-16 20:23:49 +0530465 * @param install true to create an add objective, false to create a remove
466 * objective
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800467 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800468 private void updateOspfForwarding(InterfaceProvisionRequest request, boolean install) {
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800469 // TODO IPv6 support has not been implemented yet
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800470 Interface intf = request.intf();
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800471 log.debug("{} OSPF flows for {}", operation(install), intf);
472
Jonathan Hartea492382016-01-13 09:33:13 -0800473 // OSPF to router
474 TrafficSelector toSelector = DefaultTrafficSelector.builder()
475 .matchInPort(intf.connectPoint().port())
476 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
477 .matchVlanId(intf.vlan())
478 .matchIPProtocol((byte) OSPF_IP_PROTO)
479 .build();
Jonathan Hart6344f572015-12-15 08:26:25 -0800480
Saurav Das49cb5a12016-01-16 22:54:07 -0800481 // create nextObjectives for forwarding to the controlPlaneConnectPoint
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700482 DeviceId deviceId = intf.connectPoint().deviceId();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800483 PortNumber controlPlanePort = request.controlPlaneConnectPoint().port();
Saurav Das49cb5a12016-01-16 22:54:07 -0800484 int cpNextId;
485 if (intf.vlan() == VlanId.NONE) {
kishore71a27532016-03-16 20:23:49 +0530486 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800487 VlanId.vlanId(ASSIGNED_VLAN),
kishore71a27532016-03-16 20:23:49 +0530488 true, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800489 } else {
kishore71a27532016-03-16 20:23:49 +0530490 cpNextId = modifyNextObjective(deviceId, controlPlanePort,
491 intf.vlan(), false, install);
Saurav Das49cb5a12016-01-16 22:54:07 -0800492 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700493 flowObjectiveService.forward(intf.connectPoint().deviceId(),
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800494 buildForwardingObjective(toSelector, null, cpNextId,
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800495 install ? request.info().ospfEnabled() : install, ACL_PRIORITY));
Jonathan Hartea492382016-01-13 09:33:13 -0800496 }
497
498 /**
Saurav Das49cb5a12016-01-16 22:54:07 -0800499 * Creates a next objective for forwarding to a port. Handles metadata for
500 * some pipelines that require vlan information for egress port.
501 *
502 * @param deviceId the device on which the next objective is being created
503 * @param portNumber the egress port
504 * @param vlanId vlan information for egress port
505 * @param popVlan if vlan tag should be popped or not
kishore71a27532016-03-16 20:23:49 +0530506 * @param install true to create an add next objective, false to create a remove
507 * next objective
Saurav Das49cb5a12016-01-16 22:54:07 -0800508 * @return nextId of the next objective created
509 */
kishore71a27532016-03-16 20:23:49 +0530510 private int modifyNextObjective(DeviceId deviceId, PortNumber portNumber,
511 VlanId vlanId, boolean popVlan, boolean install) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800512 int nextId = flowObjectiveService.allocateNextId();
513 NextObjective.Builder nextObjBuilder = DefaultNextObjective
514 .builder().withId(nextId)
515 .withType(NextObjective.Type.SIMPLE)
516 .fromApp(appId);
517
518 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
519 if (popVlan) {
520 ttBuilder.popVlan();
521 }
522 ttBuilder.setOutput(portNumber);
523
524 // setup metadata to pass to nextObjective - indicate the vlan on egress
525 // if needed by the switch pipeline.
526 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
527 metabuilder.matchVlanId(vlanId);
528
529 nextObjBuilder.withMeta(metabuilder.build());
530 nextObjBuilder.addTreatment(ttBuilder.build());
Jonathan Hartf04b7d92016-03-29 09:39:11 -0700531 log.debug("Submitted next objective {} in device {} for port/vlan {}/{}",
Saurav Das49cb5a12016-01-16 22:54:07 -0800532 nextId, deviceId, portNumber, vlanId);
kishore71a27532016-03-16 20:23:49 +0530533 if (install) {
534 flowObjectiveService.next(deviceId, nextObjBuilder.add());
535 } else {
536 flowObjectiveService.next(deviceId, nextObjBuilder.remove());
537 }
Saurav Das49cb5a12016-01-16 22:54:07 -0800538 return nextId;
539 }
Jonathan Hartf8035d32016-06-16 16:23:26 -0700540
Saurav Das49cb5a12016-01-16 22:54:07 -0800541 /**
542 * Builds a forwarding objective from the given selector, treatment and nextId.
Jonathan Hartea492382016-01-13 09:33:13 -0800543 *
544 * @param selector selector
Saurav Das49cb5a12016-01-16 22:54:07 -0800545 * @param treatment treatment to apply to packet, can be null
546 * @param nextId next objective to point to for forwarding packet
Jonathan Hartea492382016-01-13 09:33:13 -0800547 * @param add true to create an add objective, false to create a remove
548 * objective
549 * @return forwarding objective
550 */
551 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
552 TrafficTreatment treatment,
Saurav Das49cb5a12016-01-16 22:54:07 -0800553 int nextId,
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530554 boolean add,
555 int priority) {
Saurav Das49cb5a12016-01-16 22:54:07 -0800556 DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
557 fobBuilder.withSelector(selector);
558 if (treatment != null) {
559 fobBuilder.withTreatment(treatment);
560 }
561 if (nextId != -1) {
562 fobBuilder.nextStep(nextId);
563 }
564 fobBuilder.fromApp(appId)
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530565 .withPriority(priority)
Saurav Das49cb5a12016-01-16 22:54:07 -0800566 .withFlag(ForwardingObjective.Flag.VERSATILE);
Jonathan Hartea492382016-01-13 09:33:13 -0800567
568 return add ? fobBuilder.add() : fobBuilder.remove();
Jonathan Hart6344f572015-12-15 08:26:25 -0800569 }
570
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800571 static TrafficSelector.Builder buildBaseSelectorBuilder(PortNumber inPort,
572 MacAddress srcMac,
573 MacAddress dstMac,
574 VlanId vlanId) {
575 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
576 if (inPort != null) {
577 selectorBuilder.matchInPort(inPort);
578 }
579 if (srcMac != null) {
580 selectorBuilder.matchEthSrc(srcMac);
581 }
582 if (dstMac != null) {
583 selectorBuilder.matchEthDst(dstMac);
584 }
585 if (vlanId != null) {
586 selectorBuilder.matchVlanId(vlanId);
587 }
588 return selectorBuilder;
589 }
590
591 static TrafficSelector buildIPDstSelector(IpPrefix dstIp,
592 PortNumber inPort,
593 MacAddress srcMac,
594 MacAddress dstMac,
595 VlanId vlanId) {
596 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
597 if (dstIp.isIp4()) {
598 selector.matchEthType(TYPE_IPV4);
599 selector.matchIPDst(dstIp);
600 } else {
601 selector.matchEthType(TYPE_IPV6);
602 selector.matchIPv6Dst(dstIp);
603 }
604 return selector.build();
605 }
606
607 static TrafficSelector buildIPSrcSelector(IpPrefix srcIp,
608 PortNumber inPort,
609 MacAddress srcMac,
610 MacAddress dstMac,
611 VlanId vlanId) {
612 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, srcMac, dstMac, vlanId);
613 if (srcIp.isIp4()) {
614 selector.matchEthType(TYPE_IPV4);
615 selector.matchIPSrc(srcIp);
616 } else {
617 selector.matchEthType(TYPE_IPV6);
618 selector.matchIPv6Src(srcIp);
619 }
620 return selector.build();
621 }
622
623 static TrafficSelector buildArpSelector(PortNumber inPort,
624 VlanId vlanId,
625 Ip4Address arpSpa,
626 MacAddress srcMac) {
627 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
628 selector.matchEthType(TYPE_ARP);
629 if (arpSpa != null) {
630 selector.matchArpSpa(arpSpa);
631 }
632 if (srcMac != null) {
633 selector.matchEthSrc(srcMac);
634 }
635 return selector.build();
636 }
637
638 static TrafficSelector buildNdpSelector(PortNumber inPort,
639 VlanId vlanId,
640 IpPrefix srcIp,
Pier Luigi2b1ad872017-01-31 09:35:42 -0800641 IpPrefix dstIp,
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800642 byte subProto,
643 MacAddress srcMac) {
644 TrafficSelector.Builder selector = buildBaseSelectorBuilder(inPort, null, null, vlanId);
645 selector.matchEthType(TYPE_IPV6)
646 .matchIPProtocol(PROTOCOL_ICMP6)
647 .matchIcmpv6Type(subProto);
648 if (srcIp != null) {
649 selector.matchIPv6Src(srcIp);
650 }
Pier Luigi2b1ad872017-01-31 09:35:42 -0800651 if (dstIp != null) {
Pier Luigi9f765dc2017-02-03 13:35:23 -0800652 selector.matchIPv6Dst(dstIp);
Pier Luigi2b1ad872017-01-31 09:35:42 -0800653 }
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800654 if (srcMac != null) {
655 selector.matchEthSrc(srcMac);
656 }
657 return selector.build();
658 }
659
660 private int getPriorityFromPrefix(IpPrefix prefix) {
661 return (prefix.isIp4()) ?
662 IPV4_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY :
663 IPV6_PRIORITY * prefix.prefixLength() + MIN_IP_PRIORITY;
664 }
665
666 private String operation(boolean install) {
667 return install ? "Installing" : "Removing";
668 }
669
670
Jonathan Hartea492382016-01-13 09:33:13 -0800671 /**
Jonathan Hartea492382016-01-13 09:33:13 -0800672 * Listener for network config events.
673 */
Jonathan Hart6344f572015-12-15 08:26:25 -0800674 private class InternalNetworkConfigListener implements NetworkConfigListener {
kishore71a27532016-03-16 20:23:49 +0530675
Jonathan Hart6344f572015-12-15 08:26:25 -0800676 @Override
677 public void event(NetworkConfigEvent event) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800678 if (event.configClass().equals(RoutingService.ROUTER_CONFIG_CLASS) ||
679 event.configClass().equals(RoutersConfig.class)) {
Jonathan Hart6344f572015-12-15 08:26:25 -0800680 switch (event.type()) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700681 case CONFIG_ADDED:
682 case CONFIG_UPDATED:
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800683 case CONFIG_REMOVED:
Jonathan Hart7fc5a722017-01-26 15:54:12 -0800684 processRouterConfig();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700685 break;
686 case CONFIG_REGISTERED:
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700687 case CONFIG_UNREGISTERED:
688 break;
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530689 default:
690 break;
Jonathan Hart6344f572015-12-15 08:26:25 -0800691 }
692 }
693 }
694 }
Charles Chand0fd5dc2016-02-16 23:14:49 -0800695
696 /**
697 * Listener for host events.
698 */
699 private class InternalHostListener implements HostListener {
kishore71a27532016-03-16 20:23:49 +0530700
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700701 private Optional<Interface> getPeerInterface(Host peer) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800702 Router router = routers.get(peer.location().deviceId());
703
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700704 return interfaceService.getInterfacesByPort(peer.location()).stream()
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800705 .filter(intf -> router.info().interfaces().isEmpty()
706 || router.info().interfaces().contains(intf.name()))
Charles Chand0fd5dc2016-02-16 23:14:49 -0800707 .filter(intf -> peer.vlan().equals(intf.vlan()))
708 .findFirst();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700709 }
710
711 private void peerAdded(HostEvent event) {
712 Host peer = event.subject();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800713 Router routerInfo = routers.get(peer.location().deviceId());
714 if (routerInfo == null) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700715 return;
716 }
717
718 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800719 if (!peerIntf.isPresent()) {
720 log.debug("Adding peer {}/{} on {} but the interface is not configured",
721 peer.mac(), peer.vlan(), peer.location());
722 return;
723 }
724
Pier Luigi9f765dc2017-02-03 13:35:23 -0800725 // Generate L3 Unicast group for the traffic towards vRouter
726 // XXX This approach will change with the HA design
Charles Chand0fd5dc2016-02-16 23:14:49 -0800727 int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800728 peer.vlan(), peer.location().deviceId(), routerInfo.info().controlPlaneConnectPoint().port());
Pier Luigi9f765dc2017-02-03 13:35:23 -0800729 // Generate L3 Unicast group for the traffic towards the upStream
730 // XXX This approach will change with the HA design
Charles Chand0fd5dc2016-02-16 23:14:49 -0800731 int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
732 peer.vlan(), peer.location().deviceId(), peer.location().port());
Pier Luigi9f765dc2017-02-03 13:35:23 -0800733 // Store the next objectives in the map
Charles Chand0fd5dc2016-02-16 23:14:49 -0800734 peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
735
736 // From peer to router
737 peerIntf.get().ipAddresses().forEach(routerIp -> {
738 flowObjectiveService.forward(peer.location().deviceId(),
739 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
740 });
741
742 // From router to peer
743 peer.ipAddresses().forEach(peerIp -> {
744 flowObjectiveService.forward(peer.location().deviceId(),
745 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
746 });
747 }
748
749 private void peerRemoved(HostEvent event) {
750 Host peer = event.subject();
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800751 if (routers.get(peer.location().deviceId()) == null) {
752 return;
753 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700754 Optional<Interface> peerIntf = getPeerInterface(peer);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800755 if (!peerIntf.isPresent()) {
756 log.debug("Removing peer {}/{} on {} but the interface is not configured",
757 peer.mac(), peer.vlan(), peer.location());
758 return;
759 }
760
Charles Chand0fd5dc2016-02-16 23:14:49 -0800761 checkState(peerNextId.get(peer) != null,
762 "Peer nextId should not be null");
763 checkState(peerNextId.get(peer).size() == 2,
764 "Wrong nextId associated with the peer");
765 Iterator<Integer> iter = peerNextId.get(peer).iterator();
766 int toRouterL3Unicast = iter.next();
767 int toPeerL3Unicast = iter.next();
768
769 // From peer to router
770 peerIntf.get().ipAddresses().forEach(routerIp -> {
771 flowObjectiveService.forward(peer.location().deviceId(),
772 createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
773 });
774
775 // From router to peer
776 peer.ipAddresses().forEach(peerIp -> {
777 flowObjectiveService.forward(peer.location().deviceId(),
778 createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
779 });
780 }
781
782 private ForwardingObjective.Builder createPeerObjBuilder(
783 int nextId, IpPrefix ipAddresses) {
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530784 TrafficSelector selector = buildIPDstSelector(ipAddresses, null, null, null, null);
Charles Chand0fd5dc2016-02-16 23:14:49 -0800785 DefaultForwardingObjective.Builder builder =
786 DefaultForwardingObjective.builder()
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530787 .withSelector(selector)
Charles Chand0fd5dc2016-02-16 23:14:49 -0800788 .fromApp(appId)
789 .withPriority(getPriorityFromPrefix(ipAddresses))
790 .withFlag(ForwardingObjective.Flag.SPECIFIC);
791 if (nextId != -1) {
792 builder.nextStep(nextId);
793 }
794 return builder;
795 }
796
797 private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
798 VlanId vlanId, DeviceId deviceId, PortNumber port) {
799 int nextId = flowObjectiveService.allocateNextId();
800 NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
801 .withId(nextId)
802 .withType(NextObjective.Type.SIMPLE)
803 .fromApp(appId);
804
805 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
806 ttBuilder.setEthSrc(srcMac);
807 ttBuilder.setEthDst(dstMac);
808 ttBuilder.setOutput(port);
809 nextObjBuilder.addTreatment(ttBuilder.build());
810
811 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
812 VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
Jonathan Hartf4bd0482017-01-27 15:11:18 -0800813 VlanId.vlanId(ASSIGNED_VLAN) :
Charles Chand0fd5dc2016-02-16 23:14:49 -0800814 vlanId;
815 metabuilder.matchVlanId(matchVlanId);
816 nextObjBuilder.withMeta(metabuilder.build());
817
818 flowObjectiveService.next(deviceId, nextObjBuilder.add());
819 return nextId;
820 }
821
822 @Override
823 public void event(HostEvent event) {
824 DeviceId deviceId = event.subject().location().deviceId();
825 if (!mastershipService.isLocalMaster(deviceId)) {
826 return;
827 }
828 switch (event.type()) {
829 case HOST_ADDED:
830 peerAdded(event);
831 break;
832 case HOST_MOVED:
833 //TODO We assume BGP peer does not move for now
834 break;
835 case HOST_REMOVED:
836 peerRemoved(event);
837 break;
838 case HOST_UPDATED:
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530839 //FIXME We assume BGP peer does not change IP for now
840 // but we can discover new address.
Charles Chand0fd5dc2016-02-16 23:14:49 -0800841 break;
842 default:
843 break;
844 }
845 }
846 }
847
Jonathan Hart6344f572015-12-15 08:26:25 -0800848}
Vinayak Tejankar3a409c62017-01-12 02:20:53 +0530849