/* * Copyright 2015-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.routing.config; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.Sets; import org.onlab.packet.IpAddress; import org.onlab.packet.VlanId; import org.onosproject.core.ApplicationId; import org.onosproject.net.ConnectPoint; import org.onosproject.net.config.Config; import java.util.Objects; import java.util.Optional; import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; /** * Configuration object for BGP config. */ public class BgpConfig extends Config<ApplicationId> { public static final String SPEAKERS = "bgpSpeakers"; public static final String CONNECT_POINT = "connectPoint"; public static final String NAME = "name"; public static final String PEERS = "peers"; public static final String VLAN = "vlan"; /** * Gets the set of configured BGP speakers. * * @return BGP speakers */ public Set<BgpSpeakerConfig> bgpSpeakers() { Set<BgpSpeakerConfig> speakers = Sets.newHashSet(); JsonNode speakersNode = object.get(SPEAKERS); if (speakersNode == null) { return speakers; } speakersNode.forEach(jsonNode -> { Set<IpAddress> listenAddresses = Sets.newHashSet(); jsonNode.path(PEERS).forEach(addressNode -> listenAddresses.add(IpAddress.valueOf(addressNode.asText())) ); Optional<String> name; if (jsonNode.get(NAME) == null) { name = Optional.empty(); } else { name = Optional.of(jsonNode.get(NAME).asText()); } VlanId vlan = getVlan(jsonNode); speakers.add(new BgpSpeakerConfig(name, vlan, ConnectPoint.deviceConnectPoint(jsonNode.path(CONNECT_POINT).asText()), listenAddresses)); }); return speakers; } /* * If configured, it retrieves a VLAN Id from a BGP speaker node */ private VlanId getVlan(JsonNode node) { VlanId vlan = VlanId.NONE; if (!node.path(VLAN).isMissingNode()) { vlan = VlanId.vlanId(node.path(VLAN).asText()); } return vlan; } /** * Examines whether a name of BGP speaker exists in configuration. * * @param name the name of BGP speaker being search * @return the BGP speaker */ public BgpSpeakerConfig getSpeakerWithName(String name) { for (BgpConfig.BgpSpeakerConfig speaker : bgpSpeakers()) { if (speaker.name().filter(name::equals).isPresent()) { return speaker; } } return null; } /** * Adds a BGP speaker to the configuration. * * @param speaker the BGP speaker configuration entry */ public void addSpeaker(BgpSpeakerConfig speaker) { // Create the new speaker node and set the parameters ObjectNode speakerNode = JsonNodeFactory.instance.objectNode(); speakerNode.put(NAME, speaker.name().get()); speakerNode.put(VLAN, speaker.vlan().toString()); speakerNode.put(CONNECT_POINT, speaker.connectPoint().elementId().toString() + "/" + speaker.connectPoint().port().toString()); ArrayNode peersNode = speakerNode.putArray(PEERS); for (IpAddress peerAddress: speaker.peers()) { peersNode.add(peerAddress.toString()); } // Add the new BGP speaker to the existing node array ArrayNode speakersArray = bgpSpeakers().isEmpty() ? initBgpSpeakersConfiguration() : (ArrayNode) object.get(SPEAKERS); speakersArray.add(speakerNode); } /** * Removes BGP speaker from configuration. * * @param speakerName BGP speaker name */ public void removeSpeaker(String speakerName) { ArrayNode speakersArray = (ArrayNode) object.get(SPEAKERS); for (int i = 0; i < speakersArray.size(); i++) { if (speakersArray.get(i).hasNonNull(NAME) && speakersArray.get(i).get(NAME).asText().equals(speakerName)) { speakersArray.remove(i); return; } } } /** * Adds peering address to BGP speaker. * * @param speakerName name of BGP speaker * @param peerAddress peering address to be added */ public void addPeerToSpeaker(String speakerName, IpAddress peerAddress) { JsonNode speakersNode = object.get(SPEAKERS); speakersNode.forEach(jsonNode -> { if (jsonNode.hasNonNull(NAME) && jsonNode.get(NAME).asText().equals(speakerName)) { ArrayNode peersNode = (ArrayNode) jsonNode.get(PEERS); for (int i = 0; i < peersNode.size(); i++) { if (peersNode.get(i).asText().equals(peerAddress.toString())) { return; // Peer already exists. } } peersNode.add(peerAddress.toString()); } }); } /** * Finds BGP speaker peering with a given external peer. * * @param peerAddress BGP peer address * @return BGP speaker */ public BgpSpeakerConfig getSpeakerFromPeer(IpAddress peerAddress) { for (BgpConfig.BgpSpeakerConfig speaker : bgpSpeakers()) { if (speaker.peers().contains(peerAddress)) { return speaker; } } return null; } /** * Removes peering address from BGP speaker. * * @param speaker BGP speaker configuration entries * @param peerAddress peering address to be removed */ public void removePeerFromSpeaker(BgpSpeakerConfig speaker, IpAddress peerAddress) { JsonNode speakersNode = object.get(SPEAKERS); speakersNode.forEach(jsonNode -> { if (jsonNode.hasNonNull(NAME) && jsonNode.get(NAME).asText().equals(speaker.name().get())) { ArrayNode peersNode = (ArrayNode) jsonNode.get(PEERS); for (int i = 0; i < peersNode.size(); i++) { if (peersNode.get(i).asText().equals(peerAddress.toString())) { peersNode.remove(i); return; } } } }); } /** * Creates empty configuration for BGP speakers. * * @return empty array of BGP speakers */ private ArrayNode initBgpSpeakersConfiguration() { return object.putArray(SPEAKERS); } /** * Configuration for a BGP speaker. */ public static class BgpSpeakerConfig { private Optional<String> name; private VlanId vlanId; private ConnectPoint connectPoint; private Set<IpAddress> peers; public BgpSpeakerConfig(Optional<String> name, VlanId vlanId, ConnectPoint connectPoint, Set<IpAddress> peers) { this.name = checkNotNull(name); this.vlanId = checkNotNull(vlanId); this.connectPoint = checkNotNull(connectPoint); this.peers = checkNotNull(peers); } public Optional<String> name() { return name; } public VlanId vlan() { return vlanId; } public ConnectPoint connectPoint() { return connectPoint; } public Set<IpAddress> peers() { return peers; } /** * Examines if BGP peer is connected. * * @param peer IP address of peer * @return result of search */ public boolean isConnectedToPeer(IpAddress peer) { for (final IpAddress entry : peers()) { if (entry.equals(peer)) { return true; } } return false; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof BgpSpeakerConfig) { final BgpSpeakerConfig that = (BgpSpeakerConfig) obj; return Objects.equals(this.name, that.name) && Objects.equals(this.vlanId, that.vlanId) && Objects.equals(this.connectPoint, that.connectPoint) && Objects.equals(this.peers, that.peers); } return false; } @Override public int hashCode() { return Objects.hash(name, vlanId, connectPoint, peers); } } }