blob: 4bd31c22320e5ecc7f1d1b6f7de3e40a55452bbe [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;
36import org.onosproject.incubator.net.intf.Interface;
Andreas Papazois1f941912016-07-01 11:48:12 +030037import org.onosproject.incubator.net.intf.InterfaceEvent;
38import org.onosproject.incubator.net.intf.InterfaceListener;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020039import org.onosproject.incubator.net.intf.InterfaceService;
40import 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;
55import org.onosproject.routing.IntentSynchronizationService;
56import org.onosproject.routing.RoutingService;
57import org.onosproject.routing.config.BgpConfig;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020058import org.onosproject.sdxl3.SdxL3;
Andreas Papazoisc2c45012016-01-20 14:26:11 +020059import org.onosproject.sdxl3.SdxL3PeerService;
Andreas Papazoise6aebaa2016-05-26 15:25:51 +030060import org.onosproject.sdxl3.config.SdxParticipantsConfig;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020061import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
64import java.util.ArrayList;
65import java.util.Collection;
66import java.util.HashMap;
67import java.util.List;
68import java.util.Map;
Andreas Papazoisc2c45012016-01-20 14:26:11 +020069import java.util.Optional;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020070
71import static com.google.common.base.Preconditions.checkNotNull;
72
73/**
74 * Manages the connectivity requirements between peers.
75 */
76@Service
77@Component(immediate = true, enabled = false)
78public class SdxL3PeerManager implements SdxL3PeerService {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020079 private static final int PRIORITY_OFFSET = 1000;
80
81 private static final String SUFFIX_DST = "dst";
82 private static final String SUFFIX_SRC = "src";
83 private static final String SUFFIX_ICMP = "icmp";
84
85 private static final Logger log = LoggerFactory.getLogger(
Andreas Papazoisc2c45012016-01-20 14:26:11 +020086 SdxL3PeerManager.class);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020087
88 private static final short BGP_PORT = 179;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected CoreService coreService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected NetworkConfigService configService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected InterfaceService interfaceService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected IntentSynchronizationService intentSynchronizer;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected NetworkConfigRegistry registry;
104
105 private ConfigFactory configFactory =
106 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200107 CONFIG_CLASS, CONFIG_KEY) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200108 @Override
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300109 public SdxParticipantsConfig createConfig() {
110 return new SdxParticipantsConfig();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200111 }
112 };
113
114 private ApplicationId sdxAppId;
115 private ApplicationId routerAppId;
116
117 private final Map<Key, PointToPointIntent> peerIntents = new HashMap<>();
118
119 private final InternalNetworkConfigListener configListener
120 = new InternalNetworkConfigListener();
121
Andreas Papazois1f941912016-07-01 11:48:12 +0300122 private final InternalInterfaceListener interfaceListener
123 = new InternalInterfaceListener();
124
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200125 @Activate
126 public void activate() {
127 sdxAppId = coreService.getAppId(SdxL3.SDX_L3_APP);
128 routerAppId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
129
130 registry.registerConfigFactory(configFactory);
131
132 configService.addListener(configListener);
Andreas Papazois1f941912016-07-01 11:48:12 +0300133 interfaceService.addListener(interfaceListener);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200134
135 setUpConnectivity();
136
137 log.info("Connectivity with BGP peers established");
138 }
139
140 @Deactivate
141 public void deactivate() {
142 configService.removeListener(configListener);
Andreas Papazois1f941912016-07-01 11:48:12 +0300143 interfaceService.removeListener(interfaceListener);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200144
145 log.info("Connectivity with BGP peers stopped");
146 }
147
148 /**
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200149 * Adds details for a BGP peer to the SDX-L3 configuration.
150 *
151 * @param peerName Peer name
152 * @param peerAddress Peer IP address
153 * @param port Connection point with peer
154 * @param interfaceName Name of the interface configured on port
155 */
156 @Override
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300157 public void addPeerDetails(String peerName,
158 IpAddress peerAddress,
159 ConnectPoint port,
160 String interfaceName) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200161
162 BgpConfig bgpConfig = getBgpConfig();
163 if (bgpConfig == null) {
164 throw new ItemNotFoundException("BGP configuration not found");
165 }
166
167 if (!peerAddressExists(bgpConfig, peerAddress)) {
168 throw new ItemNotFoundException("Peer IP not found");
169 }
170
171 Interface peerInterface = getInterface(port, interfaceName);
172 if (peerInterface == null) {
173 throw new ItemNotFoundException("Interface not found");
174 }
175
176 if (!interfaceSubnetIncludesIp(peerInterface, peerAddress)) {
177 throw new IllegalArgumentException("Interface not configured for IP "
178 + peerAddress);
179 }
180
181 Interface confInterface = getConfiguredInterfaceForPeer(peerAddress);
182 if (confInterface != null) {
183 if (confInterface.equals(peerInterface)) {
184 // Do nothing since the association exists.
185 return;
186 } else {
187 // The peer is associated with another interface.
188 throw new IllegalArgumentException("Peer details already exist");
189 }
190 }
191
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300192 SdxParticipantsConfig peersConfig =
193 configService.addConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200194 if (peerName != null && peerNameExists(peersConfig, peerName)) {
195 throw new IllegalArgumentException("Peer name in use");
196 }
197
198 addPeerToConf(peersConfig, peerName, peerAddress, port, interfaceName);
199 configService.
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300200 applyConfig(sdxAppId, SdxParticipantsConfig.class, peersConfig.node());
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200201 }
202
203 /**
204 * Removes details for a BGP peer to the SDX-L3 configuration.
205 *
206 * @param peerAddress Peer IP address
207 */
208 @Override
209 public void removePeerDetails(IpAddress peerAddress) {
210 BgpConfig bgpConfig = getBgpConfig();
211 if (bgpConfig == null) {
212 throw new ItemNotFoundException("BGP configuration not found");
213 }
214
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300215 SdxParticipantsConfig peersConfig =
216 configService.addConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200217
218 if (peersConfig.getPeerForIp(peerAddress) == null) {
219 throw new ItemNotFoundException("Peer details not found");
220 }
221
222 removePeerFromConf(peersConfig, peerAddress);
223 configService.applyConfig(sdxAppId,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300224 SdxParticipantsConfig.class,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200225 peersConfig.node());
226 }
227
228 /**
229 * Returns BGP configuration has been specified and any BGP speaker
230 * exists in this configuration, else null is returned.
231 *
232 * @return BGP configuration or null
233 */
234 private BgpConfig getBgpConfig() {
235 BgpConfig bgpConfig = configService.
236 getConfig(routerAppId, BgpConfig.class);
237
238 if (bgpConfig == null || bgpConfig.bgpSpeakers().isEmpty()) {
239 return null;
240 }
241 return bgpConfig;
242 }
243
244 private Interface getInterface(ConnectPoint port, String interfaceName) {
245 Optional<Interface> interfaceMatch = interfaceService
246 .getInterfacesByPort(port)
247 .stream()
248 .filter(intf -> intf.name().equals(interfaceName))
249 .findFirst();
250 if (!interfaceMatch.isPresent()) {
251 // No such interface name configured for given connectPoint
252 return null;
253 }
254 return interfaceMatch.get();
255 }
256
Andreas Papazoisf0ec25b2016-02-05 14:20:06 +0200257 private boolean interfaceSubnetIncludesIp(Interface peerInterface, IpAddress peerAddress) {
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300258 if (peerInterface.ipAddressesList().stream()
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200259 .anyMatch(intfIp -> intfIp.subnetAddress().
260 contains(peerAddress))) {
261 // Interface configured subnet not including peer address
262 return true;
263 }
264 return false;
265 }
266
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300267 private boolean peerNameExists(SdxParticipantsConfig config, String peerName) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200268 if (config.getPeerForName(Optional.of(peerName)) == null) {
269 return false;
270 }
271 return true;
272 }
273
274 /**
275 * Adds the peer to the SdxProvidersConfig .
276 *
277 * @param peersConfig the BGP peers configuration
278 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300279 private void addPeerToConf(SdxParticipantsConfig peersConfig, String peerName,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200280 IpAddress peerAddress, ConnectPoint port,
281 String interfaceName) {
282 log.debug("Adding peer with IP to configuration: {}", peerAddress);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300283 SdxParticipantsConfig.PeerConfig peer = new SdxParticipantsConfig.
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200284 PeerConfig(Optional.ofNullable(peerName), peerAddress,
285 port, interfaceName);
286
287 peersConfig.addPeer(peer);
288 }
289
290 /**
291 * Removes the speaker from the BgpConfig service.
292 *
293 * @param peersConfig the BGP peeers configuration
294 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300295 private void removePeerFromConf(SdxParticipantsConfig peersConfig,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200296 IpAddress peerAddress) {
297 log.debug("Removing peer details from configuration: {}",
298 peerAddress.toString());
299 peersConfig.removePeer(peerAddress);
300 }
301
302 /**
303 * Returns true if a given IP address has been specified as a BGP peer
304 * address in the network configuration.
305 *
Andreas Papazoisf0ec25b2016-02-05 14:20:06 +0200306 * @param bgpConfig BGP configuration
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200307 * @param peerAddress IP address of peer
308 * @return whether address has been specified for a peer or not
309 */
310 private Boolean peerAddressExists(BgpConfig bgpConfig,
311 IpAddress peerAddress) {
312 List<IpAddress> peeringAddresses =
313 getPeerAddresses(bgpConfig);
314 if (!peeringAddresses.contains(peerAddress)) {
315 return false;
316 }
317 return true;
318 }
319
320 private Interface getConfiguredInterfaceForPeer(IpAddress peerAddress) {
321 if (sdxAppId == null) {
322 return null;
323 }
324
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300325 SdxParticipantsConfig config = configService.getConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200326 if (config == null) {
327 return null;
328 }
329
330 ConnectPoint port = config.getPortForPeer(peerAddress);
331 String intfName = config.getInterfaceNameForPeer(peerAddress);
332 if (port != null && intfName != null) {
333 Optional<Interface> interfaceMatch = interfaceService
334 .getInterfacesByPort(port)
335 .stream()
336 .filter(intf -> intf.name().equals(intfName))
337 .findFirst();
338 if (interfaceMatch.isPresent()) {
339 return interfaceMatch.get();
340 }
341 }
342 return null;
343 }
344
345 /**
346 * Returns the interface used as connection point to peer.
347 *
348 * @param peerAddress IP address of peer
349 * @return interface to the peer
350 */
351 @Override
352 public Interface getInterfaceForPeer(IpAddress peerAddress) {
353 Interface peeringInterface = getConfiguredInterfaceForPeer(peerAddress);
354 if (peeringInterface == null) {
355 peeringInterface = interfaceService.getMatchingInterface(peerAddress);
356 }
357 return peeringInterface;
358 }
359
360 @Override
361 public List<IpAddress> getPeerAddresses(BgpConfig bgpConfig) {
362 List<IpAddress> peeringAddresses = Lists.newArrayList();
363
364 List<BgpConfig.BgpSpeakerConfig> bgpSpeakers =
365 Lists.newArrayList(bgpConfig.bgpSpeakers());
366 bgpSpeakers.forEach(
367 s -> peeringAddresses.addAll(s.peers()));
368
369 return peeringAddresses;
370 }
371
372 /**
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200373 * Sets up paths to establish connectivity between all internal
374 * BGP speakers and external BGP peers.
375 */
376 private void setUpConnectivity() {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200377 BgpConfig config = getBgpConfig();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200378 if (config == null) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200379 log.warn("No BGP configuration found");
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200380 return;
381 }
382
383 Map<Key, PointToPointIntent> existingIntents = new HashMap<>(peerIntents);
384
385 for (BgpConfig.BgpSpeakerConfig bgpSpeaker : config.bgpSpeakers()) {
386 log.debug("Start to set up BGP paths for BGP speaker: {}",
387 bgpSpeaker);
388
389 buildSpeakerIntents(bgpSpeaker).forEach(i -> {
390 PointToPointIntent intent = existingIntents.remove(i.key());
391 if (intent == null || !IntentUtils.intentsAreEqual(i, intent)) {
392 peerIntents.put(i.key(), i);
393 intentSynchronizer.submit(i);
394 }
395 });
396 }
397
398 // Remove any remaining intents that we used to have that we don't need
399 // anymore
400 existingIntents.values().forEach(i -> {
401 peerIntents.remove(i.key());
402 intentSynchronizer.withdraw(i);
403 });
404 }
405
406 private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) {
407 List<PointToPointIntent> intents = new ArrayList<>();
408
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300409 // Get the BGP Speaker VLAN Id
410 VlanId bgpSpeakerVlanId = speaker.vlan();
411
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200412 for (IpAddress peerAddress : speaker.peers()) {
413 Interface peeringInterface = getInterfaceForPeer(peerAddress);
414
415 if (peeringInterface == null) {
416 log.debug("No peering interface found for peer {} on speaker {}",
417 peerAddress, speaker);
418 continue;
419 }
420
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300421 IpAddress bgpSpeakerAddress = null;
422 for (InterfaceIpAddress address : peeringInterface.ipAddressesList()) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200423 if (address.subnetAddress().contains(peerAddress)) {
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300424 bgpSpeakerAddress = address.ipAddress();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200425 break;
426 }
427 }
428
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300429 checkNotNull(bgpSpeakerAddress);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200430
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300431 VlanId peerVlanId = peeringInterface.vlan();
432
433 intents.addAll(buildIntents(speaker.connectPoint(), bgpSpeakerVlanId,
434 bgpSpeakerAddress,
435 peeringInterface.connectPoint(),
436 peerVlanId,
437 peerAddress));
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200438 }
439
440 return intents;
441 }
442
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200443 /**
Andreas Papazois1f941912016-07-01 11:48:12 +0300444 * Builds the required intents between a BGP speaker and an external router.
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200445 *
Andreas Papazois1f941912016-07-01 11:48:12 +0300446 * @param portOne the BGP speaker connect point
447 * @param vlanOne the BGP speaker VLAN
448 * @param ipOne the BGP speaker IP address
449 * @param portTwo the external BGP peer connect point
450 * @param vlanTwo the external BGP peer VLAN
451 * @param ipTwo the external BGP peer IP address
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200452 * @return the intents to install
453 */
454 private Collection<PointToPointIntent> buildIntents(ConnectPoint portOne,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300455 VlanId vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200456 IpAddress ipOne,
457 ConnectPoint portTwo,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300458 VlanId vlanTwo,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200459 IpAddress ipTwo) {
460
461 List<PointToPointIntent> intents = new ArrayList<>();
462
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300463 TrafficTreatment.Builder treatmentToPeer = DefaultTrafficTreatment.builder();
464 TrafficTreatment.Builder treatmentToSpeaker = DefaultTrafficTreatment.builder();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200465 TrafficSelector selector;
466 Key key;
467
468 byte tcpProtocol;
469 byte icmpProtocol;
470
471 if (ipOne.isIp4()) {
472 tcpProtocol = IPv4.PROTOCOL_TCP;
473 icmpProtocol = IPv4.PROTOCOL_ICMP;
474 } else {
475 tcpProtocol = IPv6.PROTOCOL_TCP;
476 icmpProtocol = IPv6.PROTOCOL_ICMP6;
477 }
478
Andreas Papazois1f941912016-07-01 11:48:12 +0300479 // Add VLAN treatment for traffic going from BGP speaker to BGP peer
Andreas papazois47deeaa2016-10-18 12:19:52 +0300480 treatmentToPeer = applyVlanTreatment(vlanOne, vlanTwo, treatmentToPeer);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300481
482 // Path from BGP speaker to BGP peer matching destination TCP port 179
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200483 selector = buildSelector(tcpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300484 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200485 ipOne,
486 ipTwo,
487 null,
488 BGP_PORT);
489
490 key = buildKey(ipOne, ipTwo, SUFFIX_DST);
491
492 intents.add(PointToPointIntent.builder()
493 .appId(sdxAppId)
494 .key(key)
495 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300496 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200497 .ingressPoint(portOne)
498 .egressPoint(portTwo)
499 .priority(PRIORITY_OFFSET)
500 .build());
501
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300502 // Path from BGP speaker to BGP peer matching source TCP port 179
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200503 selector = buildSelector(tcpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300504 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200505 ipOne,
506 ipTwo,
507 BGP_PORT,
508 null);
509
510 key = buildKey(ipOne, ipTwo, SUFFIX_SRC);
511
512 intents.add(PointToPointIntent.builder()
513 .appId(sdxAppId)
514 .key(key)
515 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300516 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200517 .ingressPoint(portOne)
518 .egressPoint(portTwo)
519 .priority(PRIORITY_OFFSET)
520 .build());
521
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200522 // ICMP path from BGP speaker to BGP peer
523 selector = buildSelector(icmpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300524 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200525 ipOne,
526 ipTwo,
527 null,
528 null);
529
530 key = buildKey(ipOne, ipTwo, SUFFIX_ICMP);
531
532 intents.add(PointToPointIntent.builder()
533 .appId(sdxAppId)
534 .key(key)
535 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300536 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200537 .ingressPoint(portOne)
538 .egressPoint(portTwo)
539 .priority(PRIORITY_OFFSET)
540 .build());
541
Andreas Papazois1f941912016-07-01 11:48:12 +0300542 // Add VLAN treatment for traffic going from BGP peer to BGP speaker
Andreas papazois47deeaa2016-10-18 12:19:52 +0300543 treatmentToSpeaker = applyVlanTreatment(vlanTwo, vlanOne, treatmentToSpeaker);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300544
545 // Path from BGP peer to BGP speaker matching destination TCP port 179
546 selector = buildSelector(tcpProtocol,
547 vlanTwo,
548 ipTwo,
549 ipOne,
550 null,
551 BGP_PORT);
552
553 key = buildKey(ipTwo, ipOne, SUFFIX_DST);
554
555 intents.add(PointToPointIntent.builder()
556 .appId(sdxAppId)
557 .key(key)
558 .selector(selector)
559 .treatment(treatmentToSpeaker.build())
560 .ingressPoint(portTwo)
561 .egressPoint(portOne)
562 .priority(PRIORITY_OFFSET)
563 .build());
564
565 // Path from BGP peer to BGP speaker matching source TCP port 179
566 selector = buildSelector(tcpProtocol,
567 vlanTwo,
568 ipTwo,
569 ipOne,
570 BGP_PORT,
571 null);
572
573 key = buildKey(ipTwo, ipOne, SUFFIX_SRC);
574
575 intents.add(PointToPointIntent.builder()
576 .appId(sdxAppId)
577 .key(key)
578 .selector(selector)
579 .treatment(treatmentToSpeaker.build())
580 .ingressPoint(portTwo)
581 .egressPoint(portOne)
582 .priority(PRIORITY_OFFSET)
583 .build());
584
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200585 // ICMP path from BGP peer to BGP speaker
586 selector = buildSelector(icmpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300587 vlanTwo,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200588 ipTwo,
589 ipOne,
590 null,
591 null);
592
593 key = buildKey(ipTwo, ipOne, SUFFIX_ICMP);
594
595 intents.add(PointToPointIntent.builder()
596 .appId(sdxAppId)
597 .key(key)
598 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300599 .treatment(treatmentToSpeaker.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200600 .ingressPoint(portTwo)
601 .egressPoint(portOne)
602 .priority(PRIORITY_OFFSET)
603 .build());
604
605 return intents;
606 }
607
608 /**
609 * Builds a traffic selector based on the set of input parameters.
610 *
611 * @param ipProto IP protocol
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300612 * @param ingressVlanId VLAN Id configured on the ingress interface
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200613 * @param srcIp source IP address
614 * @param dstIp destination IP address
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300615 * @param srcTcpPort source TCP port, or null if shouldn't be set
616 * @param dstTcpPort destination TCP port, or null if shouldn't be set
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200617 * @return the new traffic selector
618 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300619 private TrafficSelector buildSelector(byte ipProto,
620 VlanId ingressVlanId,
621 IpAddress srcIp,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200622 IpAddress dstIp, Short srcTcpPort,
623 Short dstTcpPort) {
624 TrafficSelector.Builder builder = DefaultTrafficSelector.builder().matchIPProtocol(ipProto);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300625 // Match on any VLAN Id if a VLAN Id configured on the ingress interface
626 if (!ingressVlanId.equals(VlanId.NONE)) {
627 builder.matchVlanId(VlanId.ANY);
628 }
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200629
630 if (dstIp.isIp4()) {
631 builder.matchEthType(Ethernet.TYPE_IPV4)
632 .matchIPSrc(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET_MASK_LENGTH))
633 .matchIPDst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET_MASK_LENGTH));
634 } else {
635 builder.matchEthType(Ethernet.TYPE_IPV6)
636 .matchIPv6Src(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET6_MASK_LENGTH))
637 .matchIPv6Dst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET6_MASK_LENGTH));
638 }
639
640 if (srcTcpPort != null) {
641 builder.matchTcpSrc(TpPort.tpPort(srcTcpPort));
642 }
643
644 if (dstTcpPort != null) {
645 builder.matchTcpDst(TpPort.tpPort(dstTcpPort));
646 }
647
648 return builder.build();
649 }
650
651 /**
652 * Builds an intent Key for a point-to-point intent based off the source
653 * and destination IP address, as well as a suffix String to distinguish
654 * between different types of intents between the same source and
655 * destination.
656 *
657 * @param srcIp source IP address
658 * @param dstIp destination IP address
659 * @param suffix suffix string
660 * @return intent key
661 */
662 private Key buildKey(IpAddress srcIp, IpAddress dstIp, String suffix) {
663 String keyString = new StringBuilder()
664 .append(srcIp.toString())
665 .append("-")
666 .append(dstIp.toString())
667 .append("-")
668 .append(suffix)
669 .toString();
670
671 return Key.of(keyString, sdxAppId);
672 }
673
Andreas papazois47deeaa2016-10-18 12:19:52 +0300674 /**
675 * Adds the VLAN Id treatment before building the intents, depending on how
676 * the VLAN Ids of the BGP speakers and the BGP peers are configured.
677 */
678 private TrafficTreatment.Builder applyVlanTreatment(VlanId vlanOne,
679 VlanId vlanTwo,
680 TrafficTreatment.Builder treatment) {
681 if (!vlanOne.equals(vlanTwo)) {
682 // VLANs are different. Do some VLAN treatment
683 if (vlanTwo.equals(VlanId.NONE)) {
684 // VLAN two is none. VLAN one is set. Do a pop
685 treatment.popVlan();
686 } else {
687 // Either both VLANs are set or vlanOne is not
688 if (vlanOne.equals(VlanId.NONE)) {
689 // VLAN one is none. VLAN two is set. Push the VLAN header
690 treatment.pushVlan();
691 }
692 // Set the VLAN Id to the egress VLAN Id
693 treatment.setVlanId(vlanTwo);
694 }
695 }
696 return treatment;
697 }
698
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200699 private class InternalNetworkConfigListener implements NetworkConfigListener {
700
701 @Override
702 public void event(NetworkConfigEvent event) {
703 switch (event.type()) {
704 case CONFIG_REGISTERED:
705 break;
706 case CONFIG_UNREGISTERED:
707 break;
708 case CONFIG_ADDED:
709 case CONFIG_UPDATED:
710 case CONFIG_REMOVED:
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200711 if (event.configClass() == RoutingService.CONFIG_CLASS ||
712 event.configClass() == CONFIG_CLASS) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200713 setUpConnectivity();
714 }
715 break;
716 default:
717 break;
718 }
719 }
720 }
721
Andreas Papazois1f941912016-07-01 11:48:12 +0300722 private class InternalInterfaceListener implements InterfaceListener {
723 @Override
724 public void event(InterfaceEvent event) {
725 switch (event.type()) {
726 case INTERFACE_ADDED:
727 case INTERFACE_UPDATED:
728 case INTERFACE_REMOVED:
729 setUpConnectivity();
730 break;
731 default:
732 break;
733 }
734 }
735 }
736
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200737}