blob: 7807d5f9c7c619aa1a0da9f402d1aae99522c1f6 [file] [log] [blame]
/*
* Copyright 2015 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.provider.bgp.topology.impl;
import static org.onosproject.bgp.controller.BgpDpid.uri;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.Device.Type.ROUTER;
import static org.onosproject.net.Device.Type.VIRTUAL;
import java.util.List;
import java.util.Set;
import org.onlab.packet.ChassisId;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.bgp.controller.BgpController;
import org.onosproject.bgp.controller.BgpDpid;
import org.onosproject.bgp.controller.BgpLinkListener;
import org.onosproject.bgp.controller.BgpNodeListener;
import org.onosproject.bgpio.exceptions.BgpParseException;
import org.onosproject.bgpio.protocol.linkstate.BgpLinkLSIdentifier;
import org.onosproject.bgpio.protocol.linkstate.BgpLinkLsNlriVer4;
import org.onosproject.bgpio.protocol.linkstate.BgpNodeLSIdentifier;
import org.onosproject.bgpio.protocol.linkstate.BgpNodeLSNlriVer4;
import org.onosproject.bgpio.protocol.linkstate.NodeDescriptors;
import org.onosproject.bgpio.protocol.linkstate.PathAttrNlriDetails;
import org.onosproject.bgpio.types.AutonomousSystemTlv;
import org.onosproject.bgpio.types.BgpLSIdentifierTlv;
import org.onosproject.bgpio.types.BgpValueType;
import org.onosproject.bgpio.types.IPv4AddressTlv;
import org.onosproject.bgpio.types.IsIsNonPseudonode;
import org.onosproject.bgpio.types.IsIsPseudonode;
import org.onosproject.bgpio.types.LinkLocalRemoteIdentifiersTlv;
import org.onosproject.bgpio.types.OspfNonPseudonode;
import org.onosproject.bgpio.types.OspfPseudonode;
import org.onosproject.core.CoreService;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DefaultDeviceDescription;
import org.onosproject.net.device.DeviceDescription;
import org.onosproject.net.device.DeviceProvider;
import org.onosproject.net.device.DeviceProviderRegistry;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.link.DefaultLinkDescription;
import org.onosproject.net.link.LinkDescription;
import org.onosproject.net.link.LinkProvider;
import org.onosproject.net.link.LinkProviderRegistry;
import org.onosproject.net.link.LinkProviderService;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Provider which uses an BGP controller to detect network infrastructure topology.
*/
@Component(immediate = true)
public class BgpTopologyProvider extends AbstractProvider implements DeviceProvider, LinkProvider {
public BgpTopologyProvider() {
super(new ProviderId("bgp", "org.onosproject.provider.bgp"));
}
private static final Logger log = LoggerFactory.getLogger(BgpTopologyProvider.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceProviderRegistry deviceProviderRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkProviderRegistry linkProviderRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected BgpController controller;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkService linkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
private DeviceProviderService deviceProviderService;
private LinkProviderService linkProviderService;
private InternalBgpProvider listener = new InternalBgpProvider();
private static final String UNKNOWN = "unknown";
public static final long IDENTIFIER_SET = 0x100000000L;
public static final String AS_NUMBER = "asNumber";
public static final String DOMAIN_IDENTIFIER = "domainIdentifier";
public static final String ROUTING_UNIVERSE = "routingUniverse";
public static final long PSEUDO_PORT = 0xffffffff;
@Activate
public void activate() {
log.debug("BgpTopologyProvider activate");
deviceProviderService = deviceProviderRegistry.register(this);
linkProviderService = linkProviderRegistry.register(this);
controller.addListener(listener);
controller.addLinkListener(listener);
}
@Deactivate
public void deactivate() {
log.debug("BgpTopologyProvider deactivate");
deviceProviderRegistry.unregister(this);
deviceProviderService = null;
linkProviderRegistry.unregister(this);
linkProviderService = null;
controller.removeListener(listener);
controller.removeLinkListener(listener);
}
/*
* Implements device and link update.
*/
private class InternalBgpProvider implements BgpNodeListener, BgpLinkListener {
@Override
public void addNode(BgpNodeLSNlriVer4 nodeNlri, PathAttrNlriDetails details) {
log.debug("Add node {}", nodeNlri.toString());
if (deviceProviderService == null) {
return;
}
Device.Type deviceType = ROUTER;
BgpDpid nodeUri = new BgpDpid(nodeNlri);
DeviceId deviceId = deviceId(uri(nodeUri.toString()));
ChassisId cId = new ChassisId();
DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder();
newBuilder.set(AnnotationKeys.TYPE, "L3");
newBuilder.set(ROUTING_UNIVERSE, Long.toString(nodeNlri.getIdentifier()));
List<BgpValueType> tlvs = nodeNlri.getLocalNodeDescriptors().getNodedescriptors().getSubTlvs();
for (BgpValueType tlv : tlvs) {
if (tlv instanceof AutonomousSystemTlv) {
newBuilder.set(AS_NUMBER, Integer.toString(((AutonomousSystemTlv) tlv).getAsNum()));
} else if (tlv instanceof BgpLSIdentifierTlv) {
newBuilder.set(DOMAIN_IDENTIFIER,
Integer.toString(((BgpLSIdentifierTlv) tlv).getBgpLsIdentifier()));
}
if (tlv.getType() == NodeDescriptors.IGP_ROUTERID_TYPE) {
if (tlv instanceof IsIsPseudonode) {
deviceType = VIRTUAL;
newBuilder.set(AnnotationKeys.ROUTER_ID, new String(((IsIsPseudonode) tlv).getIsoNodeId()));
} else if (tlv instanceof OspfPseudonode) {
deviceType = VIRTUAL;
newBuilder
.set(AnnotationKeys.ROUTER_ID, Integer.toString(((OspfPseudonode) tlv).getrouterID()));
} else if (tlv instanceof IsIsNonPseudonode) {
newBuilder.set(AnnotationKeys.ROUTER_ID, new String(((IsIsNonPseudonode) tlv).getIsoNodeId()));
} else if (tlv instanceof OspfNonPseudonode) {
newBuilder.set(AnnotationKeys.ROUTER_ID,
Integer.toString(((OspfNonPseudonode) tlv).getrouterID()));
}
}
}
DeviceDescription description = new DefaultDeviceDescription(uri(nodeUri.toString()), deviceType, UNKNOWN,
UNKNOWN, UNKNOWN, UNKNOWN, cId, newBuilder.build());
deviceProviderService.deviceConnected(deviceId, description);
}
@Override
public void deleteNode(BgpNodeLSNlriVer4 nodeNlri) {
log.debug("Delete node {}", nodeNlri.toString());
if (deviceProviderService == null) {
return;
}
BgpDpid deviceUri = new BgpDpid(nodeNlri);
DeviceId deviceId = deviceId(uri(deviceUri.toString()));
deviceProviderService.deviceDisconnected(deviceId);
}
@Override
public void addLink(BgpLinkLsNlriVer4 linkNlri, PathAttrNlriDetails details) throws BgpParseException {
log.debug("Addlink {}", linkNlri.toString());
if (linkProviderService == null) {
return;
}
LinkDescription linkDes = buildLinkDes(linkNlri, details, true);
linkProviderService.linkDetected(linkDes);
}
//Build link description.
private LinkDescription buildLinkDes(BgpLinkLsNlriVer4 linkNlri, PathAttrNlriDetails details, boolean isAddLink)
throws BgpParseException {
long srcAddress = 0;
long dstAddress = 0;
boolean localPseduo = false;
boolean remotePseduo = false;
List<BgpValueType> localTlvs = linkNlri.getLinkIdentifier().localNodeDescriptors().getSubTlvs();
for (BgpValueType localTlv : localTlvs) {
if (localTlv instanceof IsIsPseudonode || localTlv instanceof OspfPseudonode) {
localPseduo = true;
}
}
List<BgpValueType> remoteTlvs = linkNlri.getLinkIdentifier().remoteNodeDescriptors().getSubTlvs();
for (BgpValueType remoteTlv : remoteTlvs) {
if (remoteTlv instanceof IsIsPseudonode || remoteTlv instanceof OspfPseudonode) {
remotePseduo = true;
}
}
List<BgpValueType> tlvs = linkNlri.getLinkIdentifier().linkDescriptors();
for (BgpValueType tlv : tlvs) {
if (tlv instanceof LinkLocalRemoteIdentifiersTlv) {
srcAddress = ((LinkLocalRemoteIdentifiersTlv) tlv).getLinkLocalIdentifier();
//Set 32nd bit.
srcAddress = srcAddress | IDENTIFIER_SET;
dstAddress = ((LinkLocalRemoteIdentifiersTlv) tlv).getLinkRemoteIdentifier();
dstAddress = dstAddress | IDENTIFIER_SET;
} else if (tlv instanceof IPv4AddressTlv) {
if (tlv.getType() == BgpLinkLSIdentifier.IPV4_INTERFACE_ADDRESS_TYPE) {
srcAddress = ((IPv4AddressTlv) tlv).address().toInt();
} else {
dstAddress = ((IPv4AddressTlv) tlv).address().toInt();
}
}
}
DeviceId srcId = deviceId(uri(new BgpDpid(linkNlri, BgpDpid.NODE_DESCRIPTOR_LOCAL).toString()));
DeviceId dstId = deviceId(uri(new BgpDpid(linkNlri, BgpDpid.NODE_DESCRIPTOR_REMOTE).toString()));
if (localPseduo && srcAddress == 0) {
srcAddress = PSEUDO_PORT;
} else if (remotePseduo && dstAddress == 0) {
dstAddress = PSEUDO_PORT;
}
ConnectPoint src = new ConnectPoint(srcId, PortNumber.portNumber(srcAddress));
ConnectPoint dst = new ConnectPoint(dstId, PortNumber.portNumber(dstAddress));
BgpNodeLSNlriVer4 srcNodeNlri = new BgpNodeLSNlriVer4(linkNlri.getIdentifier(), linkNlri.getProtocolId()
.getType(), new BgpNodeLSIdentifier(linkNlri.getLinkIdentifier().localNodeDescriptors()), false,
linkNlri.getRouteDistinguisher());
BgpNodeLSNlriVer4 dstNodeNlri = new BgpNodeLSNlriVer4(linkNlri.getIdentifier(), linkNlri.getProtocolId()
.getType(), new BgpNodeLSIdentifier(linkNlri.getLinkIdentifier().remoteNodeDescriptors()), false,
linkNlri.getRouteDistinguisher());
addOrDeletePseudoNode(isAddLink, localPseduo, remotePseduo, srcNodeNlri,
dstNodeNlri, srcId, dstId, details);
return new DefaultLinkDescription(src, dst, Link.Type.DIRECT, false);
}
private void addOrDeletePseudoNode(boolean isAddLink, boolean localPseduo, boolean remotePseduo,
BgpNodeLSNlriVer4 srcNodeNlri, BgpNodeLSNlriVer4 dstNodeNlri, DeviceId srcId, DeviceId dstId,
PathAttrNlriDetails details) {
if (isAddLink) {
if (localPseduo) {
if (deviceService.getDevice(srcId) == null) {
for (BgpNodeListener l : controller.listener()) {
l.addNode(srcNodeNlri, details);
}
}
} else if (remotePseduo) {
if (deviceService.getDevice(dstId) == null) {
for (BgpNodeListener l : controller.listener()) {
l.addNode(dstNodeNlri, details);
}
}
}
} else {
if (localPseduo) {
Set<Link> links = linkService.getDeviceLinks(srcId);
if (links == null || links.isEmpty()) {
for (BgpNodeListener l : controller.listener()) {
l.deleteNode(srcNodeNlri);
}
}
} else if (remotePseduo) {
log.info("Remote pseudo delete link ");
Set<Link> links = linkService.getDeviceLinks(dstId);
if (links == null || links.isEmpty()) {
for (BgpNodeListener l : controller.listener()) {
l.deleteNode(dstNodeNlri);
}
}
}
}
}
@Override
public void deleteLink(BgpLinkLsNlriVer4 linkNlri) throws BgpParseException {
log.debug("Delete link {}", linkNlri.toString());
if (linkProviderService == null) {
return;
}
LinkDescription linkDes = buildLinkDes(linkNlri, null, false);
linkProviderService.linkVanished(linkDes);
}
}
@Override
public void triggerProbe(DeviceId deviceId) {
// TODO Auto-generated method stub
}
@Override
public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
}
@Override
public boolean isReachable(DeviceId deviceId) {
// TODO Auto-generated method stub
return true;
}
@Override
public void changePortState(DeviceId deviceId, PortNumber portNumber,
boolean enable) {
}
}