/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
*/
public void setQbgpLog(String fileName, String logLevel) throws Exception;
+ /**
+ * @param rd
+ * @param prefix
+ * @param nextHop
+ * @param vpnLabel
+ */
+ public void advertisePrefix(String rd, String prefix, String nextHop, int vpnLabel) throws Exception;
+
+ /**
+ *
+ * @param rd
+ * @param prefix
+ */
+ public void withdrawPrefix(String rd, String prefix) throws Exception;
+
+
public String getDCGwIP();
}
/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
bcm.delPrefix(rd, prefix);
}
+ @Override
+ public void advertisePrefix(String rd, String prefix, String nextHop, int vpnLabel) throws Exception {
+ bcm.addPrefix(rd, prefix, nextHop, vpnLabel);
+ }
+
+ @Override
+ public void withdrawPrefix(String rd, String prefix) throws Exception {
+ bcm.delPrefix(rd, prefix);
+ }
+
public void setQbgpLog(String fileName, String debugLevel) throws Exception {
bcm.addLogging(fileName, debugLevel);
}
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.RdToElanOp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnToExtraroute;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
+ Long vpnId = vpnInstance.getVpnId();
+ RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, vrfTableKey.getRouteDistinguisher(),
+ vrfEntry.getDestPrefix());
+ if (rdToElanOpEntry!=null) {
+ if (vpnToDpnList!=null) {
+ for (VpnToDpnList curDpn : vpnToDpnList) {
+ installSubnetRouteInFib(curDpn.getDpnId(), rdToElanOpEntry, vpnId.longValue(), vrfEntry);
+ }
+ }
+ return;
+ }
BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
vrfTableKey.getRouteDistinguisher(), vrfEntry);
if (vpnToDpnList != null) {
}
}
+ private void installSubnetRouteInFib(BigInteger dpnId, RdToElanOpEntry rdToElanOpEntry,
+ long vpnId, VrfEntry vrfEntry){
+ makeSubnetRouteFlow(dpnId);
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ Long elanTag = rdToElanOpEntry.getElanTag();
+ instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
+ instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
+ makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
+ instructions,NwConstants.ADD_FLOW);
+ makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
+ vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
+ // TODO makeTunnelTableEntry();
+ }
+
+ private RdToElanOpEntry getRdToElanOpEntry(DataBroker broker, String rd, String subnetIp) {
+ InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(rd,subnetIp);
+ Optional<RdToElanOpEntry> sn = read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if(sn.isPresent()) {
+ return sn.get();
+ }
+ return null;
+ }
+
+ private InstanceIdentifier<RdToElanOpEntry> getRdToElanOpEntryDataPath(String rd, String subnetIp) {
+ return InstanceIdentifier.builder(RdToElanOp.class).child(RdToElanOpEntry.class,
+ new RdToElanOpEntryKey(rd,subnetIp)).build();
+ }
+ private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
+ InstanceIdentifier<T> path) {
+
+ ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+
+ Optional<T> result = Optional.absent();
+ try {
+ result = tx.read(datastoreType, path).get();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return result;
+ }
+
+ private void makeSubnetRouteFlow(BigInteger dpnId) {
+ //Ask Vivek cookie
+ final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+ List<MatchInfo> matches = new ArrayList<MatchInfo>();
+ String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
+ NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
+
+ LOG.debug("Invoking MDSAL to install Table Miss Entries");
+ mdsalManager.syncInstallFlow(flowEntity,1);
+ }
+
+ private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
+ Collection<BigInteger> dpns = new HashSet<>();
+ for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
+ dpns.add(dpn.getDpnId());
+ }
+
+ return dpns;
+ }
+
public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
BigInteger localDpnId = BigInteger.ZERO;
Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
}
if(localNextHopInfo != null) {
- localDpnId = localNextHopInfo.getDpnId();
- long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
- List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
+ localDpnId = localNextHopInfo.getDpnId();
+ long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
- actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
+ List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+ List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+
+ actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
+ instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
+ makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
- makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
- makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
+ actionsInfos=new ArrayList<ActionInfo>();;
+ instructions=new ArrayList<InstructionInfo>();
+ actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+ actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+ makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
- LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
- localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
- makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
+ LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
+ localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
+ makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
}
return localDpnId;
Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
NwConstants.DEL_FLOW);
- makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */,
+ makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
tunnelId}));
}
actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
+ List<InstructionInfo> instructions= new ArrayList<InstructionInfo>();
+ instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
/*
List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
if(actionInfos == null) {
MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
}
**/
- makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
- LOG.debug(
- "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
- }
-
- private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
- InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
- Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
- if (dpnInVpn.isPresent()) {
- List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
- .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
- org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
- currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
-
- if (vpnInterfaces.remove(currVpnInterface)) {
- if (vpnInterfaces.isEmpty()) {
+ makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
+ LOG.debug("Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
+ }
+
+ private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
+ InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
+ Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+ if (dpnInVpn.isPresent()) {
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+ .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
+ org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
+ currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
+
+ if (vpnInterfaces.remove(currVpnInterface)) {
+ if (vpnInterfaces.isEmpty()) {
LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
cleanUpDpnForVpn(dpnId, vpnId, rd);
- } else {
+ } else {
LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
- FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
- org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
- .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
- new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
- }
- }
- }
- }
+ FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+ .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
+ }
+ }
+ }
+ }
private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
/* Get interface info from prefix to interface mapping;
VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
+ RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
+ vrfEntry.getDestPrefix());
+ if (rdToElanOpEntry != null) {
+ if (vpnToDpnList!=null) {
+ for(VpnToDpnList curDpn : vpnToDpnList) {
+ makeConnectedRoute(curDpn.getDpnId(),vpnInstance.getVpnId(),vrfEntry,vrfTableKey
+ .getRouteDistinguisher(), null,NwConstants.DEL_FLOW);
+ makeLFibTableEntry(curDpn.getDpnId(),vrfEntry.getLabel(),null,
+ vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
+ // TODO DeleteTunnelTableEntry();
+ }
+ }
+ //Delete rd-to-elan-op-entry
+ InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
+ vrfEntry.getDestPrefix());
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
+ return;
+ }
BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
vrfTableKey.getRouteDistinguisher(), vrfEntry);
if (vpnToDpnList != null) {
}
private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
- List<ActionInfo> actionInfos, int addOrRemove) {
- LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
+ List<InstructionInfo> instructions, int addOrRemove) { LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
String values[] = vrfEntry.getDestPrefix().split("/");
String ipAddress = values[0];
int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
new long[] { 0x0800L }));
if(prefixLength != 0) {
- matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
- getIpAddress(destPrefix.getAddress()), prefixLength }));
- }
-
- List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
- if(addOrRemove == NwConstants.ADD_FLOW) {
- instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
+ matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+ destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
}
String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
}
}
- private void makeLFibTableEntry(BigInteger dpId, long label, long groupId,
+ private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
String nextHop, int addOrRemove) {
List<MatchInfo> matches = new ArrayList<MatchInfo>();
matches.add(new MatchInfo(MatchFieldType.eth_type,
new long[] { 0x8847L }));
matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
- List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
- List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
- actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
- actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
- instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
-
// Install the flow entry in L3_LFIB_TABLE
String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
} else {
mdsalManager.syncRemoveFlow(flowEntity, 1);
}
- LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId );
+ LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
}
private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
if (vrfTable.isPresent()) {
for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+ RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
+ vrfEntry.getDestPrefix());
+ if (rdToElanOpEntry!= null) {
+ installSubnetRouteInFib(dpnId, rdToElanOpEntry, vpnId, vrfEntry);
+ continue;
+ }
// Passing null as we don't know the dpn
// to which prefix is attached at this point
createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
}
}
+ notification subnet-added-to-vpn{
+ description "new subnet added to vpn";
+ leaf subnet-id {
+ type yang:uuid;
+ }
+ leaf subnet-ip {
+ type string;
+ }
+ leaf vpn-name {
+ type string;
+ }
+ leaf external-vpn {
+ type boolean;
+ }
+ leaf elan-tag {
+ type uint32;
+ }
+ }
+
+ notification subnet-deleted-from-vpn{
+ description "subnet deleted from vpn";
+ leaf subnet-id {
+ type yang:uuid;
+ }
+ leaf subnet-ip {
+ type string;
+ }
+ leaf vpn-name {
+ type string;
+ }
+ leaf external-vpn {
+ type boolean;
+ }
+ leaf elan-tag {
+ type uint32;
+ }
+ }
+
+ notification subnet-updated-in-vpn{
+ description "subnet updated in vpn";
+ leaf subnet-id {
+ type yang:uuid;
+ }
+ leaf subnet-ip {
+ type string;
+ }
+ leaf vpn-name {
+ type string;
+ }
+ leaf external-vpn {
+ type boolean;
+ }
+ leaf elan-tag {
+ type uint32;
+ }
+ }
+
+ notification port-added-to-subnet{
+ description "new port added to subnet";
+ leaf subnet-id{
+ type yang:uuid;
+ }
+ leaf subnet-ip{
+ type string;
+ }
+ leaf port-id{
+ type yang:uuid;
+ }
+ leaf elan-tag {
+ type uint32;
+ }
+ }
+
+ notification port-removed-from-subnet{
+ description "port removed from subnet";
+ leaf subnet-id{
+ type yang:uuid;
+ }
+ leaf subnet-ip{
+ type string;
+ }
+ leaf port-id{
+ type yang:uuid;
+ }
+ leaf elan-tag {
+ type uint32;
+ }
+ }
+
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v1.0 which accompanies this distribution,
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
<name>runtime-mapping-singleton</name>
</binding-normalized-node-serializer>
+ <notification-publish-service>
+ <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-publish-service</type>
+ <name>binding-notification-publish-adapter</name>
+ </notification-publish-service>
+ <notification-service>
+ <type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-service</type>
+ <name>binding-notification-adapter</name>
+ </notification-service>
</module>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
/*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
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.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlanBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortAddedToSubnetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.PortRemovedFromSubnetBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data
.PortFixedipToPortNameBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
private ListenerRegistration<DataChangeListener> listenerRegistration;
private final DataBroker broker;
private NeutronvpnManager nvpnManager;
+ private LockManagerService lockManager;
+ private NotificationPublishService notificationPublishService;
+ private NotificationService notificationService;
- public NeutronPortChangeListener(final DataBroker db, NeutronvpnManager nVpnMgr) {
+ public NeutronPortChangeListener(final DataBroker db, NeutronvpnManager nVpnMgr,NotificationPublishService notiPublishService, NotificationService notiService) {
super(Port.class);
broker = db;
nvpnManager = nVpnMgr;
+ notificationPublishService = notiPublishService;
+ notificationService = notiService;
registerListener(db);
}
+ public void setLockManager(LockManagerService lockManager) {
+ this.lockManager = lockManager;
+ }
+
@Override
public void close() throws Exception {
if (listenerRegistration != null) {
Uuid vpnId = null;
Subnetmap subnetmap = null;
String infName = port.getUuid().getValue();
+ boolean isLockAcquired = false;
+ String lockName = port.getUuid().getValue();
// find the subnet to which this port is associated
FixedIps ip = port.getFixedIps().get(0);
if (subnetmap != null) {
vpnId = subnetmap.getVpnId();
}
+ if(vpnId != null) {
+ try {
+ isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+ checkAndPublishPortAddNotification(subnetmap.getSubnetIp(), subnetId, port.getUuid());
+ LOG.debug("Port added to subnet notification sent");
+ } catch (Exception e) {
+ LOG.error("Port added to subnet notification failed", e);
+ } finally {
+ if (isLockAcquired) {
+ NeutronvpnUtils.unlock(lockManager, lockName);
+ }
+ }
+ }
return vpnId;
}
Uuid subnetId = null;
Uuid vpnId = null;
Subnetmap subnetmap = null;
+ boolean isLockAcquired = false;
+ String lockName = port.getUuid().getValue();
// find the subnet to which this port is associated
FixedIps ip = port.getFixedIps().get(0);
if (subnetmap != null) {
vpnId = subnetmap.getVpnId();
}
+ if(vpnId != null) {
+ try {
+ isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+ checkAndPublishPortRemoveNotification(subnetmap.getSubnetIp(), subnetId, port.getUuid());
+ LOG.debug("Port removed from subnet notification sent");
+ } catch (Exception e) {
+ LOG.error("Port removed from subnet notification failed", e);
+ } finally {
+ if (isLockAcquired) {
+ NeutronvpnUtils.unlock(lockManager, lockName);
+ }
+ }
+ }
return vpnId;
}
+
+ private void checkAndPublishPortAddNotification(String subnetIp, Uuid subnetId, Uuid portId)throws InterruptedException{
+ PortAddedToSubnetBuilder builder = new PortAddedToSubnetBuilder();
+
+ LOG.info("publish notification called");
+
+ builder.setSubnetIp(subnetIp);
+ builder.setSubnetId(subnetId);
+ builder.setPortId(portId);
+
+ notificationPublishService.putNotification(builder.build());
+ }
+
+ private void checkAndPublishPortRemoveNotification(String subnetIp, Uuid subnetId, Uuid portId)throws InterruptedException{
+ PortRemovedFromSubnetBuilder builder = new PortRemovedFromSubnetBuilder();
+
+ LOG.info("publish notification called");
+
+ builder.setPortId(portId);
+ builder.setSubnetIp(subnetIp);
+ builder.setSubnetId(subnetId);
+
+ notificationPublishService.putNotification(builder.build());
+ }
}
/*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
import com.google.common.base.Optional;
import com.google.common.util.concurrent.SettableFuture;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.AssociateNetworksInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.AssociateNetworksOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.AssociateNetworksOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.AssociateRouterInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.CreateL3VPNInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.CreateL3VPNOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.CreateL3VPNOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DeleteL3VPNInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DeleteL3VPNOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DeleteL3VPNOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DissociateNetworksInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DissociateNetworksOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DissociateNetworksOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DissociateRouterInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602
- .GetFixedIPsForNeutronPortOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetL3VPNInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetL3VPNInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetL3VPNOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetL3VPNOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.L3vpnInstance;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.Subnetmaps;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.VpnMaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.*;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.createl3vpn.input.L3vpn;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.getl3vpn.output.L3vpnInstances;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.getl3vpn.output
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.vpnmaps.VpnMapBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.vpnmaps.VpnMapKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import java.util.EventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
-public class NeutronvpnManager implements NeutronvpnService, AutoCloseable {
+public class NeutronvpnManager implements NeutronvpnService, AutoCloseable , EventListener{
private static final Logger logger = LoggerFactory.getLogger(NeutronvpnManager.class);
private final DataBroker broker;
private LockManagerService lockManager;
IMdsalApiManager mdsalUtil;
+ private NotificationPublishService notificationPublishService;
+ private NotificationService notificationService;
+ Boolean isExternalVpn;
/**
* @param db - dataBroker reference
* @param mdsalManager - MDSAL Util API access
*/
- public NeutronvpnManager(final DataBroker db, IMdsalApiManager mdsalManager) {
+ public NeutronvpnManager(final DataBroker db, IMdsalApiManager mdsalManager,NotificationPublishService notiPublishService,
+ NotificationService notiService) {
broker = db;
mdsalUtil = mdsalManager;
+ notificationPublishService = notiPublishService;
+ notificationService = notiService;
}
public void setLockManager(LockManagerService lockManager) {
protected void addSubnetToVpn(Uuid vpnId, Uuid subnet) {
logger.debug("Adding subnet {} to vpn {}", subnet.getValue(), vpnId.getValue());
Subnetmap sn = updateSubnetNode(subnet, null, null, null, null, vpnId, null);
+ boolean isLockAcquired = false;
+ String lockName = vpnId.getValue() + subnet.getValue();
+ String elanInstanceName = sn.getNetworkId().getValue();
+ InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+ Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
+ long elanTag = elanInstance.get().getElanTag();
+ if(vpnId.equals(NeutronvpnUtils.getVpnMap(broker,vpnId).getRouterId())){isExternalVpn = false;}
+ else {isExternalVpn = true;}
+ try {
+ isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+ checkAndPublishSubnetAddNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isExternalVpn, elanTag);
+ logger.debug("Subnet added to Vpn notification sent");
+ }catch (Exception e){
+ logger.error("Subnet added to Vpn notification failed",e);
+ }finally {
+ if (isLockAcquired) {
+ NeutronvpnUtils.unlock(lockManager, lockName);
+ }
+ }
// Check if there are ports on this subnet and add corresponding vpn-interfaces
List<Uuid> portList = sn.getPortList();
if (portList != null) {
}
}
- protected void updateVpnForSubnet(Uuid vpnId, Uuid subnet) {
+ protected void updateVpnForSubnet(Uuid vpnId, Uuid subnet, boolean isBeingAssociated) {
logger.debug("Updating VPN {} for subnet {}", vpnId.getValue(), subnet.getValue());
Subnetmap sn = updateSubnetNode(subnet, null, null, null, null, vpnId, null);
+ boolean isLockAcquired = false;
+ String lockName = vpnId.getValue() + subnet.getValue();
+ String elanInstanceName = sn.getNetworkId().getValue();
+ InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+ Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
+ long elanTag = elanInstance.get().getElanTag();
+ try {
+ isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+ checkAndPublishSubnetUpdNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isBeingAssociated, elanTag);
+ logger.debug("Subnet updated in Vpn notification sent");
+ }catch (Exception e){
+ logger.error("Subnet updated in Vpn notification failed",e);
+ }finally {
+ if (isLockAcquired) {
+ NeutronvpnUtils.unlock(lockManager, lockName);
+ }
+ }
// Check for ports on this subnet and update association of corresponding vpn-interfaces to external vpn
List<Uuid> portList = sn.getPortList();
if (portList != null) {
protected void removeSubnetFromVpn(Uuid vpnId, Uuid subnet) {
logger.debug("Removing subnet {} from vpn {}", subnet.getValue(), vpnId.getValue());
Subnetmap sn = NeutronvpnUtils.getSubnetmap(broker, subnet);
+ boolean isLockAcquired = false;
+ String lockName = vpnId.getValue() + subnet.getValue();
+ String elanInstanceName = sn.getNetworkId().getValue();
+ InstanceIdentifier<ElanInstance>elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+ Optional<ElanInstance> elanInstance = NeutronvpnUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
+ long elanTag = elanInstance.get().getElanTag();
+ if(vpnId.equals(NeutronvpnUtils.getVpnMap(broker,vpnId).getRouterId())){isExternalVpn = false;}
+ else {isExternalVpn = true;}
+ try {
+ isLockAcquired = NeutronvpnUtils.lock(lockManager, lockName);
+ checkAndPublishSubnetDelNotification(subnet, sn.getSubnetIp(), vpnId.getValue(), isExternalVpn, elanTag);
+ logger.debug("Subnet removed from Vpn notification sent");
+ }catch (Exception e){
+ logger.error("Subnet removed from Vpn notification failed",e);
+ }finally {
+ if (isLockAcquired) {
+ NeutronvpnUtils.unlock(lockManager, lockName);
+ }
+ }
if (sn != null) {
// Check if there are ports on this subnet; remove corresponding vpn-interfaces
List<Uuid> portList = sn.getPortList();
logger.debug("Updating association of subnets to external vpn {}", vpnId.getValue());
if (routerSubnets != null) {
for (Uuid subnetId : routerSubnets) {
- updateVpnForSubnet(vpnId, subnetId);
+ updateVpnForSubnet(vpnId, subnetId,true);
}
}
} else {
if (routerSubnets != null) {
for (Uuid subnetId : routerSubnets) {
logger.debug("Updating association of subnets to internal vpn {}", routerId.getValue());
- updateVpnForSubnet(routerId, subnetId);
+ updateVpnForSubnet(routerId, subnetId,false);
}
}
clearFromVpnMaps(vpnId, routerId, null);
return help.toString();
}
+ private void checkAndPublishSubnetAddNotification(Uuid subnetId, String subnetIp, String vpnName, Boolean isExternalvpn, Long elanTag)throws InterruptedException{
+ SubnetAddedToVpnBuilder builder = new SubnetAddedToVpnBuilder();
+
+ logger.info("publish notification called");
+
+ builder.setSubnetId(subnetId);
+ builder.setSubnetIp(subnetIp);
+ builder.setVpnName(vpnName);
+ builder.setExternalVpn(isExternalvpn);
+ builder.setElanTag(elanTag);
+
+ notificationPublishService.putNotification(builder.build());
+ }
+
+ private void checkAndPublishSubnetDelNotification(Uuid subnetId, String subnetIp, String vpnName, Boolean isExternalvpn, Long elanTag)throws InterruptedException{
+ SubnetDeletedFromVpnBuilder builder = new SubnetDeletedFromVpnBuilder();
+
+ logger.info("publish notification called");
+
+ builder.setSubnetId(subnetId);
+ builder.setSubnetIp(subnetIp);
+ builder.setVpnName(vpnName);
+ builder.setExternalVpn(isExternalvpn);
+ builder.setElanTag(elanTag);
+
+ notificationPublishService.putNotification(builder.build());
+ }
+
+ private void checkAndPublishSubnetUpdNotification(Uuid subnetId, String subnetIp, String vpnName, Boolean isExternalvpn, Long elanTag)throws InterruptedException{
+ SubnetUpdatedInVpnBuilder builder = new SubnetUpdatedInVpnBuilder();
+
+ logger.info("publish notification called");
+
+ builder.setSubnetId(subnetId);
+ builder.setSubnetIp(subnetIp);
+ builder.setVpnName(vpnName);
+ builder.setExternalVpn(isExternalvpn);
+ builder.setElanTag(elanTag);
+
+ notificationPublishService.putNotification(builder.build());
+ }
+
}
/*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
package org.opendaylight.vpnservice.neutronvpn;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private L2GatewayProvider l2GatewayProvider;
private EntityOwnershipService entityOwnershipService;
private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+ private NotificationPublishService notificationPublishService;
+ private NotificationService notificationService;
- public NeutronvpnProvider(RpcProviderRegistry rpcRegistry) {
+ public NeutronvpnProvider(RpcProviderRegistry rpcRegistry,NotificationPublishService notificationPublishService,
+ NotificationService notificationService) {
this.rpcProviderRegistry = rpcRegistry;
+ this.notificationPublishService = notificationPublishService;
+ this.notificationService = notificationService;
}
public RpcProviderRegistry getRpcProviderRegistry() {
public void onSessionInitiated(ProviderContext session) {
try {
final DataBroker dbx = session.getSALService(DataBroker.class);
- nvManager = new NeutronvpnManager(dbx, mdsalManager);
+ nvManager = new NeutronvpnManager(dbx, mdsalManager,notificationPublishService,notificationService);
final BindingAwareBroker.RpcRegistration<NeutronvpnService> rpcRegistration =
getRpcProviderRegistry().addRpcImplementation(NeutronvpnService.class, nvManager);
bgpvpnListener = new NeutronBgpvpnChangeListener(dbx, nvManager);
networkListener = new NeutronNetworkChangeListener(dbx, nvManager);
subnetListener = new NeutronSubnetChangeListener(dbx, nvManager);
routerListener = new NeutronRouterChangeListener(dbx, nvManager);
- portListener = new NeutronPortChangeListener(dbx, nvManager);
+ portListener = new NeutronPortChangeListener(dbx, nvManager,notificationPublishService,notificationService);
+ portListener.setLockManager(lockManager);
nvManager.setLockManager(lockManager);
l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService,
bindingNormalizedNodeSerializer);
/*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
public java.lang.AutoCloseable createInstance() {
// TODO:implement
LockManagerService lockManagerService = getRpcRegistryDependency().getRpcService(LockManagerService.class);
- NeutronvpnProvider provider = new NeutronvpnProvider(getRpcRegistryDependency());
+ NeutronvpnProvider provider = new NeutronvpnProvider(getRpcRegistryDependency(),
+ getNotificationPublishServiceDependency(),getNotificationServiceDependency());
provider.setMdsalManager(getMdsalutilDependency());
provider.setLockManager(lockManagerService);
provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
}
}
}
+
+ container notification-publish-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding-impl:binding-new-notification-publish-service;
+ }
+ }
+ }
+ container notification-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding-impl:binding-new-notification-service;
+ }
+ }
+ }
}
}
}
import yang-ext {prefix ext; revision-date "2013-07-09";}
import l3vpn { prefix l3vpn; revision-date "2014-08-15"; }
+ import ietf-yang-types { prefix "yang"; }
revision "2013-09-11" {
description "L3 VPN Service module";
}
}
+ typedef task-state {
+ type enumeration {
+ enum na {
+ value "0";
+ description
+ "Task not applicable";
+ }
+ enum pending {
+ value "1";
+ description
+ "Task is in pending state";
+ }
+ enum done {
+ value "2";
+ description
+ "Task has been completed";
+ }
+ }
+ description
+ "This value the status of any task.
+ The possible values are NA, PENDING or DONE.
+ ";
+ }
+
+
+ container subnet-op-data {
+ list subnet-op-data-entry {
+ key subnet-id;
+ leaf subnet-id {
+ type yang:uuid;
+ description "UUID representing the subnet ";
+ }
+ leaf nh-dpnId {
+ type uint64;
+ description "DpnId for the DPN used as nexthop for this subnet";
+ }
+ leaf vpn-name {
+ type string;
+ description "VPN Instance name";
+ }
+ leaf vrf-id {
+ type string;
+ }
+ leaf subnet-cidr {
+ type string;
+ description "Subnet in cidr notation";
+ }
+ leaf route-adv-state {
+ type task-state;
+ description "The status of the subnet route advertisement. Route advertisement could be in a NA, PENDING or DONE state.";
+ }
+ leaf elan-tag{
+ type uint32;
+ }
+ list subnet-to-dpn {
+ key dpnId;
+ leaf dpnId {
+ type uint64;
+ }
+ list vpn-interfaces {
+ key interface-name;
+ leaf interface-name {
+ type string;
+ }
+ }
+ }
+
+ }
+ }
+
+ container port-op-data {
+ list port-op-data-entry {
+ key port-id;
+ leaf port-id {
+ type string;
+ description "UUID in string format representing the port ";
+ }
+ leaf subnet-id {
+ type yang:uuid;
+ description "Back reference to obtain the subnet for a port ";
+ }
+ leaf dpnId {
+ type uint64;
+ }
+ }
+ }
+
+ container rd-to-elan-op{
+ list rd-to-elan-op-entry{
+ key "rd subnet-ip";
+ leaf rd {
+ type string;
+ }
+ leaf subnet-ip {
+ type string;
+ }
+ leaf next-hop-ip {
+ type string;
+ }
+ leaf vpn-name {
+ type string;
+ }
+ leaf elan-tag{
+ type uint32;
+ }
+ }
+ }
+
}
\ No newline at end of file
<artifactId>arputil-api</artifactId>
<version>${vpnservices.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>neutronvpn-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.vpnservice</groupId>
+ <artifactId>elanmanager-api</artifactId>
+ <version>${vpnservices.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
}
} else {
vpnInterfaceManager.processVpnInterfaceUp(dpnId, interfaceName, intrf.getIfIndex());
+ vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(intrf);
}
} catch (Exception e) {
LOG.error("Exception caught in Interface Operational State Up event", e);
} else {
if (VpnUtil.isVpnInterfaceConfigured(broker, interfaceName)) {
vpnInterfaceManager.processVpnInterfaceDown(dpId, interfaceName, intrf.getIfIndex(), true);
+ vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(intrf);
}
}
} catch (Exception e) {
if(update.getOperStatus().equals(Interface.OperStatus.Up)) {
//advertise all prefixes in all vpns for this dpn to bgp
// vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.ADVERTISE_ROUTE);
+ vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceUp(update);
} else if(update.getOperStatus().equals(Interface.OperStatus.Down)) {
//withdraw all prefixes in all vpns for this dpn from bgp
// vpnInterfaceManager.updatePrefixesForDPN(dpnId, VpnInterfaceManager.UpdateRouteAction.WITHDRAW_ROUTE);
+ vpnInterfaceManager.getVpnSubnetRouteHandler().onInterfaceDown(update);
}*/
}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfacesKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PortOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.SubnetOpData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpnBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpnKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.math.BigInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+
+public class SubnetOpDpnManager {
+ private static final Logger logger = LoggerFactory.getLogger(SubnetOpDpnManager.class);
+
+ private final DataBroker broker;
+
+ public SubnetOpDpnManager(final DataBroker db) {
+ broker = db;
+ }
+
+ private SubnetToDpn addDpnToSubnet(Uuid subnetId, BigInteger dpnId) {
+ SubnetToDpn subDpn = null;
+ try {
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ InstanceIdentifier<SubnetToDpn> dpnOpId = subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
+ Optional<SubnetToDpn> optionalSubDpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+ if (optionalSubDpn.isPresent()) {
+ logger.error("Cannot create, SubnetToDpn for subnet " + subnetId.getValue() +
+ " as DPN " + dpnId + " already seen in datastore");
+ return null;
+ }
+ SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder().setKey(new SubnetToDpnKey(dpnId));
+ List<VpnInterfaces> vpnIntfList = new ArrayList<VpnInterfaces>();
+ subDpnBuilder.setVpnInterfaces(vpnIntfList);
+ subDpn = subDpnBuilder.build();
+ logger.trace("Creating SubnetToDpn entry for subnet " + subnetId.getValue() + " with DPNId "+ dpnId);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId, subDpn);
+ } catch (Exception ex) {
+ logger.error("Creation of SubnetToDpn for subnet " +
+ subnetId.getValue() + " with DpnId " + dpnId + " failed {}" + ex);
+ return null;
+ } finally {
+ }
+ return subDpn;
+ }
+
+ private void removeDpnFromSubnet(Uuid subnetId, BigInteger dpnId) {
+ try {
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ InstanceIdentifier<SubnetToDpn> dpnOpId =subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
+ Optional<SubnetToDpn> optionalSubDpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+ if (!optionalSubDpn.isPresent()) {
+ logger.warn("Cannot delete, SubnetToDpn for subnet " + subnetId.getValue() +
+ " DPN " + dpnId + " not available in datastore");
+ return;
+ }
+ logger.trace("Deleting SubnetToDpn entry for subnet " + subnetId.getValue() + " with DPNId "+ dpnId);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+ } catch (Exception ex) {
+ logger.error("Deletion of SubnetToDpn for subnet " +
+ subnetId.getValue() + " with DPN " + dpnId + " failed {}" + ex);
+ } finally {
+ }
+ }
+
+ public SubnetToDpn addInterfaceToDpn(Uuid subnetId, BigInteger dpnId, String intfName) {
+ SubnetToDpn subDpn = null;
+ try {
+ // Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ //Please use a synchronize block here as we donot need a cluster-wide lock
+ InstanceIdentifier<SubnetToDpn> dpnOpId = subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
+ Optional<SubnetToDpn> optionalSubDpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+ if (!optionalSubDpn.isPresent()) {
+ // Create a new DPN Entry
+ subDpn = addDpnToSubnet(subnetId, dpnId);
+ } else {
+ subDpn = optionalSubDpn.get();
+ }
+ SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder(subDpn);
+ List<VpnInterfaces> vpnIntfList = subDpnBuilder.getVpnInterfaces();
+ VpnInterfaces vpnIntfs = new VpnInterfacesBuilder().setKey(new VpnInterfacesKey(intfName)).setInterfaceName(intfName).build();
+ vpnIntfList.add(vpnIntfs);
+ subDpnBuilder.setVpnInterfaces(vpnIntfList);
+ subDpn = subDpnBuilder.build();
+
+ logger.trace("Creating SubnetToDpn entry for subnet " + subnetId.getValue() + " with DPNId "+ dpnId);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId, subDpn);
+ } catch (Exception ex) {
+ logger.error("Addition of Interface " + intfName + " for SubnetToDpn on subnet " +
+ subnetId.getValue() + " with DPN " + dpnId + " failed {}" + ex);
+ return null;
+ } finally {
+ }
+ return subDpn;
+ }
+
+ public void addPortOpDataEntry(String intfName, Uuid subnetId, BigInteger dpnId) {
+ try {
+ // Add to PortOpData as well.
+ PortOpDataEntryBuilder portOpBuilder = null;
+ PortOpDataEntry portOpEntry = null;
+
+ InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
+ child(PortOpDataEntry.class, new PortOpDataEntryKey(intfName)).build();
+ Optional<PortOpDataEntry> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+ if (!optionalPortOp.isPresent()) {
+ // Create PortOpDataEntry only if not present
+ portOpBuilder = new PortOpDataEntryBuilder().setKey(new PortOpDataEntryKey(intfName)).setPortId(intfName);
+ portOpBuilder.setSubnetId(subnetId);
+ portOpBuilder.setDpnId(dpnId);
+ portOpEntry = portOpBuilder.build();
+ } else {
+ portOpBuilder = new PortOpDataEntryBuilder(optionalPortOp.get());
+ portOpBuilder.setSubnetId(subnetId);
+ portOpBuilder.setDpnId(dpnId);
+ portOpEntry = portOpBuilder.build();
+ }
+ logger.trace("Creating PortOpData entry for port " + intfName + " with DPNId "+ dpnId);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier, portOpEntry);
+ } catch (Exception ex) {
+ logger.error("Addition of Interface " + intfName + " for SubnetToDpn on subnet " +
+ subnetId.getValue() + " with DPN " + dpnId + " failed {}" + ex);
+ } finally {
+ }
+ }
+
+ public boolean removeInterfaceFromDpn(Uuid subnetId, BigInteger dpnId, String intfName) {
+ boolean dpnRemoved = false;
+ try {
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ InstanceIdentifier<SubnetToDpn> dpnOpId = subOpIdentifier.child(SubnetToDpn.class, new SubnetToDpnKey(dpnId));
+ Optional<SubnetToDpn> optionalSubDpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId);
+ if (!optionalSubDpn.isPresent()) {
+ logger.warn("Cannot delete, SubnetToDpn for subnet " + subnetId.getValue() +
+ " DPN " + dpnId + " not available in datastore");
+ return false;
+ }
+
+ SubnetToDpnBuilder subDpnBuilder = new SubnetToDpnBuilder(optionalSubDpn.get());
+ List<VpnInterfaces> vpnIntfList = subDpnBuilder.getVpnInterfaces();
+ VpnInterfaces vpnIntfs = new VpnInterfacesBuilder().setKey(new VpnInterfacesKey(intfName)).setInterfaceName(intfName).build();
+ vpnIntfList.remove(vpnIntfs);
+ if (vpnIntfList.isEmpty()) {
+ // Remove the DPN as well
+ removeDpnFromSubnet(subnetId, dpnId);
+ dpnRemoved = true;
+ } else {
+ subDpnBuilder.setVpnInterfaces(vpnIntfList);
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnOpId, subDpnBuilder.build());
+ }
+ } catch (Exception ex) {
+ logger.error("Deletion of Interface " + intfName + " for SubnetToDpn on subnet " +
+ subnetId.getValue() + " with DPN " + dpnId + " failed {}" + ex);
+ return false;
+ } finally {
+ }
+ return dpnRemoved;
+ }
+
+ public PortOpDataEntry removePortOpDataEntry(String intfName) {
+ // Remove PortOpData and return out
+ InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
+ child(PortOpDataEntry.class, new PortOpDataEntryKey(intfName)).build();
+ PortOpDataEntry portOpEntry = null;
+ Optional<PortOpDataEntry> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+ if (!optionalPortOp.isPresent()) {
+ logger.error("Cannot delete, portOp for port " + intfName +
+ " is not available in datastore");
+ return null;
+ } else {
+ portOpEntry = optionalPortOp.get();
+ logger.trace("Deleting portOpData entry for port " + intfName);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+ }
+ return portOpEntry;
+ }
+
+ public PortOpDataEntry getPortOpDataEntry(String intfName) {
+ // Remove PortOpData and return out
+ InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
+ child(PortOpDataEntry.class, new PortOpDataEntryKey(intfName)).build();
+ Optional<PortOpDataEntry> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+ if (!optionalPortOp.isPresent()) {
+ logger.error("Cannot get, portOp for port " + intfName +
+ " is not available in datastore");
+ return null;
+ }
+ return optionalPortOp.get();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vpnservice;
+
+import com.google.common.base.Optional;
+import com.google.common.primitives.Ints;
+import org.opendaylight.controller.liblldp.EtherTypes;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.SubnetOpData;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NetworkMaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.networkmaps.NetworkMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.networkmaps.NetworkMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.vpnservice.mdsalutil.packet.ARP;
+import org.opendaylight.vpnservice.mdsalutil.packet.IPv4;
+import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.controller.liblldp.Packet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.nio.charset.StandardCharsets;
+import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
+import org.opendaylight.vpnservice.mdsalutil.ActionType;
+import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
+
+public class SubnetRoutePacketInHandler implements PacketProcessingListener {
+
+ private static final Logger s_logger = LoggerFactory.getLogger(SubnetRoutePacketInHandler.class);
+ private final DataBroker broker;
+ private PacketProcessingService packetService;
+ private VpnInterfaceManager ifManager;
+ private IdManagerService idManager;
+ //List maintains info about the arp request sent - id src+dst ip
+ private ArrayList<String> arpList = new ArrayList();
+
+ public SubnetRoutePacketInHandler(DataBroker dataBroker, IdManagerService idManager) {
+ broker = dataBroker;
+ this.idManager = idManager;
+ }
+
+ public void onPacketReceived(PacketReceived notification) {
+
+ s_logger.debug("SubnetRoutePacketInHandler: PacketReceived invoked...");
+
+ short tableId = notification.getTableId().getValue();
+ byte[] data = notification.getPayload();
+ BigInteger metadata = notification.getMatch().getMetadata().getMetadata();
+ Ethernet res = new Ethernet();
+
+ if (notification.getPacketInReason() == SendToController.class) { /*&& tableId == VpnConstants.FIB_TABLE) {*/
+ try {
+ s_logger.debug("SubnetRoutePacketInHandler: Some packet received");
+ res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+ Packet pkt = res.getPayload();
+ if (pkt instanceof IPv4) {
+ IPv4 ipv4 = (IPv4) pkt;
+ byte[] srcMac = res.getSourceMACAddress();
+ byte[] dstMac = res.getDestinationMACAddress();
+ byte[] srcIp = Ints.toByteArray(ipv4.getSourceAddress());
+ byte[] dstIp = Ints.toByteArray(ipv4.getDestinationAddress());
+ String dstIpStr = toStringIpAddress(dstIp);
+ String srcIpStr = toStringIpAddress(srcIp);
+ if (VpnUtil.getNeutronPortNamefromPortFixedIp(broker, dstIpStr) != null) {
+ s_logger.debug("SubnetRoutePacketInHandler: IPv4 Packet received with "
+ + "Target IP {} is a valid Neutron port, ignoring subnet route processing", dstIpStr);
+ return;
+ }
+ long elanTag = MetaDataUtil.getElanTagFromMetadata(metadata);
+ s_logger.debug("SubnetRoutePacketInHandler: Elan Tag obtained as {}" , elanTag);
+ if (elanTag == 0) {
+ s_logger.error("SubnetRoutePacketInHandler: elanTag value from metadata found to be 0, for IPv4 " +
+ "Packet received with Target IP {}", dstIpStr);
+ return;
+ }
+ s_logger.info("SubnetRoutePacketInHandler: Processing IPv4 Packet received with Source IP {} "
+ + "and Target IP {}", srcIpStr, dstIpStr);
+ BigInteger dpnId = getTargetDpnForPacketOut(broker, elanTag, ipv4.getDestinationAddress());
+ //Handle subnet routes ip requests
+ if (dpnId != BigInteger.ZERO) {
+ long groupid = VpnUtil.getRemoteBCGroup(elanTag);
+ String key = srcIpStr + dstIpStr;
+ sendArpRequest(dpnId, groupid, srcMac, srcIp, dstIp);
+ arpList.add(key);
+ }
+ return;
+ }
+
+ if (pkt instanceof ARP) {
+ s_logger.debug("SubnetRoutePacketInHandler: ARP packet received");
+ ARP arpPacket = (ARP) pkt;
+ boolean arpReply = (arpPacket.getOpCode() == 2) ? true : false;
+ if (arpReply) {
+ //Handle subnet routes arp responses
+ s_logger.debug("SubnetRoutePacketInHandler: ARP reply received");
+ byte[] respSrc = arpPacket.getSenderProtocolAddress();
+ byte[] respDst = arpPacket.getTargetProtocolAddress();
+ String respIp = toStringIpAddress(respSrc);
+ String check = toStringIpAddress(respDst) + respIp;
+ if (arpList.contains(check)) {
+ s_logger.debug("SubnetRoutePacketInHandler: ARP reply received for listening target IP " + respIp);
+ String destination = VpnUtil.getIpPrefix(respIp);
+ long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+ s_logger.debug("SubnetRoutePacketInHandler Lport Tag of arp replier " + portTag);
+ IfIndexInterface interfaceInfo = VpnUtil.getInterfaceInfoByInterfaceTag(broker, portTag);
+ String ifName = interfaceInfo.getInterfaceName();
+ InstanceIdentifier<VpnInterface> vpnIfIdentifier = VpnUtil.getVpnInterfaceIdentifier(ifName);
+ VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, ifName);
+
+ //Get VPN interface adjacencies
+ if (vpnInterface != null) {
+ InstanceIdentifier<Adjacencies> path = vpnIfIdentifier.augmentation(Adjacencies.class);
+ Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
+ String nextHopIpAddr = null;
+ String nextHopMacAddress = null;
+ if (adjacencies.isPresent()) {
+ List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
+ for (Adjacency adjacs : adjacencyList) {
+ if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
+ nextHopIpAddr = adjacs.getIpAddress();
+ nextHopMacAddress = adjacs.getMacAddress();
+ break;
+ }
+ }
+ if (nextHopMacAddress != null && destination != null) {
+ String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
+ long label =
+ VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+ VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnInterface.getVpnInstanceName(), destination));
+ String nextHopIp = nextHopIpAddr.split("/")[0];
+ Adjacency newAdj = new AdjacencyBuilder().setIpAddress(destination).setKey
+ (new AdjacencyKey(destination)).setNextHopIp(nextHopIp).build();
+ adjacencyList.add(newAdj);
+ Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
+ VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface.getName())).
+ setName(vpnInterface.getName()).setVpnInstanceName(vpnInterface.getVpnInstanceName()).
+ addAugmentation(Adjacencies.class, aug).build();
+ VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, newVpnIntf);
+ s_logger.debug("SubnetRoutePacketInHandler: Successfully stored subnetroute Adjacency into VpnInterface {}", newVpnIntf);
+ }
+ }
+ }
+ //Remove from list once response was processed
+ arpList.remove(check);
+ }
+ }
+ }
+ } catch (Exception ex) {
+ //Failed to decode packet
+ s_logger.error("SubnetRoutePacketInHandler: Failed to handle subnetroute packets {}", ex);
+ }
+ }
+ }
+
+ private static BigInteger getTargetDpnForPacketOut(DataBroker broker, long elanTag, int ipAddress) {
+ BigInteger dpnid = BigInteger.ZERO;
+ ElanTagName elanInfo = VpnUtil.getElanInfoByElanTag(broker, elanTag);
+ if (elanInfo == null) {
+ s_logger.trace("SubnetRoutePacketInHandler: Unable to retrieve ElanInfo for elanTag {}", elanTag);
+ return dpnid;
+ }
+ InstanceIdentifier<NetworkMap> networkId = InstanceIdentifier.builder(NetworkMaps.class)
+ .child(NetworkMap.class, new NetworkMapKey(new Uuid(elanInfo.getName()))).build();
+ s_logger.trace("SubnetRoutePacketInHandler: Obtained target ip address as " + ipAddress);
+ s_logger.trace("SubnetRoutePacketInHandler: Obtained elanTag as " + elanTag);
+ s_logger.trace("SubnetRoutePacketInHandler: Obtained elanInfo as " + elanInfo);
+ s_logger.trace("SubnetRoutePacketInHandler: Obtained network name as " + elanInfo.getName());
+
+ Optional<NetworkMap> optionalNetworkMap = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, networkId);
+ if (optionalNetworkMap.isPresent()) {
+ List<Uuid> subnetList = optionalNetworkMap.get().getSubnetIdList();
+ s_logger.trace("SubnetRoutePacketInHandler: Obtained subnetList as " + subnetList);
+ for (Uuid subnetId : subnetList) {
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+ subOpIdentifier);
+ if (!optionalSubs.isPresent()) {
+ continue;
+ }
+ s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId.getValue());
+ SubnetOpDataEntry subOpEntry = optionalSubs.get();
+ if (subOpEntry.getNhDpnId() != null) {
+ boolean match = VpnUtil.isIpInSubnet(ipAddress, subOpEntry.getSubnetCidr());
+ s_logger.trace("SubnetRoutePacketInHandler: Viewing Subnet " + subnetId + " matching " + match);
+ if (match) {
+ dpnid = subOpEntry.getNhDpnId();
+ return dpnid;
+ }
+ }
+ }
+ }
+ return dpnid;
+ }
+
+ private static String toStringIpAddress(byte[] ipAddress)
+ {
+ String ip = null;
+ if (ipAddress == null) {
+ return ip;
+ }
+
+ try {
+ ip = InetAddress.getByAddress(ipAddress).getHostAddress();
+ } catch(UnknownHostException e) {
+ s_logger.error("SubnetRoutePacketInHandler: Unable to translate byt[] ipAddress to String {}", e);
+ }
+
+ return ip;
+ }
+
+ public void setPacketProcessingService(PacketProcessingService service) {
+ this.packetService = service;
+ }
+
+ private long getDpnIdFromPktRcved(PacketReceived packet) {
+ InstanceIdentifier<?> identifier = packet.getIngress().getValue();
+ NodeId id = identifier.firstKeyOf(Node.class, NodeKey.class).getId();
+ return getDpnIdFromNodeName(id.getValue());
+ }
+
+ private long getDpnIdFromNodeName(String nodeName) {
+ String dpId = nodeName.substring(nodeName.lastIndexOf(":") + 1);
+ return Long.parseLong(dpId);
+ }
+
+ private void sendArpRequest(BigInteger dpnId, long groupId, byte[] abySenderMAC, byte[] abySenderIpAddress,
+ byte[] abyTargetIpAddress) {
+
+ s_logger.info("SubnetRoutePacketInHandler: sendArpRequest dpnId {}, groupId {}, senderMAC {}, senderIPAddress {}, targetIPAddress {}",
+ dpnId, groupId,new String(abySenderMAC, StandardCharsets.UTF_8),
+ toStringIpAddress(abySenderIpAddress),toStringIpAddress(abyTargetIpAddress));
+ if (abySenderIpAddress != null) {
+ byte[] arpPacket;
+ byte[] ethPacket;
+ List<ActionInfo> lstActionInfo;
+ TransmitPacketInput transmitPacketInput;
+
+ arpPacket = createARPPacket(ARP.REQUEST, abySenderMAC, abySenderIpAddress, VpnConstants.MAC_Broadcast,
+ abyTargetIpAddress);
+ ethPacket = createEthernetPacket(abySenderMAC, VpnConstants.EthernetDestination_Broadcast, arpPacket);
+ lstActionInfo = new ArrayList<ActionInfo>();
+ lstActionInfo.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
+ transmitPacketInput = MDSALUtil.getPacketOutDefault(lstActionInfo, ethPacket, dpnId);
+ packetService.transmitPacket(transmitPacketInput);
+ } else {
+ s_logger.info("SubnetRoutePacketInHandler: Unable to send ARP request because client port has no IP ");
+ }
+ }
+
+ private static byte[] createARPPacket(short opCode, byte[] senderMacAddress, byte[] senderIP, byte[] targetMacAddress,
+ byte[] targetIP) {
+ ARP arp = new ARP();
+ byte[] rawArpPkt = null;
+ try {
+ arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
+ arp.setProtocolType(EtherTypes.IPv4.shortValue());
+ arp.setHardwareAddressLength((byte) 6);
+ arp.setProtocolAddressLength((byte) 4);
+ arp.setOpCode(opCode);
+ arp.setSenderHardwareAddress(senderMacAddress);
+ arp.setSenderProtocolAddress(senderIP);
+ arp.setTargetHardwareAddress(targetMacAddress);
+ arp.setTargetProtocolAddress(targetIP);
+ rawArpPkt = arp.serialize();
+ } catch (Exception ex) {
+ s_logger.error("VPNUtil: Serialized ARP packet with senderMacAddress {} senderIp {} targetIP {} exception {}",
+ senderMacAddress, senderIP, targetIP, ex);
+ }
+
+ return rawArpPkt;
+ }
+
+ private static byte[] createEthernetPacket(byte[] sourceMAC, byte[] targetMAC, byte[] arp) {
+ Ethernet ethernet = new Ethernet();
+ byte[] rawEthPkt = null;
+ try {
+ ethernet.setSourceMACAddress(sourceMAC);
+ ethernet.setDestinationMACAddress(targetMAC);
+ ethernet.setEtherType(EtherTypes.ARP.shortValue());
+ ethernet.setRawPayload(arp);
+ rawEthPkt = ethernet.serialize();
+ } catch (Exception ex) {
+ s_logger.error("VPNUtil: Serialized Ethernet packet with sourceMacAddress {} targetMacAddress {} exception {}",
+ sourceMAC, targetMAC, ex);
+ }
+ return rawEthPkt;
+ }
+}
public static final BigInteger COOKIE_L3_BASE = new BigInteger("8000000", 16);
public static final String FLOWID_PREFIX = "L3.";
public static final long WAIT_TIME_IN_MILLISECONDS = 5000;
+ public static final int ELAN_GID_MIN = 200000;
+ public static final short ELAN_SMAC_TABLE = 50;
+ public static final short FIB_TABLE = 21;
+ public static byte[] EthernetDestination_Broadcast = new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF };
+ public static byte[] MAC_Broadcast = new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 };
+
}
import org.opendaylight.controller.md.sal.binding.api.*;
import org.opendaylight.vpnservice.mdsalutil.*;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
import com.google.common.base.Optional;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
import org.opendaylight.bgpmanager.api.IBgpManager;
import org.opendaylight.fibmanager.api.IFibManager;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
private ItmRpcService itmProvider;
private IdManagerService idManager;
private OdlArputilService arpManager;
+ private NeutronvpnService neuService;
+ private VpnSubnetRouteHandler vpnSubnetRouteHandler;
private InterfaceStateChangeListener interfaceListener;
private VpnInterfaceOpListener vpnInterfaceOpListener;
private ArpNotificationHandler arpNotificationHandler;
vpnInterfaceOpListener = new VpnInterfaceOpListener();
arpNotificationHandler = new ArpNotificationHandler(this, broker);
notificationService.registerNotificationListener(arpNotificationHandler);
+ vpnSubnetRouteHandler = new VpnSubnetRouteHandler(broker, bgpManager, this);
+ notificationService.registerNotificationListener(vpnSubnetRouteHandler);
registerListener(db);
}
public void setIdManager(IdManagerService idManager) {
this.idManager = idManager;
+ vpnSubnetRouteHandler.setIdManager(idManager);
}
public void setArpManager(OdlArputilService arpManager) {
this.arpManager = arpManager;
}
+ public void setNeutronvpnManager(NeutronvpnService neuService) { this.neuService = neuService; }
+
+ public VpnSubnetRouteHandler getVpnSubnetRouteHandler() {
+ return this.vpnSubnetRouteHandler;
+ }
+
@Override
public void close() throws Exception {
if (listenerRegistration != null) {
InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
+ makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
+ vpnId, ArpReplyOrRequest.REPLY, NwConstants.ADD_FLOW);
}
long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
+ makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
+ vpnId, ArpReplyOrRequest.REPLY, NwConstants.DEL_FLOW);
}
(rd != null) ? rd : routerID, destination),
VpnUtil.getVpnToExtraroute(destination, nextHop));
- if(intfName != null && !intfName.isEmpty()) {
+ if (intfName != null && !intfName.isEmpty()) {
BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, intfName);
String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
- if (nextHopIp == null && !nextHopIp.isEmpty()) {
- LOG.error("NextHop for interface {} is null. Adding extra route {} without nextHop", intfName,
- destination);
+ if (nextHopIp == null || nextHopIp.isEmpty()) {
+ LOG.warn("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}", intfName, destination);
}
nextHop = nextHopIp;
}
import org.opendaylight.bgpmanager.api.IBgpManager;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
private VpnInterfaceManager vpnInterfaceManager;
private final FibEntriesListener fibListener;
private final VpnInstanceOpListener vpnInstOpListener;
+ private NotificationService notificationService;
private static final FutureCallback<Void> DEFAULT_CALLBACK =
new FutureCallback<Void>() {
--- /dev/null
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.vpnservice;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.bgpmanager.api.IBgpManager;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.vpnservice.utilities.InterfaceUtils;
+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.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.Subnetmap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.math.BigInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+
+public class VpnSubnetRouteHandler implements NeutronvpnListener {
+ private static final Logger logger = LoggerFactory.getLogger(VpnSubnetRouteHandler.class);
+
+ private final DataBroker broker;
+ private SubnetOpDpnManager subOpDpnManager;
+ private final IBgpManager bgpManager;
+ private IdManagerService idManager;
+ private VpnInterfaceManager vpnInterfaceManager;
+
+ public VpnSubnetRouteHandler(final DataBroker db, IBgpManager bgpManager, VpnInterfaceManager vpnIntfManager) {
+ broker = db;
+ subOpDpnManager = new SubnetOpDpnManager(broker);
+ this.bgpManager = bgpManager;
+ this.vpnInterfaceManager = vpnIntfManager;
+ }
+
+ public void setIdManager(IdManagerService idManager) {
+ this.idManager = idManager;
+ }
+
+ @Override
+ public void onSubnetAddedToVpn(SubnetAddedToVpn notification) {
+ if (!notification.isExternalVpn()) {
+ return;
+ }
+
+ Uuid subnetId = notification.getSubnetId();
+ String vpnName = notification.getVpnName();
+ String subnetIp = notification.getSubnetIp();
+ Long elanTag = notification.getElanTag();
+
+ Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
+ Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
+ Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
+ Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
+
+ logger.info("onSubnetAddedToVpn: Subnet" + subnetId.getValue() + " being added to vpn");
+ //TODO(vivek): Change this to use more granularized lock at subnetId level
+ synchronized (this) {
+ try {
+ //Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
+ LogicalDatastoreType.OPERATIONAL,
+ subOpIdentifier);
+ if (optionalSubs.isPresent()) {
+ logger.error("onSubnetAddedToVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() +
+ " already detected to be present");
+ return;
+ }
+ logger.debug("onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet: " + subnetId.getValue());
+ Map<BigInteger, SubnetToDpn> subDpnMap = new HashMap<BigInteger, SubnetToDpn>();
+ SubnetOpDataEntry subOpEntry = null;
+ BigInteger dpnId = null;
+ BigInteger nhDpnId = null;
+ SubnetToDpn subDpn = null;
+
+ SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
+ subOpBuilder.setSubnetId(subnetId);
+ subOpBuilder.setSubnetCidr(subnetIp);
+ String rd = VpnUtil.getVpnRd(broker, vpnName);
+ if (rd == null) {
+ logger.error("onSubnetAddedToVpn: The VPN Instance name " + notification.getVpnName() + " does not have RD ");
+ return;
+ }
+ subOpBuilder.setVrfId(rd);
+ subOpBuilder.setVpnName(vpnName);
+ subOpBuilder.setSubnetToDpn(new ArrayList<SubnetToDpn>());
+ subOpBuilder.setRouteAdvState(TaskState.Na);
+ subOpBuilder.setElanTag(elanTag);
+
+ // First recover set of ports available in this subnet
+ InstanceIdentifier<Subnetmap> subMapid = InstanceIdentifier.builder(Subnetmaps.class).
+ child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
+ Optional<Subnetmap> sm = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subMapid);
+ if (!sm.isPresent()) {
+ logger.error("onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet : " + subnetId);
+ return;
+ }
+ Subnetmap subMap = sm.get();
+ List<Uuid> portList = subMap.getPortList();
+ if (portList != null) {
+ for (Uuid port: portList) {
+ Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(broker,port.getValue());
+ if (intfState != null) {
+ dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
+ if (dpnId == null) {
+ logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not assigned DPN yet, ignoring ");
+ continue;
+ }
+ subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, dpnId);
+ if (intfState.getOperStatus() != OperStatus.Up) {
+ logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not UP yet, ignoring ");
+ continue;
+ }
+ subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, port.getValue());
+ if (intfState.getOperStatus() == OperStatus.Up) {
+ // port is UP
+ subDpnMap.put(dpnId, subDpn);
+ if (nhDpnId == null) {
+ nhDpnId = dpnId;
+ }
+ }
+ } else {
+ subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, null);
+ }
+ }
+ if (subDpnMap.size() > 0) {
+ subOpBuilder.setSubnetToDpn(new ArrayList<SubnetToDpn>(subDpnMap.values()));
+ }
+ }
+
+ if (nhDpnId != null) {
+ subOpBuilder.setNhDpnId(nhDpnId);
+ try {
+ /*
+ Write the subnet route entry to the FIB.
+ And also advertise the subnet route entry via BGP.
+ */
+ addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ subOpBuilder.setRouteAdvState(TaskState.Done);
+ } catch (Exception ex) {
+ logger.error("onSubnetAddedToVpn: FIB rules and Advertising nhDpnId " + nhDpnId +
+ " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
+ subOpBuilder.setRouteAdvState(TaskState.Pending);
+ }
+ } else {
+ try {
+ /*
+ Write the subnet route entry to the FIB.
+ NOTE: Will not advertise to BGP as NextHopDPN is not available yet.
+ */
+ addSubnetRouteToFib(rd, subnetIp, null, vpnName, elanTag);
+ } catch (Exception ex) {
+ logger.error("onSubnetAddedToVpn: FIB rules writing for subnet {} with exception {} " +
+ subnetId.getValue(), ex);
+ subOpBuilder.setRouteAdvState(TaskState.Pending);
+ }
+ }
+
+ subOpEntry = subOpBuilder.build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+ logger.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet " + subnetId.getValue());
+ } catch (Exception ex) {
+ logger.error("Creation of SubnetOpDataEntry for subnet " +
+ subnetId.getValue() + " failed {}", ex);
+ } finally {
+ }
+ }
+ }
+
+ @Override
+ public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) {
+ Uuid subnetId = notification.getSubnetId();
+
+ if (!notification.isExternalVpn()) {
+ return;
+ }
+ logger.info("onSubnetDeletedFromVpn: Subnet" + subnetId.getValue() + " being removed to vpn");
+ //TODO(vivek): Change this to use more granularized lock at subnetId level
+ synchronized (this) {
+ try {
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ logger.trace(" Removing the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
+ Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
+ LogicalDatastoreType.OPERATIONAL,
+ subOpIdentifier);
+ if (!optionalSubs.isPresent()) {
+ logger.error("onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() +
+ " not available in datastore");
+ return;
+ }
+ SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+ List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
+ for (SubnetToDpn subDpn: subDpnList) {
+ List<VpnInterfaces> vpnIntfList = subDpn.getVpnInterfaces();
+ for (VpnInterfaces vpnIntf: vpnIntfList) {
+ subOpDpnManager.removePortOpDataEntry(vpnIntf.getInterfaceName());
+ }
+ }
+ //Removing Stale Ports in portOpData
+ InstanceIdentifier<Subnetmap> subMapid = InstanceIdentifier.builder(Subnetmaps.class).
+ child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
+ Optional<Subnetmap> sm = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subMapid);
+ if (!sm.isPresent()) {
+ logger.error("Stale ports removal: Unable to retrieve subnetmap entry for subnet : " + subnetId);
+ }
+ Subnetmap subMap = sm.get();
+ List<Uuid> portList = subMap.getPortList();
+ if(portList!=null){
+ InstanceIdentifier<PortOpData> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).build();
+ Optional<PortOpData> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
+ if(!optionalPortOp.isPresent()){
+ logger.error("Stale ports removal: Cannot delete port. Not available in data store");
+ return;
+ } else{
+ PortOpData portOpData = optionalPortOp.get();
+ List<PortOpDataEntry> portOpDataList = portOpData.getPortOpDataEntry();
+ if(portOpDataList!=null){
+ for(PortOpDataEntry portOpDataListEntry : portOpDataList){
+ if(portList.contains(new Uuid(portOpDataListEntry.getPortId()))){
+ logger.trace("Removing stale port: " + portOpDataListEntry + "for dissociated subnetId: " + subnetId);
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier.
+ child(PortOpDataEntry.class, new PortOpDataEntryKey(portOpDataListEntry.getKey())));
+ }
+ }
+ }
+ }
+ }
+
+ String rd = subOpBuilder.getVrfId();
+ String subnetIp = subOpBuilder.getSubnetCidr();
+ BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
+ logger.trace("Removed subnetopdataentry successfully to CONFIG Datastore");
+ try {
+ //Withdraw the routes for all the interfaces on this subnet
+ //Remove subnet route entry from FIB
+ withdrawSubnetRoutefromBgp(rd, subnetIp);
+ deleteSubnetRouteFromFib(rd, subnetIp);
+ } catch (Exception ex) {
+ logger.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet " +
+ subnetId.getValue() + " failed {}" + ex);
+ }
+ } catch (Exception ex) {
+ logger.error("Removal of SubnetOpDataEntry for subnet " +
+ subnetId.getValue() + " failed {}" + ex);
+ } finally {
+ }
+ }
+ }
+
+ @Override
+ public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) {
+ Uuid subnetId = notification.getSubnetId();
+ String vpnName = notification.getVpnName();
+ String subnetIp = notification.getSubnetIp();
+ Long elanTag = notification.getElanTag();
+
+ Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
+ Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
+ Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
+ Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
+
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
+ LogicalDatastoreType.OPERATIONAL,
+ subOpIdentifier);
+ if (optionalSubs.isPresent()) {
+ if (!notification.isExternalVpn()) {
+ SubnetDeletedFromVpnBuilder bldr = new SubnetDeletedFromVpnBuilder().setVpnName(vpnName);
+ bldr.setElanTag(elanTag).setExternalVpn(true).setSubnetIp(subnetIp).setSubnetId(subnetId);
+ onSubnetDeletedFromVpn(bldr.build());
+ }
+ // TODO(vivek): Something got updated, but we donot know what ?
+ } else {
+ if (notification.isExternalVpn()) {
+ SubnetAddedToVpnBuilder bldr = new SubnetAddedToVpnBuilder().setVpnName(vpnName).setElanTag(elanTag);
+ bldr.setSubnetIp(subnetIp).setSubnetId(subnetId).setExternalVpn(true);;
+ onSubnetAddedToVpn(bldr.build());
+ }
+ // TODO(vivek): Something got updated, but we donot know what ?
+ }
+ }
+
+ @Override
+ public void onPortAddedToSubnet(PortAddedToSubnet notification) {
+ Uuid subnetId = notification.getSubnetId();
+ Uuid portId = notification.getPortId();
+
+ logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue());
+ //TODO(vivek): Change this to use more granularized lock at subnetId level
+ synchronized (this) {
+ try {
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+
+ Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+ subOpIdentifier);
+ if (!optionalSubs.isPresent()) {
+ logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() +
+ " that is not in VPN, ignoring");
+ return;
+ }
+ Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(broker,portId.getValue());
+ if (intfState == null) {
+ // Interface State not yet available
+ subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, null);
+ return;
+ }
+ BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
+ if (dpnId == null) {
+ logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not assigned DPN yet, ignoring ");
+ return;
+ }
+ subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, dpnId);
+ if (intfState.getOperStatus() != OperStatus.Up) {
+ logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not UP yet, ignoring ");
+ return;
+ }
+ logger.debug("onPortAddedToSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
+ SubnetToDpn subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, portId.getValue());
+ if (subDpn == null) {
+ return;
+ }
+ SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+ List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
+ subDpnList.add(subDpn);
+ subOpBuilder.setSubnetToDpn(subDpnList);
+ if (subOpBuilder.getNhDpnId() == null) {
+ subOpBuilder.setNhDpnId(dpnId);
+ }
+ BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+ String rd = subOpBuilder.getVrfId();
+ String subnetIp = subOpBuilder.getSubnetCidr();
+ String vpnName = subOpBuilder.getVpnName();
+ Long elanTag = subOpBuilder.getElanTag();
+ if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) ||
+ (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
+ try {
+ // Write the Subnet Route Entry to FIB
+ // Advertise BGP Route here and set route_adv_state to DONE
+ addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ subOpBuilder.setRouteAdvState(TaskState.Done);
+ } catch (Exception ex) {
+ logger.error("onPortAddedToSubnet: Advertising NextHopDPN "+ nhDpnId +
+ " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
+ }
+ }
+ SubnetOpDataEntry subOpEntry = subOpBuilder.build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+ logger.info("onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port " + portId.getValue());
+
+ } catch (Exception ex) {
+ logger.error("Creation of SubnetOpDataEntry for subnet " +
+ subnetId.getValue() + " failed {}", ex);
+ } finally {
+ }
+ }
+ }
+
+ @Override
+ public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
+ Uuid subnetId = notification.getSubnetId();
+ Uuid portId = notification.getPortId();
+
+ logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue());
+ //TODO(vivek): Change this to use more granularized lock at subnetId level
+ synchronized (this) {
+ try {
+ PortOpDataEntry portOpEntry = subOpDpnManager.removePortOpDataEntry(portId.getValue());
+ if (portOpEntry == null) {
+ return;
+ }
+ BigInteger dpnId = portOpEntry.getDpnId();
+ if (dpnId == null) {
+ logger.debug("onPortRemovedFromSubnet: Port {} does not have a DPNId associated, ignoring", portId.getValue());
+ return;
+ }
+ logger.debug("onPortRemovedFromSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
+ boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, portId.getValue());
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+ subOpIdentifier);
+ if (!optionalSubs.isPresent()) {
+ logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() +
+ " that is not in VPN, ignoring");
+ return;
+ }
+ SubnetOpDataEntry subOpEntry = null;
+ List<SubnetToDpn> subDpnList = null;
+ SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+ String rd = subOpBuilder.getVrfId();
+ String subnetIp = subOpBuilder.getSubnetCidr();
+ String vpnName = subOpBuilder.getVpnName();
+ Long elanTag = subOpBuilder.getElanTag();
+ BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+ if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
+ // select another NhDpnId
+ if (last) {
+ logger.debug("onPortRemovedFromSubnet: Last port " + portId + " on the subnet: " + subnetId.getValue());
+ // last port on this DPN, so we need to swap the NHDpnId
+ subDpnList = subOpBuilder.getSubnetToDpn();
+ if (subDpnList.isEmpty()) {
+ subOpBuilder.setNhDpnId(null);
+ try {
+ // withdraw route from BGP
+ deleteSubnetRouteFromFib(rd, subnetIp);
+ withdrawSubnetRoutefromBgp(rd, subnetIp);
+ subOpBuilder.setRouteAdvState(TaskState.Na);
+ } catch (Exception ex) {
+ logger.error("onPortRemovedFromSubnet: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
+ subnetId.getValue() + " from BGP failed ", ex);
+ subOpBuilder.setRouteAdvState(TaskState.Pending);
+ }
+ } else {
+ nhDpnId = subDpnList.get(0).getDpnId();
+ subOpBuilder.setNhDpnId(nhDpnId);
+ logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue());
+ try {
+ // Best effort Withdrawal of route from BGP for this subnet
+ // Advertise the new NexthopIP to BGP for this subnet
+ withdrawSubnetRoutefromBgp(rd, subnetIp);
+ addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ subOpBuilder.setRouteAdvState(TaskState.Done);
+ } catch (Exception ex) {
+ logger.error("onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN " + dpnId +
+ " information for subnet " + subnetId.getValue() +
+ " to BGP failed {}" + ex);
+ subOpBuilder.setRouteAdvState(TaskState.Pending);
+ }
+ }
+ }
+ }
+ subOpEntry = subOpBuilder.build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+ logger.info("onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore removing port " + portId.getValue());
+ } catch (Exception ex) {
+ logger.error("Creation of SubnetOpDataEntry for subnet " +
+ subnetId.getValue() + " failed {}" + ex);
+ } finally {
+ }
+ }
+ }
+
+ public void onInterfaceUp(Interface intfState) {
+
+ logger.info("onInterfaceUp: Port " + intfState.getName());
+ //TODO(vivek): Change this to use more granularized lock at subnetId level
+ synchronized (this) {
+ SubnetToDpn subDpn = null;
+ String intfName = intfState.getName();
+ PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
+ if (portOpEntry == null) {
+ logger.info("onInterfaceUp: Port " + intfState.getName() + "is part of a subnet not in VPN, ignoring");
+ return;
+ }
+ BigInteger dpnId = portOpEntry.getDpnId();
+ if (dpnId == null) {
+ dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
+ if (dpnId == null) {
+ logger.error("onInterfaceUp: Unable to determine the DPNID for port " + intfName);
+ return;
+ }
+ }
+ Uuid subnetId = portOpEntry.getSubnetId();
+ try {
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+ subOpIdentifier);
+ if (!optionalSubs.isPresent()) {
+ logger.error("onInterfaceUp: SubnetOpDataEntry for subnet " + subnetId.getValue() +
+ " is not available");
+ return;
+ }
+
+ SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+ logger.debug("onInterfaceUp: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
+ subOpDpnManager.addPortOpDataEntry(intfName, subnetId, dpnId);
+ subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, intfName);
+ if (subDpn == null) {
+ return;
+ }
+ List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
+ subDpnList.add(subDpn);
+ subOpBuilder.setSubnetToDpn(subDpnList);
+ if (subOpBuilder.getNhDpnId() == null) {
+ subOpBuilder.setNhDpnId(dpnId);
+ }
+ BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+ String rd = subOpBuilder.getVrfId();
+ String subnetIp = subOpBuilder.getSubnetCidr();
+ String vpnName = subOpBuilder.getVpnName();
+ Long elanTag = subOpBuilder.getElanTag();
+ if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
+ try {
+ // Write the Subnet Route Entry to FIB
+ // Advertise BGP Route here and set route_adv_state to DONE
+ addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ subOpBuilder.setRouteAdvState(TaskState.Done);
+ } catch (Exception ex) {
+ logger.error("onInterfaceUp: Advertising NextHopDPN " + nhDpnId + " information for subnet " +
+ subnetId.getValue() + " to BGP failed {}" + ex);
+ }
+ }
+ SubnetOpDataEntry subOpEntry = subOpBuilder.build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+ logger.info("onInterfaceUp: Updated subnetopdataentry to OP Datastore port up " + intfName);
+ } catch (Exception ex) {
+ logger.error("Creation of SubnetOpDataEntry for subnet " +
+ subnetId.getValue() + " failed {}" + ex);
+ } finally {
+ }
+ }
+ }
+
+ public void onInterfaceDown(Interface intfState) {
+ logger.info("onInterfaceDown: Port " + intfState.getName());
+ //TODO(vivek): Change this to use more granularized lock at subnetId level
+ synchronized (this) {
+ String intfName = intfState.getName();
+ PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
+ if (portOpEntry == null) {
+ logger.info("onInterfaceDown: Port " + intfState.getName() + "is part of a subnet not in VPN, ignoring");
+ return;
+ }
+ BigInteger dpnId = portOpEntry.getDpnId();
+ if (dpnId == null) {
+ dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
+ if (dpnId == null) {
+ logger.error("onInterfaceDown: Unable to determine the DPNID for port " + intfName);
+ return;
+ }
+ }
+ Uuid subnetId = portOpEntry.getSubnetId();
+ try {
+ logger.debug("onInterfaceDown: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
+ boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, intfName);
+ InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
+ child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
+ Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
+ LogicalDatastoreType.OPERATIONAL,
+ subOpIdentifier);
+ if (!optionalSubs.isPresent()) {
+ logger.error("onInterfaceDown: SubnetOpDataEntry for subnet " + subnetId.getValue() +
+ " is not available");
+ return;
+ }
+ SubnetOpDataEntry subOpEntry = null;
+ List<SubnetToDpn> subDpnList = null;
+ SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+ String rd = subOpBuilder.getVrfId();
+ String subnetIp = subOpBuilder.getSubnetCidr();
+ String vpnName = subOpBuilder.getVpnName();
+ Long elanTag = subOpBuilder.getElanTag();
+ BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+ if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
+ // select another NhDpnId
+ if (last) {
+ logger.debug("onInterfaceDown: Last active port " + intfState.getName() + " on the subnet: " + subnetId.getValue());
+ // last port on this DPN, so we need to swap the NHDpnId
+ subDpnList = subOpBuilder.getSubnetToDpn();
+ if (subDpnList.isEmpty()) {
+ subOpBuilder.setNhDpnId(null);
+ try {
+ // Withdraw route from BGP for this subnet
+ deleteSubnetRouteFromFib(rd, subnetIp);
+ withdrawSubnetRoutefromBgp(rd, subnetIp);
+ subOpBuilder.setRouteAdvState(TaskState.Na);
+ } catch (Exception ex) {
+ logger.error("onInterfaceDown: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
+ subnetId.getValue() + " from BGP failed {}" + ex);
+ subOpBuilder.setRouteAdvState(TaskState.Pending);
+ }
+ } else {
+ nhDpnId = subDpnList.get(0).getDpnId();
+ subOpBuilder.setNhDpnId(nhDpnId);
+ logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue());
+ try {
+ // Best effort Withdrawal of route from BGP for this subnet
+ withdrawSubnetRoutefromBgp(rd, subnetIp);
+ addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag);
+ subOpBuilder.setRouteAdvState(TaskState.Done);
+ } catch (Exception ex) {
+ logger.error("onInterfaceDown: Swapping Withdrawing NextHopDPN " + dpnId + " information for subnet " +
+ subnetId.getValue() + " to BGP failed {}" + ex);
+ subOpBuilder.setRouteAdvState(TaskState.Pending);
+ }
+ }
+ }
+ }
+ subOpEntry = subOpBuilder.build();
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+ logger.info("onInterfaceDown: Updated subnetopdataentry to OP Datastore port down " + intfName);
+ } catch (Exception ex) {
+ logger.error("Creation of SubnetOpDataEntry for subnet " +
+ subnetId.getValue() + " failed {}" + ex);
+ } finally {
+ }
+ }
+ }
+
+ private static void setRdToElanOpEntry(DataBroker broker,
+ String rd, String subnetIp, String nextHopIp, String vpnName,
+ Long elanTag) {
+ RdToElanOpEntryBuilder rdElanBuilder = null;
+ RdToElanOpEntry rdElan = null;
+
+ try {
+ InstanceIdentifier<RdToElanOpEntry> rdIdentifier = InstanceIdentifier.builder(RdToElanOp.class).
+ child(RdToElanOpEntry.class, new RdToElanOpEntryKey(rd, subnetIp)).build();
+ Optional<RdToElanOpEntry> optionalRd = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, rdIdentifier);
+ if (!optionalRd.isPresent()) {
+ // Create PortOpDataEntry only if not present
+ rdElanBuilder = new RdToElanOpEntryBuilder().setKey(new RdToElanOpEntryKey(rd,subnetIp));
+ rdElanBuilder.setRd(rd).setSubnetIp(subnetIp).setNextHopIp(nextHopIp);
+ rdElanBuilder.setElanTag(elanTag);
+ rdElanBuilder.setVpnName(vpnName);
+ rdElan = rdElanBuilder.build();
+ } else {
+ rdElanBuilder = new RdToElanOpEntryBuilder(optionalRd.get());
+ rdElanBuilder.setRd(rd).setSubnetIp(subnetIp).setNextHopIp(nextHopIp);
+ rdElanBuilder.setElanTag(elanTag);
+ rdElanBuilder.setVpnName(vpnName);
+ rdElan = rdElanBuilder.build();
+ }
+ MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, rdIdentifier, rdElan);
+ logger.info("Creating RdToElan entry Rd {} SubnetIp {} NextHopIp {} Elan {} " ,rd, subnetIp, nextHopIp, elanTag);
+ } catch (Exception ex) {
+ logger.error("Exception when creating RdToElan entry {}" + ex);
+ } finally {
+ }
+ }
+
+ private void addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
+ Long elanTag) {
+ Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
+ Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
+ Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
+ Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
+ String nexthopIp = null;
+ if (nhDpnId != null) {
+ nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, nhDpnId);
+ }
+ int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+ VpnUtil.getNextHopLabelKey(rd, subnetIp));
+ setRdToElanOpEntry(broker, rd, subnetIp, nexthopIp, vpnName, elanTag);
+ vpnInterfaceManager.addFibEntryToDS(rd, subnetIp, nexthopIp, label);
+ }
+
+ private void deleteSubnetRouteFromFib(String rd, String subnetIp) {
+ Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
+ Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
+ vpnInterfaceManager.removeFibEntryFromDS(rd, subnetIp);
+ }
+
+ private void advertiseSubnetRouteToBgp(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
+ Long elanTag) throws Exception {
+ Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
+ Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
+ Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
+ Preconditions.checkNotNull(nhDpnId, "nhDpnId cannot be null or empty!");
+ Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
+ String nexthopIp = null;
+ nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, nhDpnId);
+ if (nexthopIp == null) {
+ logger.error("createSubnetRouteInVpn: Unable to obtain endpointIp address for DPNId " + nhDpnId);
+ throw new Exception("Unable to obtain endpointIp address for DPNId " + nhDpnId);
+ }
+ int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
+ VpnUtil.getNextHopLabelKey(rd, subnetIp));
+ setRdToElanOpEntry(broker, rd, subnetIp, nexthopIp, vpnName, elanTag);
+ try {
+ bgpManager.advertisePrefix(rd, subnetIp, nexthopIp, label);
+ } catch (Exception e) {
+ logger.error("Subnet route not advertised for rd " + rd + " failed ", e);
+ throw e;
+ }
+ }
+
+ private void withdrawSubnetRoutefromBgp(String rd, String subnetIp) throws Exception {
+ Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
+ Preconditions.checkNotNull(subnetIp, "SubnetIp cannot be null or empty!");
+ try {
+ bgpManager.withdrawPrefix(rd, subnetIp);
+ } catch (Exception e) {
+ logger.error("Subnet route not advertised for rd " + rd + " failed ", e);
+ throw e;
+ }
+ }
+}
+
package org.opendaylight.vpnservice;
import java.math.BigInteger;
+import java.net.InetAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.List;
import com.google.common.base.Optional;
+import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.vpnservice.mdsalutil.NwConstants;
+import org.opendaylight.vpnservice.mdsalutil.packet.ARP;
+import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdPools;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPool;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronPortData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data.PortFixedipToPortName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.neutron.port.data.PortFixedipToPortNameKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanTagNameMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.binding.DataObject;
result = tx.read(datastoreType, path).get();
} catch (Exception e) {
throw new RuntimeException(e);
+ } finally {
+ tx.close();
}
return result;
}
}
-}
+ public static long getRemoteBCGroup(long elanTag) {
+ return VpnConstants.ELAN_GID_MIN + ((elanTag % VpnConstants.ELAN_GID_MIN) *2);
+ }
+
+ // interface-index-tag operational container
+ public static IfIndexInterface getInterfaceInfoByInterfaceTag(DataBroker broker, long interfaceTag) {
+ InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
+ Optional<IfIndexInterface> existingInterfaceInfo = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
+ if(existingInterfaceInfo.isPresent()) {
+ return existingInterfaceInfo.get();
+ }
+ return null;
+ }
+
+ private static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) {
+ return InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class,
+ new IfIndexInterfaceKey((int) interfaceTag)).build();
+ }
+
+ public static String getNeutronPortNamefromPortFixedIp(DataBroker broker, String fixedIp) {
+ InstanceIdentifier id = buildFixedIpToPortNameIdentifier(fixedIp);
+ Optional<PortFixedipToPortName> portFixedipToPortNameData = read(broker, LogicalDatastoreType.CONFIGURATION,
+ id);
+ if (portFixedipToPortNameData.isPresent()) {
+ return portFixedipToPortNameData.get().getPortName();
+ }
+ return null;
+ }
+
+ private static InstanceIdentifier<PortFixedipToPortName> buildFixedIpToPortNameIdentifier(String fixedIp) {
+ InstanceIdentifier<PortFixedipToPortName> id = InstanceIdentifier.builder(NeutronPortData.class).child
+ (PortFixedipToPortName.class, new PortFixedipToPortNameKey(fixedIp)).build();
+ return id;
+ }
+
+ public static ElanTagName getElanInfoByElanTag(DataBroker broker,long elanTag) {
+ InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
+ Optional<ElanTagName> existingElanInfo = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanId);
+ if(existingElanInfo.isPresent()) {
+ return existingElanInfo.get();
+ }
+ return null;
+ }
+
+ private static InstanceIdentifier<ElanTagName> getElanInfoEntriesOperationalDataPath(long elanTag) {
+ return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class,
+ new ElanTagNameKey(elanTag)).build();
+ }
+
+
+ public static boolean isIpInSubnet(int ipAddress, String subnetCidr) {
+ String[] subSplit = subnetCidr.split("/");
+ LOG.trace("SubnetRoutePacketInHandler: Viewing Subnet Split " + subSplit);
+ if (subSplit.length < 2) {
+ return false;
+ }
+
+ String subnetStr = subSplit[0];
+ int subnet = 0;
+ try {
+ InetAddress subnetAddress = InetAddress.getByName(subnetStr);
+ subnet = Ints.fromByteArray(subnetAddress.getAddress());
+ } catch (Exception ex) {
+ LOG.error("Passed in Subnet IP string not convertible to InetAdddress " + subnetStr);
+ return false;
+ }
+ int prefixLength = Integer.valueOf(subSplit[1]);
+ int mask = -1 << (32 - prefixLength);
+ LOG.trace("SubnetRoutePacketInHandler: prefixLength " + prefixLength + " mask " + mask);
+ LOG.trace("SubnetRoutePacketInHandler: subnet & mask " + (subnet & mask));
+ LOG.trace("SubnetRoutePacketInHandler: subnet & mask " + (ipAddress & mask));
+ if ((subnet & mask) == (ipAddress & mask)) {
+ return true;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.fibmanager.api.IFibManager;
import org.opendaylight.vpnmanager.api.IVpnManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private ItmRpcService itmProvider;
private IdManagerService idManager;
private OdlArputilService arpManager;
+ private NeutronvpnService neuService;
+ private PacketProcessingService m_packetProcessingService;
+ private SubnetRoutePacketInHandler subnetRoutePacketInHandler;
private NotificationService notificationService;
@Override
vpnInterfaceManager.setITMProvider(itmProvider);
vpnInterfaceManager.setIdManager(idManager);
vpnInterfaceManager.setArpManager(arpManager);
+ vpnInterfaceManager.setNeutronvpnManager(neuService);
+ //Handles subnet route entries
+ subnetRoutePacketInHandler = new SubnetRoutePacketInHandler(dataBroker, idManager);
+ m_packetProcessingService = session.getRpcService(PacketProcessingService.class);
+ subnetRoutePacketInHandler.setPacketProcessingService(m_packetProcessingService);
+ notificationService.registerNotificationListener(subnetRoutePacketInHandler);
vpnManager.setVpnInterfaceManager(vpnInterfaceManager);
createIdPool();
} catch (Exception e) {
this.mdsalManager = mdsalManager;
}
- public void setFibManager(IFibManager fibManager) {
- this.fibManager = fibManager;
- }
-
public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
this.interfaceManager = interfaceManager;
}