blob: e9105a3840eb1ce2dcf8490f3377f000871b0003 [file] [log] [blame]
Andreas Papazoisa9964ea2016-01-08 15:58:22 +02001/*
Andreas Papazoise6aebaa2016-05-26 15:25:51 +03002 * Copyright 2016-present Open Networking Laboratory
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;
37import org.onosproject.incubator.net.intf.InterfaceService;
38import org.onosproject.net.ConnectPoint;
39import org.onosproject.net.config.ConfigFactory;
40import org.onosproject.net.config.NetworkConfigEvent;
41import org.onosproject.net.config.NetworkConfigListener;
42import org.onosproject.net.config.NetworkConfigRegistry;
43import org.onosproject.net.config.NetworkConfigService;
44import org.onosproject.net.config.basics.SubjectFactories;
45import org.onosproject.net.flow.DefaultTrafficSelector;
46import org.onosproject.net.flow.DefaultTrafficTreatment;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.flow.TrafficTreatment;
49import org.onosproject.net.host.InterfaceIpAddress;
50import org.onosproject.net.intent.IntentUtils;
51import org.onosproject.net.intent.Key;
52import org.onosproject.net.intent.PointToPointIntent;
53import org.onosproject.routing.IntentSynchronizationService;
54import org.onosproject.routing.RoutingService;
55import org.onosproject.routing.config.BgpConfig;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020056import org.onosproject.sdxl3.SdxL3;
Andreas Papazoisc2c45012016-01-20 14:26:11 +020057import org.onosproject.sdxl3.SdxL3PeerService;
Andreas Papazoise6aebaa2016-05-26 15:25:51 +030058import org.onosproject.sdxl3.config.SdxParticipantsConfig;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
62import java.util.ArrayList;
63import java.util.Collection;
64import java.util.HashMap;
65import java.util.List;
66import java.util.Map;
Andreas Papazoisc2c45012016-01-20 14:26:11 +020067import java.util.Optional;
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020068
69import static com.google.common.base.Preconditions.checkNotNull;
70
71/**
72 * Manages the connectivity requirements between peers.
73 */
74@Service
75@Component(immediate = true, enabled = false)
76public class SdxL3PeerManager implements SdxL3PeerService {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020077 private static final int PRIORITY_OFFSET = 1000;
78
79 private static final String SUFFIX_DST = "dst";
80 private static final String SUFFIX_SRC = "src";
81 private static final String SUFFIX_ICMP = "icmp";
82
83 private static final Logger log = LoggerFactory.getLogger(
Andreas Papazoisc2c45012016-01-20 14:26:11 +020084 SdxL3PeerManager.class);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +020085
86 private static final short BGP_PORT = 179;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected CoreService coreService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected NetworkConfigService configService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected InterfaceService interfaceService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected IntentSynchronizationService intentSynchronizer;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected NetworkConfigRegistry registry;
102
103 private ConfigFactory configFactory =
104 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200105 CONFIG_CLASS, CONFIG_KEY) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200106 @Override
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300107 public SdxParticipantsConfig createConfig() {
108 return new SdxParticipantsConfig();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200109 }
110 };
111
112 private ApplicationId sdxAppId;
113 private ApplicationId routerAppId;
114
115 private final Map<Key, PointToPointIntent> peerIntents = new HashMap<>();
116
117 private final InternalNetworkConfigListener configListener
118 = new InternalNetworkConfigListener();
119
120 @Activate
121 public void activate() {
122 sdxAppId = coreService.getAppId(SdxL3.SDX_L3_APP);
123 routerAppId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
124
125 registry.registerConfigFactory(configFactory);
126
127 configService.addListener(configListener);
128
129 setUpConnectivity();
130
131 log.info("Connectivity with BGP peers established");
132 }
133
134 @Deactivate
135 public void deactivate() {
136 configService.removeListener(configListener);
137
138 log.info("Connectivity with BGP peers stopped");
139 }
140
141 /**
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200142 * Adds details for a BGP peer to the SDX-L3 configuration.
143 *
144 * @param peerName Peer name
145 * @param peerAddress Peer IP address
146 * @param port Connection point with peer
147 * @param interfaceName Name of the interface configured on port
148 */
149 @Override
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300150 public void addPeerDetails(String peerName,
151 IpAddress peerAddress,
152 ConnectPoint port,
153 String interfaceName) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200154
155 BgpConfig bgpConfig = getBgpConfig();
156 if (bgpConfig == null) {
157 throw new ItemNotFoundException("BGP configuration not found");
158 }
159
160 if (!peerAddressExists(bgpConfig, peerAddress)) {
161 throw new ItemNotFoundException("Peer IP not found");
162 }
163
164 Interface peerInterface = getInterface(port, interfaceName);
165 if (peerInterface == null) {
166 throw new ItemNotFoundException("Interface not found");
167 }
168
169 if (!interfaceSubnetIncludesIp(peerInterface, peerAddress)) {
170 throw new IllegalArgumentException("Interface not configured for IP "
171 + peerAddress);
172 }
173
174 Interface confInterface = getConfiguredInterfaceForPeer(peerAddress);
175 if (confInterface != null) {
176 if (confInterface.equals(peerInterface)) {
177 // Do nothing since the association exists.
178 return;
179 } else {
180 // The peer is associated with another interface.
181 throw new IllegalArgumentException("Peer details already exist");
182 }
183 }
184
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300185 SdxParticipantsConfig peersConfig =
186 configService.addConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200187 if (peerName != null && peerNameExists(peersConfig, peerName)) {
188 throw new IllegalArgumentException("Peer name in use");
189 }
190
191 addPeerToConf(peersConfig, peerName, peerAddress, port, interfaceName);
192 configService.
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300193 applyConfig(sdxAppId, SdxParticipantsConfig.class, peersConfig.node());
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200194 }
195
196 /**
197 * Removes details for a BGP peer to the SDX-L3 configuration.
198 *
199 * @param peerAddress Peer IP address
200 */
201 @Override
202 public void removePeerDetails(IpAddress peerAddress) {
203 BgpConfig bgpConfig = getBgpConfig();
204 if (bgpConfig == null) {
205 throw new ItemNotFoundException("BGP configuration not found");
206 }
207
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300208 SdxParticipantsConfig peersConfig =
209 configService.addConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200210
211 if (peersConfig.getPeerForIp(peerAddress) == null) {
212 throw new ItemNotFoundException("Peer details not found");
213 }
214
215 removePeerFromConf(peersConfig, peerAddress);
216 configService.applyConfig(sdxAppId,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300217 SdxParticipantsConfig.class,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200218 peersConfig.node());
219 }
220
221 /**
222 * Returns BGP configuration has been specified and any BGP speaker
223 * exists in this configuration, else null is returned.
224 *
225 * @return BGP configuration or null
226 */
227 private BgpConfig getBgpConfig() {
228 BgpConfig bgpConfig = configService.
229 getConfig(routerAppId, BgpConfig.class);
230
231 if (bgpConfig == null || bgpConfig.bgpSpeakers().isEmpty()) {
232 return null;
233 }
234 return bgpConfig;
235 }
236
237 private Interface getInterface(ConnectPoint port, String interfaceName) {
238 Optional<Interface> interfaceMatch = interfaceService
239 .getInterfacesByPort(port)
240 .stream()
241 .filter(intf -> intf.name().equals(interfaceName))
242 .findFirst();
243 if (!interfaceMatch.isPresent()) {
244 // No such interface name configured for given connectPoint
245 return null;
246 }
247 return interfaceMatch.get();
248 }
249
Andreas Papazoisf0ec25b2016-02-05 14:20:06 +0200250 private boolean interfaceSubnetIncludesIp(Interface peerInterface, IpAddress peerAddress) {
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300251 if (peerInterface.ipAddressesList().stream()
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200252 .anyMatch(intfIp -> intfIp.subnetAddress().
253 contains(peerAddress))) {
254 // Interface configured subnet not including peer address
255 return true;
256 }
257 return false;
258 }
259
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300260 private boolean peerNameExists(SdxParticipantsConfig config, String peerName) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200261 if (config.getPeerForName(Optional.of(peerName)) == null) {
262 return false;
263 }
264 return true;
265 }
266
267 /**
268 * Adds the peer to the SdxProvidersConfig .
269 *
270 * @param peersConfig the BGP peers configuration
271 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300272 private void addPeerToConf(SdxParticipantsConfig peersConfig, String peerName,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200273 IpAddress peerAddress, ConnectPoint port,
274 String interfaceName) {
275 log.debug("Adding peer with IP to configuration: {}", peerAddress);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300276 SdxParticipantsConfig.PeerConfig peer = new SdxParticipantsConfig.
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200277 PeerConfig(Optional.ofNullable(peerName), peerAddress,
278 port, interfaceName);
279
280 peersConfig.addPeer(peer);
281 }
282
283 /**
284 * Removes the speaker from the BgpConfig service.
285 *
286 * @param peersConfig the BGP peeers configuration
287 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300288 private void removePeerFromConf(SdxParticipantsConfig peersConfig,
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200289 IpAddress peerAddress) {
290 log.debug("Removing peer details from configuration: {}",
291 peerAddress.toString());
292 peersConfig.removePeer(peerAddress);
293 }
294
295 /**
296 * Returns true if a given IP address has been specified as a BGP peer
297 * address in the network configuration.
298 *
Andreas Papazoisf0ec25b2016-02-05 14:20:06 +0200299 * @param bgpConfig BGP configuration
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200300 * @param peerAddress IP address of peer
301 * @return whether address has been specified for a peer or not
302 */
303 private Boolean peerAddressExists(BgpConfig bgpConfig,
304 IpAddress peerAddress) {
305 List<IpAddress> peeringAddresses =
306 getPeerAddresses(bgpConfig);
307 if (!peeringAddresses.contains(peerAddress)) {
308 return false;
309 }
310 return true;
311 }
312
313 private Interface getConfiguredInterfaceForPeer(IpAddress peerAddress) {
314 if (sdxAppId == null) {
315 return null;
316 }
317
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300318 SdxParticipantsConfig config = configService.getConfig(sdxAppId, SdxParticipantsConfig.class);
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200319 if (config == null) {
320 return null;
321 }
322
323 ConnectPoint port = config.getPortForPeer(peerAddress);
324 String intfName = config.getInterfaceNameForPeer(peerAddress);
325 if (port != null && intfName != null) {
326 Optional<Interface> interfaceMatch = interfaceService
327 .getInterfacesByPort(port)
328 .stream()
329 .filter(intf -> intf.name().equals(intfName))
330 .findFirst();
331 if (interfaceMatch.isPresent()) {
332 return interfaceMatch.get();
333 }
334 }
335 return null;
336 }
337
338 /**
339 * Returns the interface used as connection point to peer.
340 *
341 * @param peerAddress IP address of peer
342 * @return interface to the peer
343 */
344 @Override
345 public Interface getInterfaceForPeer(IpAddress peerAddress) {
346 Interface peeringInterface = getConfiguredInterfaceForPeer(peerAddress);
347 if (peeringInterface == null) {
348 peeringInterface = interfaceService.getMatchingInterface(peerAddress);
349 }
350 return peeringInterface;
351 }
352
353 @Override
354 public List<IpAddress> getPeerAddresses(BgpConfig bgpConfig) {
355 List<IpAddress> peeringAddresses = Lists.newArrayList();
356
357 List<BgpConfig.BgpSpeakerConfig> bgpSpeakers =
358 Lists.newArrayList(bgpConfig.bgpSpeakers());
359 bgpSpeakers.forEach(
360 s -> peeringAddresses.addAll(s.peers()));
361
362 return peeringAddresses;
363 }
364
365 /**
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200366 * Sets up paths to establish connectivity between all internal
367 * BGP speakers and external BGP peers.
368 */
369 private void setUpConnectivity() {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200370 BgpConfig config = getBgpConfig();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200371 if (config == null) {
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200372 log.warn("No BGP configuration found");
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200373 return;
374 }
375
376 Map<Key, PointToPointIntent> existingIntents = new HashMap<>(peerIntents);
377
378 for (BgpConfig.BgpSpeakerConfig bgpSpeaker : config.bgpSpeakers()) {
379 log.debug("Start to set up BGP paths for BGP speaker: {}",
380 bgpSpeaker);
381
382 buildSpeakerIntents(bgpSpeaker).forEach(i -> {
383 PointToPointIntent intent = existingIntents.remove(i.key());
384 if (intent == null || !IntentUtils.intentsAreEqual(i, intent)) {
385 peerIntents.put(i.key(), i);
386 intentSynchronizer.submit(i);
387 }
388 });
389 }
390
391 // Remove any remaining intents that we used to have that we don't need
392 // anymore
393 existingIntents.values().forEach(i -> {
394 peerIntents.remove(i.key());
395 intentSynchronizer.withdraw(i);
396 });
397 }
398
399 private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) {
400 List<PointToPointIntent> intents = new ArrayList<>();
401
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300402 // Get the BGP Speaker VLAN Id
403 VlanId bgpSpeakerVlanId = speaker.vlan();
404
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200405 for (IpAddress peerAddress : speaker.peers()) {
406 Interface peeringInterface = getInterfaceForPeer(peerAddress);
407
408 if (peeringInterface == null) {
409 log.debug("No peering interface found for peer {} on speaker {}",
410 peerAddress, speaker);
411 continue;
412 }
413
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300414 IpAddress bgpSpeakerAddress = null;
415 for (InterfaceIpAddress address : peeringInterface.ipAddressesList()) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200416 if (address.subnetAddress().contains(peerAddress)) {
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300417 bgpSpeakerAddress = address.ipAddress();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200418 break;
419 }
420 }
421
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300422 checkNotNull(bgpSpeakerAddress);
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200423
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300424 VlanId peerVlanId = peeringInterface.vlan();
425
426 intents.addAll(buildIntents(speaker.connectPoint(), bgpSpeakerVlanId,
427 bgpSpeakerAddress,
428 peeringInterface.connectPoint(),
429 peerVlanId,
430 peerAddress));
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200431 }
432
433 return intents;
434 }
435
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200436 /**
437 * Builds the required intents between the two pairs of connect points and
438 * IP addresses.
439 *
440 * @param portOne the first connect point
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300441 * @param vlanOne the ingress VLAN
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200442 * @param ipOne the first IP address
443 * @param portTwo the second connect point
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300444 * @param vlanTwo the egress VLAN
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200445 * @param ipTwo the second IP address
446 * @return the intents to install
447 */
448 private Collection<PointToPointIntent> buildIntents(ConnectPoint portOne,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300449 VlanId vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200450 IpAddress ipOne,
451 ConnectPoint portTwo,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300452 VlanId vlanTwo,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200453 IpAddress ipTwo) {
454
455 List<PointToPointIntent> intents = new ArrayList<>();
456
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300457 TrafficTreatment.Builder treatmentToPeer = DefaultTrafficTreatment.builder();
458 TrafficTreatment.Builder treatmentToSpeaker = DefaultTrafficTreatment.builder();
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200459 TrafficSelector selector;
460 Key key;
461
462 byte tcpProtocol;
463 byte icmpProtocol;
464
465 if (ipOne.isIp4()) {
466 tcpProtocol = IPv4.PROTOCOL_TCP;
467 icmpProtocol = IPv4.PROTOCOL_ICMP;
468 } else {
469 tcpProtocol = IPv6.PROTOCOL_TCP;
470 icmpProtocol = IPv6.PROTOCOL_ICMP6;
471 }
472
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300473 // Add treatment for VLAN for traffic going from BGP speaker to BGP peer
474 if (!vlanTwo.equals(VlanId.NONE)) {
475 treatmentToPeer.setVlanId(vlanTwo);
476 }
477
478 // Path from BGP speaker to BGP peer matching destination TCP port 179
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200479 selector = buildSelector(tcpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300480 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200481 ipOne,
482 ipTwo,
483 null,
484 BGP_PORT);
485
486 key = buildKey(ipOne, ipTwo, SUFFIX_DST);
487
488 intents.add(PointToPointIntent.builder()
489 .appId(sdxAppId)
490 .key(key)
491 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300492 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200493 .ingressPoint(portOne)
494 .egressPoint(portTwo)
495 .priority(PRIORITY_OFFSET)
496 .build());
497
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300498 // Path from BGP speaker to BGP peer matching source TCP port 179
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200499 selector = buildSelector(tcpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300500 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200501 ipOne,
502 ipTwo,
503 BGP_PORT,
504 null);
505
506 key = buildKey(ipOne, ipTwo, SUFFIX_SRC);
507
508 intents.add(PointToPointIntent.builder()
509 .appId(sdxAppId)
510 .key(key)
511 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300512 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200513 .ingressPoint(portOne)
514 .egressPoint(portTwo)
515 .priority(PRIORITY_OFFSET)
516 .build());
517
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200518 // ICMP path from BGP speaker to BGP peer
519 selector = buildSelector(icmpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300520 vlanOne,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200521 ipOne,
522 ipTwo,
523 null,
524 null);
525
526 key = buildKey(ipOne, ipTwo, SUFFIX_ICMP);
527
528 intents.add(PointToPointIntent.builder()
529 .appId(sdxAppId)
530 .key(key)
531 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300532 .treatment(treatmentToPeer.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200533 .ingressPoint(portOne)
534 .egressPoint(portTwo)
535 .priority(PRIORITY_OFFSET)
536 .build());
537
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300538 // Add treatment for VLAN for traffic going from BGP peer to BGP speaker
539 if (!vlanOne.equals(VlanId.NONE)) {
540 treatmentToSpeaker.setVlanId(vlanOne);
541 }
542
543 // Path from BGP peer to BGP speaker matching destination TCP port 179
544 selector = buildSelector(tcpProtocol,
545 vlanTwo,
546 ipTwo,
547 ipOne,
548 null,
549 BGP_PORT);
550
551 key = buildKey(ipTwo, ipOne, SUFFIX_DST);
552
553 intents.add(PointToPointIntent.builder()
554 .appId(sdxAppId)
555 .key(key)
556 .selector(selector)
557 .treatment(treatmentToSpeaker.build())
558 .ingressPoint(portTwo)
559 .egressPoint(portOne)
560 .priority(PRIORITY_OFFSET)
561 .build());
562
563 // Path from BGP peer to BGP speaker matching source TCP port 179
564 selector = buildSelector(tcpProtocol,
565 vlanTwo,
566 ipTwo,
567 ipOne,
568 BGP_PORT,
569 null);
570
571 key = buildKey(ipTwo, ipOne, SUFFIX_SRC);
572
573 intents.add(PointToPointIntent.builder()
574 .appId(sdxAppId)
575 .key(key)
576 .selector(selector)
577 .treatment(treatmentToSpeaker.build())
578 .ingressPoint(portTwo)
579 .egressPoint(portOne)
580 .priority(PRIORITY_OFFSET)
581 .build());
582
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200583 // ICMP path from BGP peer to BGP speaker
584 selector = buildSelector(icmpProtocol,
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300585 vlanTwo,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200586 ipTwo,
587 ipOne,
588 null,
589 null);
590
591 key = buildKey(ipTwo, ipOne, SUFFIX_ICMP);
592
593 intents.add(PointToPointIntent.builder()
594 .appId(sdxAppId)
595 .key(key)
596 .selector(selector)
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300597 .treatment(treatmentToSpeaker.build())
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200598 .ingressPoint(portTwo)
599 .egressPoint(portOne)
600 .priority(PRIORITY_OFFSET)
601 .build());
602
603 return intents;
604 }
605
606 /**
607 * Builds a traffic selector based on the set of input parameters.
608 *
609 * @param ipProto IP protocol
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300610 * @param ingressVlanId VLAN Id configured on the ingress interface
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200611 * @param srcIp source IP address
612 * @param dstIp destination IP address
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300613 * @param srcTcpPort source TCP port, or null if shouldn't be set
614 * @param dstTcpPort destination TCP port, or null if shouldn't be set
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200615 * @return the new traffic selector
616 */
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300617 private TrafficSelector buildSelector(byte ipProto,
618 VlanId ingressVlanId,
619 IpAddress srcIp,
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200620 IpAddress dstIp, Short srcTcpPort,
621 Short dstTcpPort) {
622 TrafficSelector.Builder builder = DefaultTrafficSelector.builder().matchIPProtocol(ipProto);
Andreas Papazoise6aebaa2016-05-26 15:25:51 +0300623 // Match on any VLAN Id if a VLAN Id configured on the ingress interface
624 if (!ingressVlanId.equals(VlanId.NONE)) {
625 builder.matchVlanId(VlanId.ANY);
626 }
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200627
628 if (dstIp.isIp4()) {
629 builder.matchEthType(Ethernet.TYPE_IPV4)
630 .matchIPSrc(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET_MASK_LENGTH))
631 .matchIPDst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET_MASK_LENGTH));
632 } else {
633 builder.matchEthType(Ethernet.TYPE_IPV6)
634 .matchIPv6Src(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET6_MASK_LENGTH))
635 .matchIPv6Dst(IpPrefix.valueOf(dstIp, IpPrefix.MAX_INET6_MASK_LENGTH));
636 }
637
638 if (srcTcpPort != null) {
639 builder.matchTcpSrc(TpPort.tpPort(srcTcpPort));
640 }
641
642 if (dstTcpPort != null) {
643 builder.matchTcpDst(TpPort.tpPort(dstTcpPort));
644 }
645
646 return builder.build();
647 }
648
649 /**
650 * Builds an intent Key for a point-to-point intent based off the source
651 * and destination IP address, as well as a suffix String to distinguish
652 * between different types of intents between the same source and
653 * destination.
654 *
655 * @param srcIp source IP address
656 * @param dstIp destination IP address
657 * @param suffix suffix string
658 * @return intent key
659 */
660 private Key buildKey(IpAddress srcIp, IpAddress dstIp, String suffix) {
661 String keyString = new StringBuilder()
662 .append(srcIp.toString())
663 .append("-")
664 .append(dstIp.toString())
665 .append("-")
666 .append(suffix)
667 .toString();
668
669 return Key.of(keyString, sdxAppId);
670 }
671
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200672 private class InternalNetworkConfigListener implements NetworkConfigListener {
673
674 @Override
675 public void event(NetworkConfigEvent event) {
676 switch (event.type()) {
677 case CONFIG_REGISTERED:
678 break;
679 case CONFIG_UNREGISTERED:
680 break;
681 case CONFIG_ADDED:
682 case CONFIG_UPDATED:
683 case CONFIG_REMOVED:
Andreas Papazoisc2c45012016-01-20 14:26:11 +0200684 if (event.configClass() == RoutingService.CONFIG_CLASS ||
685 event.configClass() == CONFIG_CLASS) {
Andreas Papazoisa9964ea2016-01-08 15:58:22 +0200686 setUpConnectivity();
687 }
688 break;
689 default:
690 break;
691 }
692 }
693 }
694
695}