/* * Copyright (c) 2018 Red Hat, Inc. 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.netvirt.natservice.internal; import static org.opendaylight.netvirt.natservice.internal.AbstractSnatService.LOAD_END; import static org.opendaylight.netvirt.natservice.internal.AbstractSnatService.LOAD_START; import static org.opendaylight.netvirt.natservice.internal.NatUtil.getGroupIdKey; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.genius.infra.Datastore.Configuration; import org.opendaylight.genius.infra.TypedReadWriteTransaction; import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager; import org.opendaylight.genius.mdsalutil.ActionInfo; import org.opendaylight.genius.mdsalutil.BucketInfo; import org.opendaylight.genius.mdsalutil.GroupEntity; import org.opendaylight.genius.mdsalutil.InstructionInfo; import org.opendaylight.genius.mdsalutil.MDSALUtil; import org.opendaylight.genius.mdsalutil.MatchInfo; import org.opendaylight.genius.mdsalutil.MatchInfoBase; import org.opendaylight.genius.mdsalutil.MetaDataUtil; import org.opendaylight.genius.mdsalutil.NWUtil; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.genius.mdsalutil.actions.ActionGroup; import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort; import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadMetadata; import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit; import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId; import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions; import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType; import org.opendaylight.genius.mdsalutil.matches.MatchMetadata; import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId; import org.opendaylight.netvirt.natservice.api.SnatServiceListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Ipv6ForwardingService implements SnatServiceListener { private static final Logger LOG = LoggerFactory.getLogger(Ipv6ForwardingService.class); protected final DataBroker dataBroker; protected final IMdsalApiManager mdsalManager; protected final IdManagerService idManager; protected final NAPTSwitchSelector naptSwitchSelector; protected final ItmRpcService itmManager; protected final OdlInterfaceRpcService odlInterfaceRpcService; protected final IInterfaceManager interfaceManager; protected final Ipv6SubnetFlowProgrammer ipv6SubnetFlowProgrammer; public Ipv6ForwardingService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager, final ItmRpcService itmManager, final OdlInterfaceRpcService odlInterfaceRpcService, final IdManagerService idManager, final NAPTSwitchSelector naptSwitchSelector, final IInterfaceManager interfaceManager, final Ipv6SubnetFlowProgrammer ipv6SubnetFlowProgrammer) { this.dataBroker = dataBroker; this.mdsalManager = mdsalManager; this.itmManager = itmManager; this.odlInterfaceRpcService = odlInterfaceRpcService; this.idManager = idManager; this.naptSwitchSelector = naptSwitchSelector; this.interfaceManager = interfaceManager; this.ipv6SubnetFlowProgrammer = ipv6SubnetFlowProgrammer; } public void init() { LOG.info("Ipv6ForwardingService: {} init", getClass().getSimpleName()); } @Override public boolean addCentralizedRouterAllSwitch(TypedReadWriteTransaction confTx, Routers routers, BigInteger primarySwitchId) { String routerName = routers.getRouterName(); LOG.info("handleSnatAllSwitch : invoked for router {} with NAPTSwitch {} for {} flows", routerName, primarySwitchId, "installing"); List switches = naptSwitchSelector.getDpnsForVpn(routerName); /* * Primary switch handled separately since the pseudo port created may * not be present in the switch list on delete. */ addCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId); for (BigInteger dpnId : switches) { if (!Objects.equals(primarySwitchId, dpnId)) { addCentralizedRouter(confTx, routers, primarySwitchId, dpnId); } } return true; } @Override public boolean addCentralizedRouter(TypedReadWriteTransaction confTx, Routers routers, BigInteger primarySwitchId, BigInteger dpnId) { Long routerId = NatUtil.getVpnId(dataBroker, routers.getRouterName()); BigInteger routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId); if (!dpnId.equals(primarySwitchId)) { LOG.info("handleSnat (non-NAPTSwitch) : {} flows on switch {} for router {}", "Installing", dpnId, routers.getRouterName()); // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction) addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata); // Currently we are only programming flows when ext-net has an IPv6Subnet if (routerHasIpv6ExtSubnet(routers)) { // Program flows on non-NAPTSwitch to send N/S packets to the NAPTSwitch addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routers.getRouterName(), primarySwitchId); } } else { LOG.info("handleSnat (NAPTSwitch) : {} flows on switch {} for router {}", "Installing", dpnId, routers.getRouterName()); // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction) addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata); // Program flows from PSNAT_TABLE(26) to OUTBOUND_NAPT_TABLE(46) (egress direction) addIpv6SnatMissEntryForNaptSwitch(confTx, dpnId, routerId, routerMetadata); // Program flows in INTERNAL_TUNNEL_TABLE(36) for packets coming from non-NAPTSwitch (egress direction) addIpv6TerminatingServiceTblEntry(confTx, dpnId, routerId, routerMetadata); // Program flows from NAPT_PFIB_TABLE(47) to FIB_TABLE(21) (ingress direction) addIpv6NaptPfibInboundFlow(confTx, dpnId, routerId, routerMetadata); // Now installing flows that use SubnetInfo ipv6SubnetFlowProgrammer. addSubnetSpecificFlows(confTx, dpnId, routerId, routers, routerMetadata); } return true; } @Override public boolean removeCentralizedRouterAllSwitch(TypedReadWriteTransaction confTx, Routers routers, BigInteger primarySwitchId) throws ExecutionException, InterruptedException { String routerName = routers.getRouterName(); LOG.info("handleSnatAllSwitch : invoked for router {} with NAPTSwitch {} for {} flows", routerName, primarySwitchId, "removing"); List switches = naptSwitchSelector.getDpnsForVpn(routerName); /* * Primary switch handled separately since the pseudo port created may * not be present in the switch list on delete. */ removeCentralizedRouter(confTx, routers, primarySwitchId, primarySwitchId); for (BigInteger dpnId : switches) { if (!Objects.equals(primarySwitchId, dpnId)) { removeCentralizedRouter(confTx, routers, primarySwitchId, dpnId); } } return true; } @Override public boolean removeCentralizedRouter(TypedReadWriteTransaction confTx, Routers routers, BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException { Long routerId = NatUtil.getVpnId(dataBroker, routers.getRouterName()); BigInteger routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId); if (!dpnId.equals(primarySwitchId)) { LOG.info("handleSnat (non-NAPTSwitch) : {} flows on switch {} for router {}", "Removing", dpnId, routers.getRouterName()); // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction) addIpv6DefaultFibRoute(confTx, dpnId, routerId, routerMetadata); // Currently we are only programming flows when ext-net has an IPv6Subnet if (routerHasIpv6ExtSubnet(routers)) { // Program flows on non-NAPTSwitch to send N/S packets to the NAPTSwitch addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routers.getRouterName(), primarySwitchId); } } else { LOG.info("handleSnat (NAPTSwitch) : {} flows on switch {} for router {}", "Removing", dpnId, routers.getRouterName()); // Program default flow from FIB_TABLE(21) to PSNAT_TABLE(26) (egress direction) removeIpv6DefaultFibRoute(confTx, dpnId, routerId); // Program flows from PSNAT_TABLE(26) to OUTBOUND_NAPT_TABLE(46) (egress direction) removeIpv6SnatMissEntryForNaptSwitch(confTx, dpnId, routerId); // Program flows in INTERNAL_TUNNEL_TABLE(36) for packets coming from non-NAPTSwitch (egress direction) removeIpv6TerminatingServiceTblEntry(confTx, dpnId, routerId); // Program flows from NAPT_PFIB_TABLE(47) to FIB_TABLE(21) (ingress direction) removeIpv6NaptPfibInboundFlow(confTx, dpnId, routerId); // Now installing flows that use SubnetInfo ipv6SubnetFlowProgrammer.removeSubnetSpecificFlows(confTx, dpnId, routerId, routers); } return true; } @Override public boolean handleRouterUpdate(TypedReadWriteTransaction confTx, Routers origRouter, Routers updatedRouter) throws ExecutionException, InterruptedException { LOG.info("handleRouterUpdate : originalRouter {}, updatedRouter {}", origRouter, updatedRouter); String routerName = origRouter.getRouterName(); BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName); Long routerId = NatUtil.getVpnId(dataBroker, routerName); BigInteger routerMetadata = MetaDataUtil.getVpnIdMetadata(routerId); // If the external network is updated with an IPv6Subnet, program the necessary flows on non-NAPTSwitch if (!routerHasIpv6ExtSubnet(origRouter) && routerHasIpv6ExtSubnet(updatedRouter)) { List switches = naptSwitchSelector.getDpnsForVpn(routerName); for (BigInteger dpnId : switches) { if (!Objects.equals(primarySwitchId, dpnId)) { LOG.info("handleRouterUpdate (non-NAPTSwitch) : Installing flows on switch {} for router {}", dpnId, routerName); addIpv6PsNatMissEntryNonNaptSwitch(confTx, dpnId, routerId, routerName, primarySwitchId); } } } ipv6SubnetFlowProgrammer.removeSubnetSpecificFlows(confTx, primarySwitchId, routerId, origRouter); ipv6SubnetFlowProgrammer.addSubnetSpecificFlows(confTx, primarySwitchId, routerId, updatedRouter, routerMetadata); return true; } @Override public boolean addSnatAllSwitch(TypedReadWriteTransaction confTx, Routers routers, BigInteger primarySwitchId) { return true; } @Override public boolean addSnat(TypedReadWriteTransaction confTx, Routers routers, BigInteger primarySwitchId, BigInteger dpnId) { return true; } @Override public boolean removeSnatAllSwitch(TypedReadWriteTransaction confTx, Routers routers, BigInteger primarySwitchId) throws ExecutionException, InterruptedException { return true; } @Override public boolean removeSnat(TypedReadWriteTransaction confTx, Routers routers, BigInteger primarySwitchId, BigInteger dpnId) throws ExecutionException, InterruptedException { return true; } protected void addIpv6DefaultFibRoute(TypedReadWriteTransaction confTx, BigInteger dpnId, Long routerId, BigInteger routerMetadata) { LOG.debug("installIpv6DefaultFibRoute : Installing default FIB route to PSNAT_TABLE on {}", dpnId); List matches = new ArrayList<>(); matches.add(MatchEthernetType.IPV6); matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID)); List instructions = new ArrayList<>(); instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE)); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId); flowRef += ".Outbound"; NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef, NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions); } protected void removeIpv6DefaultFibRoute(TypedReadWriteTransaction confTx, BigInteger dpnId, Long routerId) throws ExecutionException, InterruptedException { LOG.debug("installIpv6DefaultFibRoute : Installing default FIB route to PSNAT_TABLE on {}", dpnId); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.L3_FIB_TABLE, routerId); flowRef += ".Outbound"; NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.L3_FIB_TABLE, flowRef); } protected void addIpv6PsNatMissEntryNonNaptSwitch(TypedReadWriteTransaction confTx, BigInteger dpnId, Long routerId, String routerName, BigInteger primarySwitchId) { LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, installing SNAT miss entry in" + " switch {} for router {}", dpnId, routerName); List listActionInfoPrimary = new ArrayList<>(); List listBucketInfo = new ArrayList<>(); String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager); if (ifNamePrimary != null) { LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, Primary Tunnel interface is {}", ifNamePrimary); listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager, interfaceManager, ifNamePrimary, routerId, true); } else { LOG.warn("installIpv6PsNatMissEntryNonNaptSwitch: could not get tunnelInterface for {} on Switch {}", primarySwitchId, dpnId); } BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary); listBucketInfo.add(0, bucketPrimary); LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : installSnatMissEntry called for dpnId {} with" + " primaryBucket {} ", dpnId, listBucketInfo.get(0)); long groupId = createGroupIdForIpv6Router(getGroupIdKey(routerName + "IPv6")); GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo); LOG.debug("installing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId); mdsalManager.addGroup(confTx, groupEntity); List matches = new ArrayList<>(); matches.add(MatchEthernetType.IPV6); matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID)); List actionsInfo = new ArrayList<>(); actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(routerId))); actionsInfo.add(new ActionGroup(groupId)); List instructions = new ArrayList<>(); instructions.add(new InstructionApplyActions(actionsInfo)); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId); NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions); } protected void removeIpv6PsNatMissEntryNonNaptSwitch(TypedReadWriteTransaction confTx, BigInteger dpnId, Long routerId, String routerName, BigInteger primarySwitchId) throws ExecutionException, InterruptedException { LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, installing SNAT miss entry in" + " switch {} for router {}", dpnId, routerName); List listActionInfoPrimary = new ArrayList<>(); List listBucketInfo = new ArrayList<>(); String ifNamePrimary = NatUtil.getTunnelInterfaceName(dpnId, primarySwitchId, itmManager); if (ifNamePrimary != null) { LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : On Non-Napt Switch, Primary Tunnel interface is {}", ifNamePrimary); listActionInfoPrimary = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmManager, interfaceManager, ifNamePrimary, routerId, true); } else { LOG.warn("installIpv6PsNatMissEntryNonNaptSwitch: could not get tunnelInterface for {} on Switch {}", primarySwitchId, dpnId); } BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary); listBucketInfo.add(0, bucketPrimary); LOG.debug("installIpv6PsNatMissEntryNonNaptSwitch : installSnatMissEntry called for dpnId {} with" + " primaryBucket {} ", dpnId, listBucketInfo.get(0)); long groupId = createGroupIdForIpv6Router(getGroupIdKey(routerName + "IPv6")); GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo); LOG.debug("removing the PSNAT to NAPTSwitch GroupEntity:{} with GroupId: {}", groupEntity, groupId); mdsalManager.removeGroup(confTx, groupEntity); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId); NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef); } protected void addIpv6SnatMissEntryForNaptSwitch(TypedReadWriteTransaction confTx, BigInteger dpnId, Long routerId, BigInteger routerMetadata) { LOG.debug("installIpv6SnatMissEntryForNaptSwitch {} called for routerId {}", dpnId, routerId); List matches = new ArrayList<>(); matches.add(MatchEthernetType.IPV6); matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID)); List instructions = new ArrayList<>(); instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE)); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId); flowRef += ".Outbound"; NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions); } protected void removeIpv6SnatMissEntryForNaptSwitch(TypedReadWriteTransaction confTx, BigInteger dpnId, Long routerId) throws ExecutionException, InterruptedException { LOG.debug("installIpv6SnatMissEntryForNaptSwitch {} called for routerId {}", dpnId, routerId); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.PSNAT_TABLE, routerId); flowRef += ".Outbound"; NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.PSNAT_TABLE, flowRef); } protected void addIpv6TerminatingServiceTblEntry(TypedReadWriteTransaction confTx, BigInteger dpnId, Long routerId, BigInteger routerMetadata) { LOG.debug("installIpv6TerminatingServiceTblEntry : creating entry for Terminating Service Table " + "for switch {}, routerId {}", dpnId, routerId); List matches = new ArrayList<>(); matches.add(MatchEthernetType.IPV6); matches.add(new MatchTunnelId(BigInteger.valueOf(routerId))); List actionsInfos = new ArrayList<>(); ActionNxLoadMetadata actionLoadMeta = new ActionNxLoadMetadata(routerMetadata, LOAD_START, LOAD_END); actionsInfos.add(actionLoadMeta); actionsInfos.add(new ActionNxResubmit(NwConstants.OUTBOUND_NAPT_TABLE)); List instructions = new ArrayList<>(); instructions.add(new InstructionApplyActions(actionsInfos)); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId); flowRef += ".Outbound"; NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef, NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructions); } protected void removeIpv6TerminatingServiceTblEntry(TypedReadWriteTransaction confTx, BigInteger dpnId, Long routerId) throws ExecutionException, InterruptedException { LOG.debug("installIpv6TerminatingServiceTblEntry : creating entry for Terminating Service Table " + "for switch {}, routerId {}", dpnId, routerId); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId); flowRef += ".Outbound"; NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef); } protected void addIpv6NaptPfibInboundFlow(TypedReadWriteTransaction confTx, BigInteger dpnId, long routerId, BigInteger routerMetadata) { LOG.debug("installIpv6NaptPfibInboundFlow : called for dpnId {} and routerId {} ", dpnId, routerId); List matches = new ArrayList<>(); matches.add(MatchEthernetType.IPV6); matches.add(new MatchMetadata(routerMetadata, MetaDataUtil.METADATA_MASK_VRFID)); ArrayList listActionInfo = new ArrayList<>(); ArrayList instructionInfo = new ArrayList<>(); listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO)); listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE)); instructionInfo.add(new InstructionApplyActions(listActionInfo)); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId); flowRef += ".Inbound"; NatUtil.addFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef, NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo); } protected void removeIpv6NaptPfibInboundFlow(TypedReadWriteTransaction confTx, BigInteger dpnId, long routerId) throws ExecutionException, InterruptedException { LOG.debug("installIpv6NaptPfibInboundFlow : called for dpnId {} and routerId {} ", dpnId, routerId); String flowRef = NatUtil.getIpv6FlowRef(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId); flowRef += ".Inbound"; NatUtil.removeFlow(confTx, mdsalManager, dpnId, NwConstants.NAPT_PFIB_TABLE, flowRef); } protected long createGroupIdForIpv6Router(String groupIdKey) { AllocateIdInput getIdInput = new AllocateIdInputBuilder() .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey) .build(); try { Future> result = idManager.allocateId(getIdInput); RpcResult rpcResult = result.get(); return rpcResult.getResult().getIdValue(); } catch (NullPointerException | InterruptedException | ExecutionException e) { LOG.error("createGroupIdForIPv6Router: Exception while creating group with key : {}", groupIdKey, e); } return 0; } protected boolean routerHasIpv6ExtSubnet(Routers routers) { for (ExternalIps externalIp : routers.getExternalIps()) { if (!NWUtil.isIpv4Address(externalIp.getIpAddress())) { LOG.debug("router {}, has an external IPv6 subnet {}", routers.getRouterName(), externalIp.getIpAddress()); return true; } } LOG.debug("router {}, does not have an external IPv6 subnet", routers.getRouterName()); return false; } }