blob: 7f7314b46582ab6942fb5bd70d6488659f0d4d0c [file] [log] [blame]
Mohammad Shahid4c30ea32017-08-09 18:02:10 +05301/*
2 * Copyright 2017-present Open Networking Foundation
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 */
16
17package org.onosproject.evpnopenflow.manager.impl;
18
19import com.fasterxml.jackson.databind.JsonNode;
20import com.google.common.collect.Sets;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onlab.osgi.DefaultServiceDirectory;
28import org.onlab.packet.EthType;
29import org.onlab.packet.IpAddress;
30import org.onlab.packet.IpPrefix;
31import org.onlab.packet.MplsLabel;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.evpnopenflow.manager.EvpnService;
35import org.onosproject.evpnopenflow.rsc.VpnAfConfig;
36import org.onosproject.evpnopenflow.rsc.VpnInstance;
37import org.onosproject.evpnopenflow.rsc.VpnInstanceId;
38import org.onosproject.evpnopenflow.rsc.VpnPort;
39import org.onosproject.evpnopenflow.rsc.VpnPortId;
40import org.onosproject.evpnopenflow.rsc.baseport.BasePortService;
41import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigEvent;
42import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigListener;
43import org.onosproject.evpnopenflow.rsc.vpnafconfig.VpnAfConfigService;
44import org.onosproject.evpnopenflow.rsc.vpninstance.VpnInstanceService;
45import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortEvent;
46import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortListener;
47import org.onosproject.evpnopenflow.rsc.vpnport.VpnPortService;
48import org.onosproject.gluon.rsc.GluonConfig;
49import org.onosproject.incubator.net.resource.label.LabelResource;
50import org.onosproject.incubator.net.resource.label.LabelResourceAdminService;
51import org.onosproject.incubator.net.resource.label.LabelResourceId;
52import org.onosproject.incubator.net.resource.label.LabelResourceService;
53import org.onosproject.incubator.net.routing.EvpnInstanceName;
54import org.onosproject.incubator.net.routing.EvpnInstanceNextHop;
55import org.onosproject.incubator.net.routing.EvpnInstancePrefix;
56import org.onosproject.incubator.net.routing.EvpnInstanceRoute;
57import org.onosproject.incubator.net.routing.EvpnNextHop;
58import org.onosproject.incubator.net.routing.EvpnRoute;
59import org.onosproject.incubator.net.routing.EvpnRoute.Source;
60import org.onosproject.incubator.net.routing.EvpnRouteAdminService;
61import org.onosproject.incubator.net.routing.EvpnRouteEvent;
62import org.onosproject.incubator.net.routing.EvpnRouteListener;
63import org.onosproject.incubator.net.routing.EvpnRouteService;
64import org.onosproject.incubator.net.routing.EvpnRouteSet;
65import org.onosproject.incubator.net.routing.EvpnRouteStore;
66import org.onosproject.incubator.net.routing.Label;
67import org.onosproject.incubator.net.routing.RouteDistinguisher;
68import org.onosproject.incubator.net.routing.VpnRouteTarget;
69import org.onosproject.mastership.MastershipService;
70import org.onosproject.net.AnnotationKeys;
71import org.onosproject.net.Device;
72import org.onosproject.net.DeviceId;
73import org.onosproject.net.Host;
74import org.onosproject.net.Port;
75import org.onosproject.net.PortNumber;
76import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
77import org.onosproject.net.config.NetworkConfigEvent;
78import org.onosproject.net.config.NetworkConfigListener;
79import org.onosproject.net.config.NetworkConfigService;
80import org.onosproject.net.device.DeviceService;
81import org.onosproject.net.driver.DriverHandler;
82import org.onosproject.net.driver.DriverService;
83import org.onosproject.net.flow.DefaultTrafficSelector;
84import org.onosproject.net.flow.DefaultTrafficTreatment;
85import org.onosproject.net.flow.TrafficSelector;
86import org.onosproject.net.flow.TrafficTreatment;
87import org.onosproject.net.flow.instructions.ExtensionTreatment;
88import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
89import org.onosproject.net.flowobjective.DefaultForwardingObjective;
90import org.onosproject.net.flowobjective.FlowObjectiveService;
91import org.onosproject.net.flowobjective.ForwardingObjective;
92import org.onosproject.net.flowobjective.Objective;
93import org.onosproject.net.flowobjective.Objective.Operation;
94import org.onosproject.net.host.HostEvent;
95import org.onosproject.net.host.HostListener;
96import org.onosproject.net.host.HostService;
97import org.slf4j.Logger;
98
99import java.util.ArrayList;
100import java.util.Collection;
101import java.util.HashSet;
102import java.util.LinkedList;
103import java.util.List;
104import java.util.Set;
105
106import static com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type.Reference;
107import static org.onosproject.evpnopenflow.rsc.EvpnConstants.APP_ID;
108import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ARP_PRIORITY;
109import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ARP_RESPONSE;
110import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BASEPORT;
111import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BGP_EVPN_ROUTE_DELETE_START;
112import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BGP_EVPN_ROUTE_UPDATE_START;
113import static org.onosproject.evpnopenflow.rsc.EvpnConstants.BOTH;
114import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CANNOT_FIND_TUNNEL_PORT_DEVICE;
115import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CANT_FIND_CONTROLLER_DEVICE;
116import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CANT_FIND_VPN_INSTANCE;
117import static org.onosproject.evpnopenflow.rsc.EvpnConstants.CANT_FIND_VPN_PORT;
118import static org.onosproject.evpnopenflow.rsc.EvpnConstants.DELETE;
119import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_OPENFLOW_START;
120import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EVPN_OPENFLOW_STOP;
121import static org.onosproject.evpnopenflow.rsc.EvpnConstants.EXPORT_EXTCOMMUNITY;
122import static org.onosproject.evpnopenflow.rsc.EvpnConstants.FAILED_TO_SET_TUNNEL_DST;
123import static org.onosproject.evpnopenflow.rsc.EvpnConstants.GET_PRIVATE_LABEL;
124import static org.onosproject.evpnopenflow.rsc.EvpnConstants.HOST_DETECT;
125import static org.onosproject.evpnopenflow.rsc.EvpnConstants.HOST_VANISHED;
126import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IFACEID;
127import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IFACEID_OF_HOST_IS_NULL;
128import static org.onosproject.evpnopenflow.rsc.EvpnConstants.IMPORT_EXTCOMMUNITY;
129import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INVALID_EVENT_RECEIVED;
130import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INVALID_ROUTE_TARGET_TYPE;
131import static org.onosproject.evpnopenflow.rsc.EvpnConstants.INVALID_TARGET_RECEIVED;
132import static org.onosproject.evpnopenflow.rsc.EvpnConstants.MPLS_OUT_FLOWS;
133import static org.onosproject.evpnopenflow.rsc.EvpnConstants.NETWORK_CONFIG_EVENT_IS_RECEIVED;
134import static org.onosproject.evpnopenflow.rsc.EvpnConstants.NOT_MASTER_FOR_SPECIFIC_DEVICE;
135import static org.onosproject.evpnopenflow.rsc.EvpnConstants.RELEASE_LABEL_FAILED;
136import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_ADD_ARP_RULES;
137import static org.onosproject.evpnopenflow.rsc.EvpnConstants.ROUTE_REMOVE_ARP_RULES;
138import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SET;
139import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SLASH;
140import static org.onosproject.evpnopenflow.rsc.EvpnConstants.SWITCH_CHANNEL_ID;
141import static org.onosproject.evpnopenflow.rsc.EvpnConstants.TUNNEL_DST;
142import static org.onosproject.evpnopenflow.rsc.EvpnConstants.UPDATE;
143import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_AF_TARGET;
144import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_INSTANCE_TARGET;
145import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_BIND;
146import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_TARGET;
147import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VPN_PORT_UNBIND;
148import static org.onosproject.evpnopenflow.rsc.EvpnConstants.VXLAN;
149import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
150import static org.slf4j.LoggerFactory.getLogger;
151
152/**
153 * Implementation of the EVPN service.
154 */
155@Component(immediate = true)
156@Service
157public class EvpnManager implements EvpnService {
158 private final Logger log = getLogger(getClass());
159 private static final EthType.EtherType ARP_TYPE = EthType.EtherType.ARP;
160
161 protected ApplicationId appId;
162 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
163 protected HostService hostService;
164
165 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
166 protected CoreService coreService;
167
168 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
169 protected EvpnRouteService evpnRouteService;
170
171 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
172 protected EvpnRouteStore evpnRouteStore;
173
174 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
175 protected DeviceService deviceService;
176
177 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
178 protected EvpnRouteAdminService evpnRouteAdminService;
179
180 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
181 protected MastershipService mastershipService;
182
183 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
184 protected LabelResourceAdminService labelAdminService;
185
186 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
187 protected LabelResourceService labelService;
188
189 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
190 protected VpnInstanceService vpnInstanceService;
191
192 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
193 protected FlowObjectiveService flowObjectiveService;
194
195 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
196 protected DriverService driverService;
197
198 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
199 protected VpnPortService vpnPortService;
200
201 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
202 protected VpnAfConfigService vpnAfConfigService;
203
204 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
205 protected NetworkConfigService configService;
206
207 public Set<EvpnInstanceRoute> evpnInstanceRoutes = new HashSet<>();
208 private final HostListener hostListener = new InnerHostListener();
209 private final VpnPortListener vpnPortListner = new InnerVpnPortListener();
210 private final VpnAfConfigListener vpnAfConfigListener = new
211 InnerVpnAfConfigListener();
212 private final InternalRouteEventListener routeListener = new
213 InternalRouteEventListener();
214
215 private final NetworkConfigListener configListener = new
216 InternalNetworkConfigListener();
217
218 @Activate
219 public void activate() {
220 appId = coreService.registerApplication(APP_ID);
221 hostService.addListener(hostListener);
222 vpnPortService.addListener(vpnPortListner);
223 vpnAfConfigService.addListener(vpnAfConfigListener);
224 configService.addListener(configListener);
225 evpnRouteService.addListener(routeListener);
226
227 labelAdminService
228 .createGlobalPool(LabelResourceId.labelResourceId(1),
229 LabelResourceId.labelResourceId(1000));
230 log.info(EVPN_OPENFLOW_START);
231 }
232
233 @Deactivate
234 public void deactivate() {
235 hostService.removeListener(hostListener);
236 vpnPortService.removeListener(vpnPortListner);
237 vpnAfConfigService.removeListener(vpnAfConfigListener);
238 configService.removeListener(configListener);
239 log.info(EVPN_OPENFLOW_STOP);
240 }
241
242 @Override
243 public void onBgpEvpnRouteUpdate(EvpnRoute route) {
244 if (EvpnRoute.Source.LOCAL.equals(route.source())) {
245 return;
246 }
247 log.info(BGP_EVPN_ROUTE_UPDATE_START, route);
248 // deal with public route and transfer to private route
249 if (vpnInstanceService.getInstances().isEmpty()) {
250 log.info("unable to get instnaces from vpninstance");
251 return;
252 }
253
254 vpnInstanceService.getInstances().forEach(vpnInstance -> {
255 log.info("got instnaces from vpninstance but not entered here");
256 List<VpnRouteTarget> vpnImportRouteRt = new
257 LinkedList<>(vpnInstance.getImportRouteTargets());
258 List<VpnRouteTarget> expRt = route.exportRouteTarget();
259 List<VpnRouteTarget> similar = new LinkedList<>(expRt);
260 similar.retainAll(vpnImportRouteRt);
261
262 if (!similar.isEmpty()) {
263 EvpnInstancePrefix evpnPrefix = EvpnInstancePrefix
264 .evpnPrefix(route.prefixMac(), route.prefixIp());
265
266 EvpnInstanceNextHop evpnNextHop = EvpnInstanceNextHop
267 .evpnNextHop(route.ipNextHop(), route.label());
268
269 EvpnInstanceRoute evpnPrivateRoute = new
270 EvpnInstanceRoute(vpnInstance.vpnInstanceName(),
271 route.routeDistinguisher(),
272 vpnImportRouteRt,
273 route.exportRouteTarget(),
274 evpnPrefix,
275 evpnNextHop,
276 route.prefixIp(),
277 route.ipNextHop(),
278 route.label());
279
280 //update route in route subsystem
281 //TODO: added by shahid
282 evpnInstanceRoutes.add(evpnPrivateRoute);
283
284 }
285 });
286
287 deviceService.getAvailableDevices(Device.Type.SWITCH)
288 .forEach(device -> {
289 log.info("switch device is found");
290 Set<Host> hosts = getHostsByVpn(device, route);
291 for (Host h : hosts) {
292 addArpFlows(device.id(),
293 route,
294 Objective.Operation.ADD,
295 h);
296 ForwardingObjective.Builder objective =
297 getMplsOutBuilder(device.id(),
298 route,
299 h);
300 log.info(MPLS_OUT_FLOWS, h);
301 flowObjectiveService.forward(device.id(),
302 objective.add());
303 }
304 });
305 log.info("no switch device is found");
306 }
307
308 @Override
309 public void onBgpEvpnRouteDelete(EvpnRoute route) {
310 if (EvpnRoute.Source.LOCAL.equals(route.source())) {
311 return;
312 }
313 log.info(BGP_EVPN_ROUTE_DELETE_START, route);
314 // deal with public route deleted and transfer to private route
315 vpnInstanceService.getInstances().forEach(vpnInstance -> {
316 List<VpnRouteTarget> vpnRouteRt = new
317 LinkedList<>(vpnInstance.getImportRouteTargets());
318 List<VpnRouteTarget> localRt = route.exportRouteTarget();
319 List<VpnRouteTarget> similar = new LinkedList<>(localRt);
320 similar.retainAll(vpnRouteRt);
321
322 if (!similar.isEmpty()) {
323 EvpnInstancePrefix evpnPrefix = EvpnInstancePrefix
324 .evpnPrefix(route.prefixMac(), route.prefixIp());
325
326 EvpnInstanceNextHop evpnNextHop = EvpnInstanceNextHop
327 .evpnNextHop(route.ipNextHop(), route.label());
328
329 EvpnInstanceRoute evpnPrivateRoute = new
330 EvpnInstanceRoute(vpnInstance.vpnInstanceName(),
331 route.routeDistinguisher(),
332 vpnRouteRt,
333 route.exportRouteTarget(),
334 evpnPrefix,
335 evpnNextHop,
336 route.prefixIp(),
337 route.ipNextHop(),
338 route.label());
339 //TODO: Added by Shahid
340 //evpnRouteAdminService.withdraw(Sets.newHashSet
341 // (evpnPrivateRoute));
342
343 }
344 });
345 deviceService.getAvailableDevices(Device.Type.SWITCH)
346 .forEach(device -> {
347 Set<Host> hosts = getHostsByVpn(device, route);
348 for (Host h : hosts) {
349 addArpFlows(device.id(),
350 route,
351 Objective.Operation.REMOVE,
352 h);
353 ForwardingObjective.Builder objective
354 = getMplsOutBuilder(device.id(),
355 route,
356 h);
357 flowObjectiveService.forward(device.id(),
358 objective.remove());
359 }
360 });
361 }
362
363 private void addArpFlows(DeviceId deviceId,
364 EvpnRoute route,
365 Operation type,
366 Host host) {
367 DriverHandler handler = driverService.createHandler(deviceId);
368 TrafficSelector selector = DefaultTrafficSelector.builder()
369 .matchEthType(ARP_TYPE.ethType().toShort())
370 .matchArpTpa(route.prefixIp().address().getIp4Address())
371 .matchInPort(host.location().port()).build();
372
373 ExtensionTreatmentResolver resolver = handler
374 .behaviour(ExtensionTreatmentResolver.class);
375 ExtensionTreatment ethSrcToDst = resolver
376 .getExtensionInstruction(ExtensionTreatmentType
377 .ExtensionTreatmentTypes
378 .NICIRA_MOV_ETH_SRC_TO_DST
379 .type());
380 ExtensionTreatment arpShaToTha = resolver
381 .getExtensionInstruction(ExtensionTreatmentType
382 .ExtensionTreatmentTypes
383 .NICIRA_MOV_ARP_SHA_TO_THA
384 .type());
385 ExtensionTreatment arpSpaToTpa = resolver
386 .getExtensionInstruction(ExtensionTreatmentType
387 .ExtensionTreatmentTypes
388 .NICIRA_MOV_ARP_SPA_TO_TPA
389 .type());
390 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
391 .extension(ethSrcToDst, deviceId).setEthSrc(route.prefixMac())
392 .setArpOp(ARP_RESPONSE).extension(arpShaToTha, deviceId)
393 .extension(arpSpaToTpa, deviceId).setArpSha(route.prefixMac())
394 .setArpSpa(route.prefixIp().address().getIp4Address())
395 .setOutput(PortNumber.IN_PORT)
396 .build();
397
398 ForwardingObjective.Builder objective = DefaultForwardingObjective
399 .builder().withTreatment(treatment).withSelector(selector)
400 .fromApp(appId).withFlag(ForwardingObjective.Flag.SPECIFIC)
401 .withPriority(ARP_PRIORITY);
402 if (type.equals(Objective.Operation.ADD)) {
403 log.info(ROUTE_ADD_ARP_RULES);
404 flowObjectiveService.forward(deviceId, objective.add());
405 } else {
406 log.info(ROUTE_REMOVE_ARP_RULES);
407 flowObjectiveService.forward(deviceId, objective.remove());
408 }
409 }
410
411 private Set<Host> getHostsByVpn(Device device, EvpnRoute route) {
412 Set<Host> vpnHosts = Sets.newHashSet();
413 Set<Host> hosts = hostService.getConnectedHosts(device.id());
414 for (Host h : hosts) {
415 String ifaceId = h.annotations().value(IFACEID);
416 if (!vpnPortService.exists(VpnPortId.vpnPortId(ifaceId))) {
417 continue;
418 }
419
420 VpnPort vpnPort = vpnPortService
421 .getPort(VpnPortId.vpnPortId(ifaceId));
422 VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId();
423
424 VpnInstance vpnInstance = vpnInstanceService
425 .getInstance(vpnInstanceId);
426
427 List<VpnRouteTarget> expRt = route.exportRouteTarget();
428 List<VpnRouteTarget> similar = new LinkedList<>(expRt);
429 similar.retainAll(vpnInstance.getImportRouteTargets());
430 //TODO: currently checking for RT comparision.
431 //TODO: Need to check about RD comparision is really required.
432 //if (route.routeDistinguisher()
433 //.equals(vpnInstance.routeDistinguisher())) {
434 if (!similar.isEmpty()) {
435 vpnHosts.add(h);
436 }
437 }
438 return vpnHosts;
439 }
440
441 private ForwardingObjective.Builder getMplsOutBuilder(DeviceId deviceId,
442 EvpnRoute route,
443 Host h) {
444 DriverHandler handler = driverService.createHandler(deviceId);
445 ExtensionTreatmentResolver resolver = handler
446 .behaviour(ExtensionTreatmentResolver.class);
447 ExtensionTreatment treatment = resolver
448 .getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
449 try {
450 treatment.setPropertyValue(TUNNEL_DST, route.ipNextHop());
451 } catch (Exception e) {
452 log.error(FAILED_TO_SET_TUNNEL_DST, deviceId);
453 }
454 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
455 builder.extension(treatment, deviceId);
456 TrafficSelector selector = DefaultTrafficSelector.builder()
457 .matchInPort(h.location().port()).matchEthSrc(h.mac())
458 .matchEthDst(route.prefixMac()).build();
459
460 TrafficTreatment build = builder.pushMpls()
461 .setMpls(MplsLabel.mplsLabel(route.label().getLabel()))
462 .setOutput(getTunnlePort(deviceId)).build();
463
464 return DefaultForwardingObjective
465 .builder().withTreatment(build).withSelector(selector)
466 .fromApp(appId).withFlag(ForwardingObjective.Flag.SPECIFIC)
467 .withPriority(60000);
468
469 }
470
471 private ForwardingObjective.Builder getMplsInBuilder(DeviceId deviceId,
472 Host host,
473 Label label) {
474 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
475 TrafficSelector selector = DefaultTrafficSelector.builder()
476 .matchInPort(getTunnlePort(deviceId))
477 .matchEthType(EthType.EtherType.MPLS_UNICAST.ethType()
478 .toShort())
479 .matchMplsBos(true)
480 .matchMplsLabel(MplsLabel.mplsLabel(label.getLabel())).build();
481 TrafficTreatment treatment = builder.popMpls(EthType
482 .EtherType
483 .IPV4.ethType())
484 .setOutput(host.location().port()).build();
485 return DefaultForwardingObjective
486 .builder().withTreatment(treatment).withSelector(selector)
487 .fromApp(appId).withFlag(ForwardingObjective.Flag.SPECIFIC)
488 .withPriority(60000);
489 }
490
491 /**
492 * Get local tunnel ports.
493 *
494 * @param ports Iterable of Port
495 * @return Collection of PortNumber
496 */
497 private Collection<PortNumber> getLocalTunnelPorts(Iterable<Port>
498 ports) {
499 Collection<PortNumber> localTunnelPorts = new ArrayList<>();
500 if (ports != null) {
501 log.info("port value is not null {}", ports);
502 Sets.newHashSet(ports).stream()
503 .filter(p -> !p.number().equals(PortNumber.LOCAL))
504 .forEach(p -> {
505 log.info("number is not matched but no vxlan port");
506 if (p.annotations().value(AnnotationKeys.PORT_NAME)
507 .startsWith(VXLAN)) {
508 localTunnelPorts.add(p.number());
509 }
510 });
511 }
512 return localTunnelPorts;
513 }
514
515 private PortNumber getTunnlePort(DeviceId deviceId) {
516 Iterable<Port> ports = deviceService.getPorts(deviceId);
517 Collection<PortNumber> localTunnelPorts = getLocalTunnelPorts(ports);
518 if (localTunnelPorts.isEmpty()) {
519 log.error(CANNOT_FIND_TUNNEL_PORT_DEVICE, deviceId);
520 return null;
521 }
522 return localTunnelPorts.iterator().next();
523 }
524
525 private void setFlows(DeviceId deviceId, Host host, Label label,
526 List<VpnRouteTarget> rtImport,
527 Operation type) {
528 log.info("Set the flows to OVS");
529 ForwardingObjective.Builder objective = getMplsInBuilder(deviceId,
530 host,
531 label);
532 if (type.equals(Objective.Operation.ADD)) {
533 flowObjectiveService.forward(deviceId, objective.add());
534 } else {
535 flowObjectiveService.forward(deviceId, objective.remove());
536 }
537
538 // download remote flows if and only routes are present.
539 evpnRouteStore.getRouteTables().forEach(routeTableId -> {
540 Collection<EvpnRouteSet> routes
541 = evpnRouteStore.getRoutes(routeTableId);
542 if (routes != null) {
543 routes.forEach(route -> {
544 Collection<EvpnRoute> evpnRoutes = route.routes();
545 for (EvpnRoute evpnRoute : evpnRoutes) {
546 EvpnRoute evpnRouteTem = evpnRoute;
547 Set<Host> hostByMac = hostService
548 .getHostsByMac(evpnRouteTem
549 .prefixMac());
550
551 if (!hostByMac.isEmpty()
552 || (!(compareLists(rtImport, evpnRouteTem
553 .exportRouteTarget())))) {
554 log.info("Route target import/export is not matched");
555 continue;
556 }
557 log.info("Set the ARP flows");
558 addArpFlows(deviceId, evpnRouteTem, type, host);
559 ForwardingObjective.Builder build = getMplsOutBuilder(deviceId,
560 evpnRouteTem,
561 host);
562 log.info("Set the MPLS flows");
563 if (type.equals(Objective.Operation.ADD)) {
564 flowObjectiveService.forward(deviceId, build.add());
565 } else {
566 flowObjectiveService.forward(deviceId, build.remove());
567 }
568 }
569 });
570 }
571 });
572 }
573
574 /**
575 * comparison for tow lists.
576 *
577 * @param list1 import list
578 * @param list2 export list
579 * @return true or false
580 */
581 public static boolean compareLists(List<VpnRouteTarget> list1,
582 List<VpnRouteTarget> list2) {
583 if (list1 == null && list2 == null) {
584 return true;
585 }
586
587 if (list1 != null && list2 != null) {
588 if (list1.size() == list2.size()) {
589 for (VpnRouteTarget li1Long : list1) {
590 boolean isEqual = false;
591 for (VpnRouteTarget li2Long : list2) {
592 if (li1Long.equals(li2Long)) {
593 isEqual = true;
594 break;
595 }
596 }
597 if (!isEqual) {
598 return false;
599 }
600 }
601 } else {
602 return false;
603 }
604 } else {
605 return false;
606 }
607 return true;
608 }
609
610 @Override
611 public void onHostDetected(Host host) {
612 log.info(HOST_DETECT, host);
613 DeviceId deviceId = host.location().deviceId();
614 if (!mastershipService.isLocalMaster(deviceId)) {
615 log.info(NOT_MASTER_FOR_SPECIFIC_DEVICE);
616 return;
617 }
618
619 String ifaceId = host.annotations().value(IFACEID);
620 if (ifaceId == null) {
621 log.error(IFACEID_OF_HOST_IS_NULL);
622 return;
623 }
624 VpnPortId vpnPortId = VpnPortId.vpnPortId(ifaceId);
625 // Get VPN port id from EVPN app store
626 if (!vpnPortService.exists(vpnPortId)) {
627 log.info(CANT_FIND_VPN_PORT, ifaceId);
628 return;
629 }
630
631 VpnPort vpnPort = vpnPortService.getPort(vpnPortId);
632 VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId();
633 if (!vpnInstanceService.exists(vpnInstanceId)) {
634 log.info(CANT_FIND_VPN_INSTANCE, vpnInstanceId);
635 return;
636 }
637
638 Label privateLabel = applyLabel();
639 // create private route and get label
640 setPrivateRoute(host, vpnInstanceId, privateLabel,
641 Objective.Operation.ADD);
642 VpnInstance vpnInstance = vpnInstanceService.getInstance(vpnInstanceId);
643
644 List<VpnRouteTarget> rtImport
645 = new LinkedList<>(vpnInstance.getImportRouteTargets());
646 List<VpnRouteTarget> rtExport
647 = new LinkedList<>(vpnInstance.getExportRouteTargets());
648 //download flows
649 setFlows(deviceId, host, privateLabel, rtImport,
650 Objective.Operation.ADD);
651 }
652
653 /**
654 * update or withdraw evpn route from route admin service.
655 *
656 * @param host host
657 * @param vpnInstanceId vpn instance id
658 * @param privateLabel private label
659 * @param type operation type
660 */
661 private void setPrivateRoute(Host host, VpnInstanceId vpnInstanceId,
662 Label privateLabel,
663 Operation type) {
664 DeviceId deviceId = host.location().deviceId();
665 Device device = deviceService.getDevice(deviceId);
666 VpnInstance vpnInstance = vpnInstanceService.getInstance(vpnInstanceId);
667 RouteDistinguisher rd = vpnInstance.routeDistinguisher();
668 Set<VpnRouteTarget> importRouteTargets
669 = vpnInstance.getImportRouteTargets();
670 Set<VpnRouteTarget> exportRouteTargets
671 = vpnInstance.getExportRouteTargets();
672 EvpnInstanceName instanceName = vpnInstance.vpnInstanceName();
673 String url = device.annotations().value(SWITCH_CHANNEL_ID);
674 String controllerIp = url.substring(0, url.lastIndexOf(":"));
675
676 if (controllerIp == null) {
677 log.error(CANT_FIND_CONTROLLER_DEVICE, device.id().toString());
678 return;
679 }
680 IpAddress ipAddress = IpAddress.valueOf(controllerIp);
681 // create private route
682 EvpnInstanceNextHop evpnNextHop = EvpnInstanceNextHop
683 .evpnNextHop(ipAddress, privateLabel);
684 EvpnInstancePrefix evpnPrefix = EvpnInstancePrefix
685 .evpnPrefix(host.mac(), IpPrefix.valueOf(host.ipAddresses()
686 .iterator()
687 .next()
688 .getIp4Address(), 32));
689 EvpnInstanceRoute evpnPrivateRoute
690 = new EvpnInstanceRoute(instanceName,
691 rd,
692 new LinkedList<>(importRouteTargets),
693 new LinkedList<>(exportRouteTargets),
694 evpnPrefix,
695 evpnNextHop,
696 IpPrefix.valueOf(host.ipAddresses()
697 .iterator()
698 .next()
699 .getIp4Address(), 32),
700 ipAddress,
701 privateLabel);
702
703 // change to public route
704 EvpnRoute evpnRoute
705 = new EvpnRoute(Source.LOCAL,
706 host.mac(),
707 IpPrefix.valueOf(host.ipAddresses()
708 .iterator()
709 .next()
710 .getIp4Address(), 32),
711 ipAddress,
712 rd,
713 new LinkedList<>(importRouteTargets),
714 new LinkedList<>(exportRouteTargets),
715 privateLabel);
716 if (type.equals(Objective.Operation.ADD)) {
717 //evpnRouteAdminService.update(Sets.newHashSet(evpnPrivateRoute));
718 evpnInstanceRoutes.add(evpnPrivateRoute);
719 evpnRouteAdminService.update(Sets.newHashSet(evpnRoute));
720
721 } else {
722 //evpnRouteAdminService.withdraw(Sets.newHashSet(evpnPrivateRoute));
723 evpnInstanceRoutes.remove(evpnPrivateRoute);
724 evpnRouteAdminService.withdraw(Sets.newHashSet(evpnRoute));
725 }
726 }
727
728 /**
729 * Generate the label for evpn route from global pool.
730 */
731 private Label applyLabel() {
732 Collection<LabelResource> privateLabels = labelService
733 .applyFromGlobalPool(1);
734 Label privateLabel = Label.label(0);
735 if (!privateLabels.isEmpty()) {
736 privateLabel = Label.label(Integer.parseInt(
737 privateLabels.iterator().next()
738 .labelResourceId().toString()));
739 }
740 log.info(GET_PRIVATE_LABEL, privateLabel);
741 return privateLabel;
742 }
743
744 @Override
745 public void onHostVanished(Host host) {
746 log.info(HOST_VANISHED, host);
747 DeviceId deviceId = host.location().deviceId();
748 if (!mastershipService.isLocalMaster(deviceId)) {
749 return;
750 }
751 String ifaceId = host.annotations().value(IFACEID);
752 if (ifaceId == null) {
753 log.error(IFACEID_OF_HOST_IS_NULL);
754 return;
755 }
756 // Get info from Gluon Shim
757 VpnPort vpnPort = vpnPortService.getPort(VpnPortId.vpnPortId(ifaceId));
758 VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId();
759 if (!vpnInstanceService.exists(vpnInstanceId)) {
760 log.info(CANT_FIND_VPN_INSTANCE, vpnInstanceId);
761 return;
762 }
763 VpnInstance vpnInstance = vpnInstanceService.getInstance(vpnInstanceId);
764
765 Label label = releaseLabel(vpnInstance, host);
766 // create private route and get label
767 setPrivateRoute(host, vpnInstanceId, label, Objective.Operation.REMOVE);
768 // download flows
769 List<VpnRouteTarget> rtImport
770 = new LinkedList<>(vpnInstance.getImportRouteTargets());
771 List<VpnRouteTarget> rtExport
772 = new LinkedList<>(vpnInstance.getExportRouteTargets());
773 setFlows(deviceId, host, label, rtImport,
774 Objective.Operation.REMOVE);
775 }
776
777 /**
778 * Release the label from the evpn route.
779 *
780 * @param vpnInstance vpn instance
781 * @param host host
782 */
783 private Label releaseLabel(VpnInstance vpnInstance, Host host) {
784 EvpnInstanceName instanceName = vpnInstance.vpnInstanceName();
785
786 //Get all vpn-instance routes and check for label.
787 Label label = null;
788 for (EvpnInstanceRoute evpnInstanceRoute : evpnInstanceRoutes) {
789 if (evpnInstanceRoute.evpnInstanceName().equals(instanceName)) {
790 label = evpnInstanceRoute.getLabel();
791 // delete private route and get label ,change to public route
792 boolean isRelease
793 = labelService
794 .releaseToGlobalPool(
795 Sets.newHashSet(
796 LabelResourceId
797 .labelResourceId(label.getLabel())));
798 if (!isRelease) {
799 log.error(RELEASE_LABEL_FAILED, label.getLabel());
800 }
801 break;
802 }
803 }
804 return label;
805 }
806
807 private class InternalRouteEventListener implements EvpnRouteListener {
808
809 @Override
810 public void event(EvpnRouteEvent event) {
811 if (!(event.subject() instanceof EvpnRoute)) {
812 return;
813 }
814 EvpnRoute route = (EvpnRoute) event.subject();
815 if (EvpnRouteEvent.Type.ROUTE_ADDED == event.type()) {
816 onBgpEvpnRouteUpdate(route);
817 } else if (EvpnRouteEvent.Type.ROUTE_REMOVED == event.type()) {
818 onBgpEvpnRouteDelete(route);
819 }
820 }
821 }
822
823 private class InnerHostListener implements HostListener {
824
825 @Override
826 public void event(HostEvent event) {
827 Host host = event.subject();
828 if (HostEvent.Type.HOST_ADDED == event.type()) {
829 onHostDetected(host);
830 } else if (HostEvent.Type.HOST_REMOVED == event.type()) {
831 onHostVanished(host);
832 }
833 }
834
835 }
836
837 private class InnerVpnPortListener implements VpnPortListener {
838
839 @Override
840 public void event(VpnPortEvent event) {
841 VpnPort vpnPort = event.subject();
842 if (VpnPortEvent.Type.VPN_PORT_DELETE == event.type()) {
843 onVpnPortDelete(vpnPort);
844 } else if (VpnPortEvent.Type.VPN_PORT_SET == event.type()) {
845 onVpnPortSet(vpnPort);
846 }
847 }
848 }
849
850 @Override
851 public void onVpnPortDelete(VpnPort vpnPort) {
852 // delete the flows of this vpn
853 hostService.getHosts().forEach(host -> {
854 VpnPortId vpnPortId = vpnPort.id();
855 VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId();
856 if (!vpnInstanceService.exists(vpnInstanceId)) {
857 log.error(CANT_FIND_VPN_INSTANCE, vpnInstanceId);
858 return;
859 }
860 VpnInstance vpnInstance = vpnInstanceService
861 .getInstance(vpnInstanceId);
862 List<VpnRouteTarget> rtImport
863 = new LinkedList<>(vpnInstance.getImportRouteTargets());
864 List<VpnRouteTarget> rtExport
865 = new LinkedList<>(vpnInstance.getExportRouteTargets());
866
867 if (vpnPortId.vpnPortId()
868 .equals(host.annotations().value(IFACEID))) {
869 log.info(VPN_PORT_UNBIND);
870 Label label = releaseLabel(vpnInstance, host);
871 // create private route and get label
872 DeviceId deviceId = host.location().deviceId();
873 setPrivateRoute(host, vpnInstanceId, label,
874 Objective.Operation.REMOVE);
875 // download flows
876 setFlows(deviceId, host, label, rtImport,
877 Objective.Operation.REMOVE);
878 }
879 });
880 }
881
882 @Override
883 public void onVpnPortSet(VpnPort vpnPort) {
884 // delete the flows of this vpn
885 hostService.getHosts().forEach(host -> {
886 VpnPortId vpnPortId = vpnPort.id();
887 VpnInstanceId vpnInstanceId = vpnPort.vpnInstanceId();
888 VpnInstance vpnInstance = vpnInstanceService
889 .getInstance(vpnInstanceId);
890 if (vpnInstance == null) {
891 log.info("why vpn instance is null");
892 return;
893 }
894 List<VpnRouteTarget> rtImport
895 = new LinkedList<>(vpnInstance.getImportRouteTargets());
896/* List<VpnRouteTarget> rtExport
897 = new LinkedList<>(vpnInstance.getExportRouteTargets());*/
898
899 if (!vpnInstanceService.exists(vpnInstanceId)) {
900 log.error(CANT_FIND_VPN_INSTANCE, vpnInstanceId);
901 return;
902 }
903
904 if (vpnPortId.vpnPortId()
905 .equals(host.annotations().value(IFACEID))) {
906 log.info(VPN_PORT_BIND);
907 Label label = applyLabel();
908 // create private route and get label
909 DeviceId deviceId = host.location().deviceId();
910 setPrivateRoute(host, vpnInstanceId, label,
911 Objective.Operation.ADD);
912 // download flows
913 setFlows(deviceId, host, label, rtImport,
914 Objective.Operation.ADD);
915 }
916 });
917 }
918
919 /**
920 * process the gluon configuration and will update the configuration into
921 * vpn port service.
922 *
923 * @param action action
924 * @param key key
925 * @param value json node
926 */
927 private void processEtcdResponse(String action, String key, JsonNode
928 value) {
929 String[] list = key.split(SLASH);
930 String target = list[list.length - 2];
931 switch (target) {
932 case VPN_INSTANCE_TARGET:
933 VpnInstanceService vpnInstanceService
934 = DefaultServiceDirectory
935 .getService(VpnInstanceService.class);
936 vpnInstanceService.processGluonConfig(action, key, value);
937 break;
938 case VPN_PORT_TARGET:
939 VpnPortService vpnPortService = DefaultServiceDirectory
940 .getService(VpnPortService.class);
941 vpnPortService.processGluonConfig(action, key, value);
942 break;
943 case VPN_AF_TARGET:
944 VpnAfConfigService vpnAfConfigService =
945 DefaultServiceDirectory.getService(VpnAfConfigService
946 .class);
947 vpnAfConfigService.processGluonConfig(action, key, value);
948 break;
949 case BASEPORT:
950 BasePortService basePortService =
951 DefaultServiceDirectory.getService(BasePortService
952 .class);
953 basePortService.processGluonConfig(action, key, value);
954 break;
955 default:
956 log.info("why target type is invalid {}", target);
957 log.info(INVALID_TARGET_RECEIVED);
958 break;
959 }
960 }
961
962 /**
963 * parse the gluon configuration received from network config system.
964 *
965 * @param jsonNode json node
966 * @param key key
967 * @param action action
968 */
969 private void parseEtcdResponse(JsonNode jsonNode,
970 String key,
971 String action) {
972 JsonNode modifyValue = null;
973 if (action.equals(SET)) {
974 modifyValue = jsonNode.get(key);
975 }
976 processEtcdResponse(action, key, modifyValue);
977 }
978
979 /**
980 * Listener for network config events.
981 */
982 private class InternalNetworkConfigListener implements
983 NetworkConfigListener {
984
985 @Override
986 public void event(NetworkConfigEvent event) {
987 String subject;
988 log.info(NETWORK_CONFIG_EVENT_IS_RECEIVED, event.type());
989 if (!event.configClass().equals(GluonConfig.class)) {
990 return;
991 }
992 log.info("Event is received from network configuration {}", event
993 .type());
994 switch (event.type()) {
995 case CONFIG_UPDATED:
996 subject = (String) event.subject();
997 GluonConfig gluonConfig = configService
998 .getConfig(subject, GluonConfig.class);
999 JsonNode jsonNode = gluonConfig.node();
1000 parseEtcdResponse(jsonNode, subject, SET);
1001 break;
1002 case CONFIG_REMOVED:
1003 subject = (String) event.subject();
1004 parseEtcdResponse(null, subject, DELETE);
1005 break;
1006 default:
1007 log.info(INVALID_EVENT_RECEIVED);
1008 break;
1009 }
1010 }
1011 }
1012
1013 /**
1014 * update import and export route target information in route admin service.
1015 *
1016 * @param evpnInstanceName evpn instance name
1017 * @param exportRouteTargets export route targets
1018 * @param importRouteTargets import route targets
1019 * @param action action holds update or delete
1020 */
1021 private void updateImpExpRtInRoute(EvpnInstanceName evpnInstanceName,
1022 Set<VpnRouteTarget> exportRouteTargets,
1023 Set<VpnRouteTarget> importRouteTargets,
1024 String action) {
1025
1026 for (EvpnInstanceRoute evpnInstanceRoute : evpnInstanceRoutes) {
1027 if (evpnInstanceRoute.evpnInstanceName().equals(evpnInstanceName)) {
1028 evpnInstanceRoute
1029 .setExportRtList(new LinkedList<>(exportRouteTargets));
1030 evpnInstanceRoute
1031 .setImportRtList(new LinkedList<>(importRouteTargets));
1032 if (action.equals(UPDATE)) {
1033 evpnInstanceRoutes.add(evpnInstanceRoute);
1034 } else if (action.equals(DELETE)) {
1035 evpnInstanceRoutes.remove(evpnInstanceRoute);
1036 }
1037 //Get the public route and update route targets.
1038 EvpnNextHop evpnNextHop = EvpnNextHop
1039 .evpnNextHop(evpnInstanceRoute.getNextHopl(),
1040 evpnInstanceRoute.importRouteTarget(),
1041 evpnInstanceRoute.exportRouteTarget(),
1042 evpnInstanceRoute.getLabel());
1043 Collection<EvpnRoute> evpnPublicRoutes
1044 = evpnRouteStore.getRoutesForNextHop(evpnNextHop.nextHop());
1045 for (EvpnRoute pubRoute : evpnPublicRoutes) {
1046 EvpnRoute evpnPubRoute = pubRoute;
1047 if (evpnPubRoute.label().equals(evpnInstanceRoute
1048 .getLabel())) {
1049 evpnPubRoute
1050 .setExportRtList(new LinkedList<>(exportRouteTargets));
1051 evpnPubRoute
1052 .setImportRtList(new LinkedList<>(importRouteTargets));
1053 if (action.equals(UPDATE)) {
1054 evpnRouteAdminService.update(Sets.newHashSet(evpnPubRoute));
1055 } else if (action.equals(DELETE)) {
1056 evpnRouteAdminService
1057 .withdraw(Sets.newHashSet(evpnPubRoute));
1058 }
1059 }
1060 }
1061 }
1062 }
1063 }
1064
1065 /**
1066 * update or withdraw evpn route based on vpn af configuration.
1067 *
1068 * @param vpnAfConfig vpn af configuration
1069 * @param action action holds update or delete
1070 */
1071
1072 private void processEvpnRouteUpdate(VpnAfConfig vpnAfConfig,
1073 String action) {
1074 Collection<VpnInstance> instances
1075 = vpnInstanceService.getInstances();
1076 for (VpnInstance vpnInstance : instances) {
1077 Set<VpnRouteTarget> configRouteTargets
1078 = vpnInstance.getConfigRouteTargets();
1079 for (VpnRouteTarget vpnRouteTarget : configRouteTargets) {
1080 if (vpnRouteTarget.equals(vpnAfConfig.routeTarget())) {
1081 Set<VpnRouteTarget> exportRouteTargets
1082 = vpnInstance.getExportRouteTargets();
1083 Set<VpnRouteTarget> importRouteTargets
1084 = vpnInstance.getImportRouteTargets();
1085 String routeTargetType = vpnAfConfig.routeTargetType();
1086 if (action.equals(UPDATE)) {
1087 vpnInstanceService
1088 .updateImpExpRouteTargets(routeTargetType,
1089 exportRouteTargets,
1090 importRouteTargets,
1091 vpnRouteTarget);
1092 } else if (action.equals(DELETE)) {
1093 switch (routeTargetType) {
1094 case EXPORT_EXTCOMMUNITY:
1095 exportRouteTargets.remove(vpnRouteTarget);
1096 break;
1097 case IMPORT_EXTCOMMUNITY:
1098 importRouteTargets.remove(vpnRouteTarget);
1099 break;
1100 case BOTH:
1101 exportRouteTargets.remove(vpnRouteTarget);
1102 importRouteTargets.remove(vpnRouteTarget);
1103 break;
1104 default:
1105 log.info(INVALID_ROUTE_TARGET_TYPE);
1106 break;
1107 }
1108 }
1109 updateImpExpRtInRoute(vpnInstance.vpnInstanceName(),
1110 exportRouteTargets,
1111 importRouteTargets,
1112 action);
1113 }
1114 }
1115 }
1116 }
1117
1118 private class InnerVpnAfConfigListener implements VpnAfConfigListener {
1119
1120 @Override
1121 public void event(VpnAfConfigEvent event) {
1122 VpnAfConfig vpnAfConfig = event.subject();
1123 if (VpnAfConfigEvent.Type.VPN_AF_CONFIG_DELETE == event.type()) {
1124 processEvpnRouteUpdate(vpnAfConfig, DELETE);
1125 } else if (VpnAfConfigEvent.Type.VPN_AF_CONFIG_SET
1126 == event.type() || VpnAfConfigEvent.Type
1127 .VPN_AF_CONFIG_UPDATE == event.type()) {
1128 processEvpnRouteUpdate(vpnAfConfig, UPDATE);
1129 }
1130 }
1131 }
1132}