--- /dev/null
+package org.opendaylight.vpnservice;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InterfaceChangeListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceChangeListener.class);
+
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private final DataBroker broker;
+ private VpnInterfaceManager vpnInterfaceManager;
+
+
+ public InterfaceChangeListener(final DataBroker db, VpnInterfaceManager vpnInterfaceManager) {
+ super(Interface.class);
+ broker = db;
+ this.vpnInterfaceManager = vpnInterfaceManager;
+ registerListener(db);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ try {
+ listenerRegistration.close();
+ } catch (final Exception e) {
+ LOG.error("Error when cleaning up DataChangeListener.", e);
+ }
+ listenerRegistration = null;
+ }
+ LOG.info("Interface listener Closed");
+ }
+
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ getWildCardPath(), InterfaceChangeListener.this, DataChangeScope.SUBTREE);
+ } catch (final Exception e) {
+ LOG.error("Interface DataChange listener registration failed", e);
+ throw new IllegalStateException("Nexthop Manager registration Listener failed.", e);
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
+ LOG.trace("Adding Interface : key: " + identifier + ", value=" + intrf );
+
+ }
+
+
+ private InstanceIdentifier<Interface> getWildCardPath() {
+ return InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
+ LOG.trace("Remove interface event - key: {}, value: {}", identifier, intrf );
+ VpnInterface vpnInterface = vpnInterfaceManager.getVpnInterface(intrf.getName());
+ InstanceIdentifier<VpnInterface> id = VpnUtil.getVpnInterfaceIdentifier(intrf.getName());
+ LOG.debug("Removing VPN Interface associated with Interface {}", intrf.getName());
+ vpnInterfaceManager.remove(id, vpnInterface);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Interface> identifier,
+ Interface original, Interface update) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+import org.opendaylight.vpnservice.mdsalutil.NwConstants;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacencyList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
- private ListenerRegistration<DataChangeListener> listenerRegistration;
+ private ListenerRegistration<DataChangeListener> listenerRegistration, interfaceListenerRegistration;
private final DataBroker broker;
private final IBgpManager bgpManager;
private IFibManager fibManager;
private IdManagerService idManager;
private Map<Long, Collection<BigInteger>> vpnToDpnsDb;
private Map<BigInteger, Collection<String>> dpnToInterfaceDb;
+ private InterfaceListener interfaceListener;
private static final FutureCallback<Void> DEFAULT_CALLBACK =
new FutureCallback<Void>() {
this.bgpManager = bgpManager;
vpnToDpnsDb = new ConcurrentHashMap<>();
dpnToInterfaceDb = new ConcurrentHashMap<>();
+ interfaceListener = new InterfaceListener();
registerListener(db);
}
if (listenerRegistration != null) {
try {
listenerRegistration.close();
+ interfaceListenerRegistration.close();
} catch (final Exception e) {
LOG.error("Error when cleaning up DataChangeListener.", e);
}
listenerRegistration = null;
+ interfaceListenerRegistration = null;
}
LOG.info("VPN Interface Manager Closed");
}
try {
listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
+ interfaceListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getInterfaceListenerPath(), interfaceListener, DataChangeScope.SUBTREE);
} catch (final Exception e) {
LOG.error("VPN Service DataChange listener registration fail!", e);
throw new IllegalStateException("VPN Service registration Listener failed.", e);
}
}
+ private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
+ return InstanceIdentifier.create(InterfacesState.class)
+ .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
+ }
+
@Override
protected void add(final InstanceIdentifier<VpnInterface> identifier,
final VpnInterface vpnInterface) {
LOG.trace("Unbind service on interface {} for VPN: {}", intf, vpnName);
long vpnId = getVpnId(vpnName);
- BigInteger dpId = interfaceManager.getDpnForInterface(intf.getName());
+ BigInteger dpId = interfaceManager.getDpnForInterface(intf);
if(dpId.equals(BigInteger.ZERO)) {
LOG.warn("DPN for interface {} not found. Unbind service on this interface aborted.", intf.getName());
return;
} else {
String rd = getRouteDistinguisher(vpnName);
remoteFromMappingDbs(vpnId, dpId, intf.getName(), rd);
+ LOG.debug("removed vpn mapping for interface {} from VPN RD {}", intf.getName(), rd);
}
- long portNo = interfaceManager.getPortForInterface(intf.getName());
+ long portNo = interfaceManager.getPortForInterface(intf);
String flowRef = getVpnInterfaceFlowRef(dpId, VpnConstants.LPORT_INGRESS_TABLE, vpnId, portNo);
String flowName = intf.getName();
FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
priority, flowName, 0, 0, null, matches, null);
+ LOG.debug("Remove ingress flow for port {} in dpn {}", portNo, dpId.intValue());
mdsalManager.removeFlow(flowEntity);
}
label = getUniqueId(nextHop.getIpAddress());
}
removePrefixFromBGP(rd, nextHop);
- updatePrefixToBGP(newRd, nextHop, nextHopIp, label);
+ //updatePrefixToBGP(newRd, nextHop, nextHopIp, label);
}
+ updateNextHops(identifier, update);
asyncUpdate(LogicalDatastoreType.OPERATIONAL, identifier, update, DEFAULT_CALLBACK);
}
} else {
return Collections.emptyList();
}
}
+
+ VpnInterface getVpnInterface(String interfaceName) {
+ Optional<VpnInterfaces> optVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInterfacesIdentifier());
+ if(optVpnInterfaces.isPresent()) {
+ List<VpnInterface> interfaces = optVpnInterfaces.get().getVpnInterface();
+ for(VpnInterface intf : interfaces) {
+ if(intf.getName().equals(interfaceName)) {
+ return intf;
+ }
+ }
+ }
+ return null;
+ }
+
+ private Interface getInterface(String interfaceName) {
+ Optional<Interface> optInterface = read(LogicalDatastoreType.CONFIGURATION, VpnUtil.getInterfaceIdentifier(interfaceName));
+ if(optInterface.isPresent()) {
+ return optInterface.get();
+ }
+ return null;
+ }
+
+ private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
+ return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
+ }
+
+
+ private void makeTunnelIngressFlow(BigInteger dpnId, String ifName, int addOrRemoveFlow) {
+ long portNo = 0;
+ String flowName = ifName;
+ String flowRef = getTunnelInterfaceFlowRef(dpnId, VpnConstants.LPORT_INGRESS_TABLE, ifName);
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
+ if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
+ portNo = interfaceManager.getPortForInterface(ifName);
+ matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
+ dpnId, BigInteger.valueOf(portNo) }));
+ mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {VpnConstants.LFIB_TABLE}));
+ }
+
+ BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
+ VpnConstants.DEFAULT_FLOW_PRIORITY, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
+
+ if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
+ mdsalManager.installFlow(flowEntity);
+ } else {
+ mdsalManager.removeFlow(flowEntity);
+ }
+ }
+
+ private class InterfaceListener extends AbstractDataChangeListener<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> {
+
+ public InterfaceListener() {
+ super(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface del) {
+ LOG.trace("Operational Interface remove event - {}", del);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface original,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface update) {
+ LOG.trace("Operation Interface update event - Old: {}, New: {}", original, update);
+ String interfaceName = update.getName();
+ Interface intf = getInterface(interfaceName);
+ if (intf != null && intf.getType().equals(L3tunnel.class)) {
+ BigInteger dpnId = interfaceManager.getDpnForInterface(interfaceName);
+ if(update.getOperStatus().equals(OperStatus.Up)) {
+ //Create ingress to LFIB
+ LOG.debug("Installing Ingress for tunnel interface {}", interfaceName);
+ makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.ADD_FLOW);
+ } else if(update.getOperStatus().equals(OperStatus.Down)) {
+ LOG.debug("Removing Ingress flow for tunnel interface {}", interfaceName);
+ makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.DEL_FLOW);
+ }
+ } else {
+ VpnInterface vpnInterface = getVpnInterface(interfaceName);
+ if(vpnInterface != null) {
+ if(update.getOperStatus().equals(OperStatus.Up)) {
+ LOG.debug("Installing VPN related rules for interface {}", interfaceName);
+ addInterface(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+ } else if(update.getOperStatus().equals(OperStatus.Down)) {
+ LOG.debug("Removing VPN related rules for interface {}", interfaceName);
+ VpnInterfaceManager.this.remove(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+ }
+ } else {
+ LOG.debug("No VPN Interface associated with interface {} to handle Update Operation", interfaceName);
+ }
+ }
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface add) {
+ LOG.trace("Operational Interface add event - {}", add);
+ String interfaceName = add.getName();
+ Interface intf = getInterface(interfaceName);
+ if (intf != null && intf.getType().equals(L3tunnel.class)) {
+ BigInteger dpnId = interfaceManager.getDpnForInterface(interfaceName);
+ if(add.getOperStatus().equals(OperStatus.Up)) {
+ //Create ingress to LFIB
+ LOG.debug("Installing Ingress for tunnel interface {}", interfaceName);
+ makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.ADD_FLOW);
+ }
+ } else {
+ VpnInterface vpnInterface = getVpnInterface(interfaceName);
+ if(vpnInterface != null) {
+ if(add.getOperStatus().equals(OperStatus.Up)) {
+ LOG.debug("Installing VPN related rules for interface {}", interfaceName);
+ addInterface(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+ }
+ } else {
+ LOG.debug("No VPN Interface associated with interface {} to handle add Operation", interfaceName);
+ }
+ }
+ }
+ }
}