blob: 230902ab4e75c879fd946ded81af834d6fa8b1ee [file] [log] [blame]
Andreas Papazoisa9964ea2016-01-08 15:58:22 +02001/*
Brian O'Connor6547c0e2017-08-03 18:48:25 -07002 * Copyright 2016-present Open Networking Foundation
Andreas Papazoisa9964ea2016-01-08 15:58:22 +02003 *
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.sdxl3.impl;
18
Andreas Papazoisc2c45012016-01-20 14:26:11 +020019import com.google.common.collect.Lists;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onlab.packet.Ethernet;
27import org.onlab.packet.IPv4;
28import org.onlab.packet.IPv6;
29import org.onlab.packet.IpAddress;
30import org.onlab.packet.IpPrefix;
31import org.onlab.packet.TpPort;
Andreas Papazoise6aebaa2016-05-26 15:25:51 +030032import org.onlab.packet.VlanId;
Andreas Papazoisc2c45012016-01-20 14:26:11 +020033import org.onlab.util.ItemNotFoundException;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
Ray Milkey80432b42018-02-28 10:03:35 -080036import org.onosproject.net.intf.Interface;
37import org.onosproject.net.intf.InterfaceEvent;
38import org.onosproject.net.intf.InterfaceListener;
39import org.onosproject.net.intf.InterfaceService;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020040import org.onosproject.net.ConnectPoint;
41import org.onosproject.net.config.ConfigFactory;
42import org.onosproject.net.config.NetworkConfigEvent;
43import org.onosproject.net.config.NetworkConfigListener;
44import org.onosproject.net.config.NetworkConfigRegistry;
45import org.onosproject.net.config.NetworkConfigService;
46import org.onosproject.net.config.basics.SubjectFactories;
47import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.TrafficSelector;
50import org.onosproject.net.flow.TrafficTreatment;
51import org.onosproject.net.host.InterfaceIpAddress;
52import org.onosproject.net.intent.IntentUtils;
53import org.onosproject.net.intent.Key;
54import org.onosproject.net.intent.PointToPointIntent;
Ray Milkey80432b42018-02-28 10:03:35 -080055import org.onosproject.intentsync.IntentSynchronizationService;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020056import org.onosproject.routing.RoutingService;
57import org.onosproject.routing.config.BgpConfig;
Ray Milkey80432b42018-02-28 10:03:35 -080058import org.onosproject.routing.config.RoutingConfiguration;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020059import org.onosproject.sdxl3.SdxL3;
Andreas Papazoisc2c45012016-01-20 14:26:11 +020060import org.onosproject.sdxl3.SdxL3PeerService;
Andreas Papazoise6aebaa2016-05-26 15:25:51 +030061import org.onosproject.sdxl3.config.SdxParticipantsConfig;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020062import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
65import java.util.ArrayList;
66import java.util.Collection;
67import java.util.HashMap;
68import java.util.List;
69import java.util.Map;
Andreas Papazoisc2c45012016-01-20 14:26:11 +020070import java.util.Optional;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020071
72import static com.google.common.base.Preconditions.checkNotNull;
73
74/**
75 * Manages the connectivity requirements between peers.
76 */
77@Service
78@Component(immediate = true, enabled = false)
79public class SdxL3PeerManager implements SdxL3PeerService {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020080 private static final int PRIORITY_OFFSET = 1000;
81
82 private static final String SUFFIX_DST = "dst";
83 private static final String SUFFIX_SRC = "src";
84 private static final String SUFFIX_ICMP = "icmp";
85
86 private static final Logger log = LoggerFactory.getLogger(
Andreas Papazoisc2c45012016-01-20 14:26:11 +020087 SdxL3PeerManager.class);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020088
89 private static final short BGP_PORT = 179;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected CoreService coreService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected NetworkConfigService configService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected InterfaceService interfaceService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected IntentSynchronizationService intentSynchronizer;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected NetworkConfigRegistry registry;
105
106 private ConfigFactory configFactory =
107 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200108 CONFIG_CLASS, CONFIG_KEY) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200109 @Override
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300110 public SdxParticipantsConfig createConfig() {
111 return new SdxParticipantsConfig();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200112 }
113 };
114
115 private ApplicationId sdxAppId;
116 private ApplicationId routerAppId;
117
118 private final Map<Key, PointToPointIntent> peerIntents = new HashMap<>();
119
120 private final InternalNetworkConfigListener configListener
121 = new InternalNetworkConfigListener();
122
Andreas Papazois1f941912016-07-01 11:48:12 +0300123 private final InternalInterfaceListener interfaceListener
124 = new InternalInterfaceListener();
125
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200126 @Activate
127 public void activate() {
Ray Milkey80432b42018-02-28 10:03:35 -0800128 sdxAppId = coreService.registerApplication(SdxL3.SDX_L3_APP);
129 routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
130
131 RoutingConfiguration.register(registry);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200132
133 registry.registerConfigFactory(configFactory);
134
135 configService.addListener(configListener);
Andreas Papazois1f941912016-07-01 11:48:12 +0300136 interfaceService.addListener(interfaceListener);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200137
138 setUpConnectivity();
139
140 log.info("Connectivity with BGP peers established");
141 }
142
143 @Deactivate
144 public void deactivate() {
145 configService.removeListener(configListener);
Andreas Papazois1f941912016-07-01 11:48:12 +0300146 interfaceService.removeListener(interfaceListener);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200147
148 log.info("Connectivity with BGP peers stopped");
149 }
150
151 /**
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200152 * Adds details for a BGP peer to the SDX-L3 configuration.
153 *
154 * @param peerName Peer name
155 * @param peerAddress Peer IP address
156 * @param port Connection point with peer
157 * @param interfaceName Name of the interface configured on port
158 */
159 @Override
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300160 public void addPeerDetails(String peerName,
161 IpAddress peerAddress,
162 ConnectPoint port,
163 String interfaceName) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200164
165 BgpConfig bgpConfig = getBgpConfig();
166 if (bgpConfig == null) {
167 throw new ItemNotFoundException("BGP configuration not found");
168 }
169
170 if (!peerAddressExists(bgpConfig, peerAddress)) {
171 throw new ItemNotFoundException("Peer IP not found");
172 }
173
174 Interface peerInterface = getInterface(port, interfaceName);
175 if (peerInterface == null) {
176 throw new ItemNotFoundException("Interface not found");
177 }
178
179 if (!interfaceSubnetIncludesIp(peerInterface, peerAddress)) {
180 throw new IllegalArgumentException("Interface not configured for IP "
181 + peerAddress);
182 }
183
184 Interface confInterface = getConfiguredInterfaceForPeer(peerAddress);
185 if (confInterface != null) {
186 if (confInterface.equals(peerInterface)) {
187 // Do nothing since the association exists.
188 return;
189 } else {
190 // The peer is associated with another interface.
191 throw new IllegalArgumentException("Peer details already exist");
192 }
193 }
194
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300195 SdxParticipantsConfig peersConfig =
196 configService.addConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200197 if (peerName != null && peerNameExists(peersConfig, peerName)) {
198 throw new IllegalArgumentException("Peer name in use");
199 }
200
201 addPeerToConf(peersConfig, peerName, peerAddress, port, interfaceName);
202 configService.
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300203 applyConfig(sdxAppId, SdxParticipantsConfig.class, peersConfig.node());
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200204 }
205
206 /**
207 * Removes details for a BGP peer to the SDX-L3 configuration.
208 *
209 * @param peerAddress Peer IP address
210 */
211 @Override
212 public void removePeerDetails(IpAddress peerAddress) {
213 BgpConfig bgpConfig = getBgpConfig();
214 if (bgpConfig == null) {
215 throw new ItemNotFoundException("BGP configuration not found");
216 }
217
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300218 SdxParticipantsConfig peersConfig =
219 configService.addConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200220
221 if (peersConfig.getPeerForIp(peerAddress) == null) {
222 throw new ItemNotFoundException("Peer details not found");
223 }
224
225 removePeerFromConf(peersConfig, peerAddress);
226 configService.applyConfig(sdxAppId,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300227 SdxParticipantsConfig.class,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200228 peersConfig.node());
229 }
230
231 /**
232 * Returns BGP configuration has been specified and any BGP speaker
233 * exists in this configuration, else null is returned.
234 *
235 * @return BGP configuration or null
236 */
237 private BgpConfig getBgpConfig() {
238 BgpConfig bgpConfig = configService.
239 getConfig(routerAppId, BgpConfig.class);
240
241 if (bgpConfig == null || bgpConfig.bgpSpeakers().isEmpty()) {
242 return null;
243 }
244 return bgpConfig;
245 }
246
247 private Interface getInterface(ConnectPoint port, String interfaceName) {
248 Optional<Interface> interfaceMatch = interfaceService
249 .getInterfacesByPort(port)
250 .stream()
251 .filter(intf -> intf.name().equals(interfaceName))
252 .findFirst();
253 if (!interfaceMatch.isPresent()) {
254 // No such interface name configured for given connectPoint
255 return null;
256 }
257 return interfaceMatch.get();
258 }
259
Andreas Papazoisf0ec25b2016-02-05 14:20:06 +0200260 private boolean interfaceSubnetIncludesIp(Interface peerInterface, IpAddress peerAddress) {
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300261 if (peerInterface.ipAddressesList().stream()
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200262 .anyMatch(intfIp -> intfIp.subnetAddress().
263 contains(peerAddress))) {
264 // Interface configured subnet not including peer address
265 return true;
266 }
267 return false;
268 }
269
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300270 private boolean peerNameExists(SdxParticipantsConfig config, String peerName) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200271 if (config.getPeerForName(Optional.of(peerName)) == null) {
272 return false;
273 }
274 return true;
275 }
276
277 /**
278 * Adds the peer to the SdxProvidersConfig .
279 *
280 * @param peersConfig the BGP peers configuration
281 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300282 private void addPeerToConf(SdxParticipantsConfig peersConfig, String peerName,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200283 IpAddress peerAddress, ConnectPoint port,
284 String interfaceName) {
285 log.debug("Adding peer with IP to configuration: {}", peerAddress);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300286 SdxParticipantsConfig.PeerConfig peer = new SdxParticipantsConfig.
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200287 PeerConfig(Optional.ofNullable(peerName), peerAddress,
288 port, interfaceName);
289
290 peersConfig.addPeer(peer);
291 }
292
293 /**
294 * Removes the speaker from the BgpConfig service.
295 *
296 * @param peersConfig the BGP peeers configuration
297 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300298 private void removePeerFromConf(SdxParticipantsConfig peersConfig,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200299 IpAddress peerAddress) {
300 log.debug("Removing peer details from configuration: {}",
301 peerAddress.toString());
302 peersConfig.removePeer(peerAddress);
303 }
304
305 /**
306 * Returns true if a given IP address has been specified as a BGP peer
307 * address in the network configuration.
308 *
Andreas Papazoisf0ec25b2016-02-05 14:20:06 +0200309 * @param bgpConfig BGP configuration
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200310 * @param peerAddress IP address of peer
311 * @return whether address has been specified for a peer or not
312 */
313 private Boolean peerAddressExists(BgpConfig bgpConfig,
314 IpAddress peerAddress) {
315 List<IpAddress> peeringAddresses =
316 getPeerAddresses(bgpConfig);
317 if (!peeringAddresses.contains(peerAddress)) {
318 return false;
319 }
320 return true;
321 }
322
323 private Interface getConfiguredInterfaceForPeer(IpAddress peerAddress) {
324 if (sdxAppId == null) {
325 return null;
326 }
327
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300328 SdxParticipantsConfig config = configService.getConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200329 if (config == null) {
330 return null;
331 }
332
333 ConnectPoint port = config.getPortForPeer(peerAddress);
334 String intfName = config.getInterfaceNameForPeer(peerAddress);
335 if (port != null && intfName != null) {
336 Optional<Interface> interfaceMatch = interfaceService
337 .getInterfacesByPort(port)
338 .stream()
339 .filter(intf -> intf.name().equals(intfName))
340 .findFirst();
341 if (interfaceMatch.isPresent()) {
342 return interfaceMatch.get();
343 }
344 }
345 return null;
346 }
347
348 /**
349 * Returns the interface used as connection point to peer.
350 *
351 * @param peerAddress IP address of peer
352 * @return interface to the peer
353 */
354 @Override
355 public Interface getInterfaceForPeer(IpAddress peerAddress) {
356 Interface peeringInterface = getConfiguredInterfaceForPeer(peerAddress);
357 if (peeringInterface == null) {
358 peeringInterface = interfaceService.getMatchingInterface(peerAddress);
359 }
360 return peeringInterface;
361 }
362
363 @Override
364 public List<IpAddress> getPeerAddresses(BgpConfig bgpConfig) {
365 List<IpAddress> peeringAddresses = Lists.newArrayList();
366
367 List<BgpConfig.BgpSpeakerConfig> bgpSpeakers =
368 Lists.newArrayList(bgpConfig.bgpSpeakers());
369 bgpSpeakers.forEach(
370 s -> peeringAddresses.addAll(s.peers()));
371
372 return peeringAddresses;
373 }
374
375 /**
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200376 * Sets up paths to establish connectivity between all internal
377 * BGP speakers and external BGP peers.
378 */
379 private void setUpConnectivity() {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200380 BgpConfig config = getBgpConfig();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200381 if (config == null) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200382 log.warn("No BGP configuration found");
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200383 return;
384 }
385
386 Map<Key, PointToPointIntent> existingIntents = new HashMap<>(peerIntents);
387
388 for (BgpConfig.BgpSpeakerConfig bgpSpeaker : config.bgpSpeakers()) {
389 log.debug("Start to set up BGP paths for BGP speaker: {}",
390 bgpSpeaker);
391
392 buildSpeakerIntents(bgpSpeaker).forEach(i -> {
393 PointToPointIntent intent = existingIntents.remove(i.key());
394 if (intent == null || !IntentUtils.intentsAreEqual(i, intent)) {
395 peerIntents.put(i.key(), i);
396 intentSynchronizer.submit(i);
397 }
398 });
399 }
400
401 // Remove any remaining intents that we used to have that we don't need
402 // anymore
403 existingIntents.values().forEach(i -> {
404 peerIntents.remove(i.key());
405 intentSynchronizer.withdraw(i);
406 });
407 }
408
409 private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) {
410 List<PointToPointIntent> intents = new ArrayList<>();
411
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300412 // Get the BGP Speaker VLAN Id
413 VlanId bgpSpeakerVlanId = speaker.vlan();
414
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200415 for (IpAddress peerAddress : speaker.peers()) {
416 Interface peeringInterface = getInterfaceForPeer(peerAddress);
417
418 if (peeringInterface == null) {
419 log.debug("No peering interface found for peer {} on speaker {}",
420 peerAddress, speaker);
421 continue;
422 }
423
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300424 IpAddress bgpSpeakerAddress = null;
425 for (InterfaceIpAddress address : peeringInterface.ipAddressesList()) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200426 if (address.subnetAddress().contains(peerAddress)) {
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300427 bgpSpeakerAddress = address.ipAddress();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200428 break;
429 }
430 }
431
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300432 checkNotNull(bgpSpeakerAddress);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200433
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300434 VlanId peerVlanId = peeringInterface.vlan();
435
436 intents.addAll(buildIntents(speaker.connectPoint(), bgpSpeakerVlanId,
437 bgpSpeakerAddress,
438 peeringInterface.connectPoint(),
439 peerVlanId,
440 peerAddress));
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200441 }
442
443 return intents;
444 }
445
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200446 /**
Andreas Papazois1f941912016-07-01 11:48:12 +0300447 * Builds the required intents between a BGP speaker and an external router.
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200448 *
Andreas Papazois1f941912016-07-01 11:48:12 +0300449 * @param portOne the BGP speaker connect point
450 * @param vlanOne the BGP speaker VLAN
451 * @param ipOne the BGP speaker IP address
452 * @param portTwo the external BGP peer connect point
453 * @param vlanTwo the external BGP peer VLAN
454 * @param ipTwo the external BGP peer IP address
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200455 * @return the intents to install
456 */
457 private Collection<PointToPointIntent> buildIntents(ConnectPoint portOne,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300458 VlanId vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200459 IpAddress ipOne,
460 ConnectPoint portTwo,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300461 VlanId vlanTwo,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200462 IpAddress ipTwo) {
463
464 List<PointToPointIntent> intents = new ArrayList<>();
465
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300466 TrafficTreatment.Builder treatmentToPeer = DefaultTrafficTreatment.builder();
467 TrafficTreatment.Builder treatmentToSpeaker = DefaultTrafficTreatment.builder();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200468 TrafficSelector selector;
469 Key key;
470
471 byte tcpProtocol;
472 byte icmpProtocol;
473
474 if (ipOne.isIp4()) {
475 tcpProtocol = IPv4.PROTOCOL_TCP;
476 icmpProtocol = IPv4.PROTOCOL_ICMP;
477 } else {
478 tcpProtocol = IPv6.PROTOCOL_TCP;
479 icmpProtocol = IPv6.PROTOCOL_ICMP6;
480 }
481
Andreas Papazois1f941912016-07-01 11:48:12 +0300482 // Add VLAN treatment for traffic going from BGP speaker to BGP peer
Andreas papazois47deeaa2016-10-18 12:19:52 +0300483 treatmentToPeer = applyVlanTreatment(vlanOne, vlanTwo, treatmentToPeer);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300484
485 // Path from BGP speaker to BGP peer matching destination TCP port 179
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200486 selector = buildSelector(tcpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300487 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200488 ipOne,
489 ipTwo,
490 null,
491 BGP_PORT);
492
493 key = buildKey(ipOne, ipTwo, SUFFIX_DST);
494
495 intents.add(PointToPointIntent.builder()
496 .appId(sdxAppId)
497 .key(key)
498 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300499 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200500 .ingressPoint(portOne)
501 .egressPoint(portTwo)
502 .priority(PRIORITY_OFFSET)
503 .build());
504
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300505 // Path from BGP speaker to BGP peer matching source TCP port 179
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200506 selector = buildSelector(tcpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300507 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200508 ipOne,
509 ipTwo,
510 BGP_PORT,
511 null);
512
513 key = buildKey(ipOne, ipTwo, SUFFIX_SRC);
514
515 intents.add(PointToPointIntent.builder()
516 .appId(sdxAppId)
517 .key(key)
518 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300519 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200520 .ingressPoint(portOne)
521 .egressPoint(portTwo)
522 .priority(PRIORITY_OFFSET)
523 .build());
524
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200525 // ICMP path from BGP speaker to BGP peer
526 selector = buildSelector(icmpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300527 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200528 ipOne,
529 ipTwo,
530 null,
531 null);
532
533 key = buildKey(ipOne, ipTwo, SUFFIX_ICMP);
534
535 intents.add(PointToPointIntent.builder()
536 .appId(sdxAppId)
537 .key(key)
538 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300539 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200540 .ingressPoint(portOne)
541 .egressPoint(portTwo)
542 .priority(PRIORITY_OFFSET)
543 .build());
544
Andreas Papazois1f941912016-07-01 11:48:12 +0300545 // Add VLAN treatment for traffic going from BGP peer to BGP speaker
Andreas papazois47deeaa2016-10-18 12:19:52 +0300546 treatmentToSpeaker = applyVlanTreatment(vlanTwo, vlanOne, treatmentToSpeaker);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300547
548 // Path from BGP peer to BGP speaker matching destination TCP port 179
549 selector = buildSelector(tcpProtocol,
550 vlanTwo,
551 ipTwo,
552 ipOne,
553 null,
554 BGP_PORT);
555
556 key = buildKey(ipTwo, ipOne, SUFFIX_DST);
557
558 intents.add(PointToPointIntent.builder()
559 .appId(sdxAppId)
560 .key(key)
561 .selector(selector)
562 .treatment(treatmentToSpeaker.build())
563 .ingressPoint(portTwo)
564 .egressPoint(portOne)
565 .priority(PRIORITY_OFFSET)
566 .build());
567
568 // Path from BGP peer to BGP speaker matching source TCP port 179
569 selector = buildSelector(tcpProtocol,
570 vlanTwo,
571 ipTwo,
572 ipOne,
573 BGP_PORT,
574 null);
575
576 key = buildKey(ipTwo, ipOne, SUFFIX_SRC);
577
578 intents.add(PointToPointIntent.builder()
579 .appId(sdxAppId)
580 .key(key)
581 .selector(selector)
582 .treatment(treatmentToSpeaker.build())
583 .ingressPoint(portTwo)
584 .egressPoint(portOne)
585 .priority(PRIORITY_OFFSET)
586 .build());
587
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200588 // ICMP path from BGP peer to BGP speaker
589 selector = buildSelector(icmpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300590 vlanTwo,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200591 ipTwo,
592 ipOne,
593 null,
594 null);
595
596 key = buildKey(ipTwo, ipOne, SUFFIX_ICMP);
597
598 intents.add(PointToPointIntent.builder()
599 .appId(sdxAppId)
600 .key(key)
601 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300602 .treatment(treatmentToSpeaker.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200603 .ingressPoint(portTwo)
604 .egressPoint(portOne)
605 .priority(PRIORITY_OFFSET)
606 .build());
607
608 return intents;
609 }
610
611 /**
612 * Builds a traffic selector based on the set of input parameters.
613 *
614 * @param ipProto IP protocol
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300615 * @param ingressVlanId VLAN Id configured on the ingress interface
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200616 * @param srcIp source IP address
617 * @param dstIp destination IP address
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300618 * @param srcTcpPort source TCP port, or null if shouldn't be set
619 * @param dstTcpPort destination TCP port, or null if shouldn't be set
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200620 * @return the new traffic selector
621 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300622 private TrafficSelector buildSelector(byte ipProto,
623 VlanId ingressVlanId,
624 IpAddress srcIp,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200625 IpAddress dstIp, Short srcTcpPort,
626 Short dstTcpPort) {
627 TrafficSelector.Builder builder = DefaultTrafficSelector.builder().matchIPProtocol(ipProto);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300628 // Match on any VLAN Id if a VLAN Id configured on the ingress interface
629 if (!ingressVlanId.equals(VlanId.NONE)) {
630 builder.matchVlanId(VlanId.ANY);
631 }
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200632
633 if (dstIp.isIp4()) {
634 builder.matchEthType(Ethernet.TYPE_IPV4)
635 .matchIPSrc(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET_MASK_LENGTH))
636 .matchIPDst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET_MASK_LENGTH));
637 } else {
638 builder.matchEthType(Ethernet.TYPE_IPV6)
639 .matchIPv6Src(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET6_MASK_LENGTH))
640 .matchIPv6Dst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET6_MASK_LENGTH));
641 }
642
643 if (srcTcpPort != null) {
644 builder.matchTcpSrc(TpPort.tpPort(srcTcpPort));
645 }
646
647 if (dstTcpPort != null) {
648 builder.matchTcpDst(TpPort.tpPort(dstTcpPort));
649 }
650
651 return builder.build();
652 }
653
654 /**
655 * Builds an intent Key for a point-to-point intent based off the source
656 * and destination IP address, as well as a suffix String to distinguish
657 * between different types of intents between the same source and
658 * destination.
659 *
660 * @param srcIp source IP address
661 * @param dstIp destination IP address
662 * @param suffix suffix string
663 * @return intent key
664 */
665 private Key buildKey(IpAddress srcIp, IpAddress dstIp, String suffix) {
666 String keyString = new StringBuilder()
667 .append(srcIp.toString())
668 .append("-")
669 .append(dstIp.toString())
670 .append("-")
671 .append(suffix)
672 .toString();
673
674 return Key.of(keyString, sdxAppId);
675 }
676
Andreas papazois47deeaa2016-10-18 12:19:52 +0300677 /**
678 * Adds the VLAN Id treatment before building the intents, depending on how
679 * the VLAN Ids of the BGP speakers and the BGP peers are configured.
680 */
681 private TrafficTreatment.Builder applyVlanTreatment(VlanId vlanOne,
682 VlanId vlanTwo,
683 TrafficTreatment.Builder treatment) {
684 if (!vlanOne.equals(vlanTwo)) {
685 // VLANs are different. Do some VLAN treatment
686 if (vlanTwo.equals(VlanId.NONE)) {
687 // VLAN two is none. VLAN one is set. Do a pop
688 treatment.popVlan();
689 } else {
690 // Either both VLANs are set or vlanOne is not
691 if (vlanOne.equals(VlanId.NONE)) {
692 // VLAN one is none. VLAN two is set. Push the VLAN header
693 treatment.pushVlan();
694 }
695 // Set the VLAN Id to the egress VLAN Id
696 treatment.setVlanId(vlanTwo);
697 }
698 }
699 return treatment;
700 }
701
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200702 private class InternalNetworkConfigListener implements NetworkConfigListener {
703
704 @Override
705 public void event(NetworkConfigEvent event) {
706 switch (event.type()) {
707 case CONFIG_REGISTERED:
708 break;
709 case CONFIG_UNREGISTERED:
710 break;
711 case CONFIG_ADDED:
712 case CONFIG_UPDATED:
713 case CONFIG_REMOVED:
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200714 if (event.configClass() == RoutingService.CONFIG_CLASS ||
715 event.configClass() == CONFIG_CLASS) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200716 setUpConnectivity();
717 }
718 break;
719 default:
720 break;
721 }
722 }
723 }
724
Andreas Papazois1f941912016-07-01 11:48:12 +0300725 private class InternalInterfaceListener implements InterfaceListener {
726 @Override
727 public void event(InterfaceEvent event) {
728 switch (event.type()) {
729 case INTERFACE_ADDED:
730 case INTERFACE_UPDATED:
731 case INTERFACE_REMOVED:
732 setUpConnectivity();
733 break;
734 default:
735 break;
736 }
737 }
738 }
739
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200740}