slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 1 | /* |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 2 | * Copyright 2017-present Open Networking Foundation |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 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 | package org.onosproject.artemis.impl.bgpspeakers; |
| 17 | |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 18 | import org.apache.commons.lang.exception.ExceptionUtils; |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 19 | import org.apache.commons.net.telnet.TelnetClient; |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 20 | import org.onosproject.artemis.BgpSpeakers; |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 21 | import org.onosproject.routing.bgp.BgpInfoService; |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 22 | import org.slf4j.Logger; |
| 23 | import org.slf4j.LoggerFactory; |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 24 | |
| 25 | import java.io.InputStream; |
| 26 | import java.io.PrintStream; |
| 27 | import java.util.Arrays; |
| 28 | |
| 29 | /** |
| 30 | * Quagga interface to connect and announce prefixes. |
| 31 | */ |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 32 | public class QuaggaBgpSpeakers implements BgpSpeakers { |
| 33 | // TODO: move this to configuration |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 34 | private static final String PASSWORD = "sdnip"; |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 35 | private final Logger log = LoggerFactory.getLogger(getClass()); |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 36 | private TelnetClient telnet = new TelnetClient(); |
| 37 | private InputStream in; |
| 38 | private PrintStream out; |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 39 | private BgpInfoService bgpInfoService; |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 40 | |
| 41 | public QuaggaBgpSpeakers(BgpInfoService bgpInfoService) { |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 42 | this.bgpInfoService = bgpInfoService; |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | @Override |
| 46 | public void announceSubPrefixes(String[] prefixes) { |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 47 | log.info("Announcing subprefixes: {}", (Object[]) prefixes); |
| 48 | bgpInfoService.getBgpSessions().forEach((session) -> { |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 49 | 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 Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 69 | log.error(ExceptionUtils.getFullStackTrace(e)); |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 70 | } |
| 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 Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 95 | log.error(ExceptionUtils.getFullStackTrace(e)); |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 96 | } |
| 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 Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 110 | log.error(ExceptionUtils.getFullStackTrace(e)); |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 111 | } |
| 112 | } |
| 113 | |
| 114 | /** |
| 115 | * Configure terminal and announce prefix inside the Quagga router. |
| 116 | * |
| 117 | * @param prefixes prefixes to announce |
Dimitrios Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 118 | * @param localAs ASN of BGP Speaker |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 119 | */ |
| 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 Mavrommatis | f0c0632 | 2017-10-31 23:49:04 -0700 | [diff] [blame^] | 141 | log.error(ExceptionUtils.getFullStackTrace(e)); |
slowr | db071b2 | 2017-07-07 11:10:25 -0700 | [diff] [blame] | 142 | } |
| 143 | } |
| 144 | } |