blob: 8c95896647c05b35acb873cfd6ddabc70fa4913b [file] [log] [blame]
slowrdb071b22017-07-07 11:10:25 -07001/*
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -07002 * Copyright 2017-present Open Networking Foundation
slowrdb071b22017-07-07 11:10:25 -07003 *
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 */
16package org.onosproject.artemis.impl.bgpspeakers;
17
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070018import org.apache.commons.lang.exception.ExceptionUtils;
slowrdb071b22017-07-07 11:10:25 -070019import org.apache.commons.net.telnet.TelnetClient;
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070020import org.onosproject.artemis.BgpSpeakers;
slowrdb071b22017-07-07 11:10:25 -070021import org.onosproject.routing.bgp.BgpInfoService;
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070022import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
slowrdb071b22017-07-07 11:10:25 -070024
25import java.io.InputStream;
26import java.io.PrintStream;
27import java.util.Arrays;
28
29/**
30 * Quagga interface to connect and announce prefixes.
31 */
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070032public class QuaggaBgpSpeakers implements BgpSpeakers {
33 // TODO: move this to configuration
slowrdb071b22017-07-07 11:10:25 -070034 private static final String PASSWORD = "sdnip";
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070035 private final Logger log = LoggerFactory.getLogger(getClass());
slowrdb071b22017-07-07 11:10:25 -070036 private TelnetClient telnet = new TelnetClient();
37 private InputStream in;
38 private PrintStream out;
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070039 private BgpInfoService bgpInfoService;
slowrdb071b22017-07-07 11:10:25 -070040
41 public QuaggaBgpSpeakers(BgpInfoService bgpInfoService) {
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070042 this.bgpInfoService = bgpInfoService;
slowrdb071b22017-07-07 11:10:25 -070043 }
44
45 @Override
46 public void announceSubPrefixes(String[] prefixes) {
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070047 log.info("Announcing subprefixes: {}", (Object[]) prefixes);
48 bgpInfoService.getBgpSessions().forEach((session) -> {
slowrdb071b22017-07-07 11:10:25 -070049 String peerIp = session.remoteInfo().ip4Address().toString(),
50 localAs = String.valueOf(session.remoteInfo().as4Number());
51 assert peerIp != null;
52
53 try {
54 telnet.connect(peerIp, 2605);
55 in = telnet.getInputStream();
56 out = new PrintStream(telnet.getOutputStream());
57
58 readUntil("Password: ");
59 write(PASSWORD);
60 readUntil("> ");
61
62 // we user remote AS as local because he is iBGP neighbor.
63 announcePrefix(prefixes, localAs);
64
65 disconnect();
66
67 log.info("Announced " + prefixes[0] + " and " + prefixes[1] + " at " + peerIp);
68 } catch (Exception e) {
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070069 log.error(ExceptionUtils.getFullStackTrace(e));
slowrdb071b22017-07-07 11:10:25 -070070 }
71 });
72 }
73
74 /**
75 * Read telnet buffer until a pattern is met.
76 *
77 * @param pattern string pattern to match in terminal
78 * @return matched string
79 */
80 private String readUntil(String pattern) {
81 try {
82 char lastChar = pattern.charAt(pattern.length() - 1);
83 StringBuffer sb = new StringBuffer();
84 char ch = (char) in.read();
85 while (true) {
86 sb.append(ch);
87 if (ch == lastChar) {
88 if (sb.toString().endsWith(pattern)) {
89 return sb.toString();
90 }
91 }
92 ch = (char) in.read();
93 }
94 } catch (Exception e) {
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -070095 log.error(ExceptionUtils.getFullStackTrace(e));
slowrdb071b22017-07-07 11:10:25 -070096 }
97 return null;
98 }
99
100 /**
101 * Write to the telnet client.
102 *
103 * @param value string to write
104 */
105 private void write(String value) {
106 try {
107 out.println(value);
108 out.flush();
109 } catch (Exception e) {
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -0700110 log.error(ExceptionUtils.getFullStackTrace(e));
slowrdb071b22017-07-07 11:10:25 -0700111 }
112 }
113
114 /**
115 * Configure terminal and announce prefix inside the Quagga router.
116 *
117 * @param prefixes prefixes to announce
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -0700118 * @param localAs ASN of BGP Speaker
slowrdb071b22017-07-07 11:10:25 -0700119 */
120 private void announcePrefix(String[] prefixes, String localAs) {
121 write("en");
122 readUntil("# ");
123 write("configure terminal");
124 readUntil("(config)# ");
125 write("router bgp " + localAs);
126 readUntil("(config-router)# ");
127 Arrays.stream(prefixes).forEach((prefix) -> {
128 write("network " + prefix);
129 readUntil("(config-router)# ");
130 });
131 write("end");
132 }
133
134 /**
135 * Disconnect from the telnet session.
136 */
137 private void disconnect() {
138 try {
139 telnet.disconnect();
140 } catch (Exception e) {
Dimitrios Mavrommatisf0c06322017-10-31 23:49:04 -0700141 log.error(ExceptionUtils.getFullStackTrace(e));
slowrdb071b22017-07-07 11:10:25 -0700142 }
143 }
144}