package org.opendaylight.netvirt.natservice.internal;
-import org.opendaylight.genius.mdsalutil.*;
-import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
-import org.opendaylight.genius.interfacemanager.globals.VlanInterfaceInfo;
import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.FlowEntity;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.InstructionType;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MatchFieldType;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionOutput;
+import org.opendaylight.genius.mdsalutil.actions.ActionPushVlan;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldVlanVid;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetTcpDestinationPort;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetTcpSourcePort;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetUdpDestinationPort;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetUdpSourcePort;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.genius.mdsalutil.packet.Ethernet;
import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
import org.opendaylight.genius.mdsalutil.packet.IPv4;
import org.opendaylight.genius.mdsalutil.packet.TCP;
import org.opendaylight.genius.mdsalutil.packet.UDP;
-import org.opendaylight.controller.liblldp.NetUtils;
-import org.opendaylight.controller.liblldp.PacketException;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
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.NodeConnectorRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
import org.opendaylight.yangtools.yang.common.RpcResult;
-import java.math.BigInteger;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NaptEventHandler {
- private NaptManager naptManager;
private static final Logger LOG = LoggerFactory.getLogger(NaptEventHandler.class);
+ private final DataBroker dataBroker;
private static IMdsalApiManager mdsalManager;
- private DataBroker dataBroker;
- private PacketProcessingService pktService;
- private OdlInterfaceRpcService interfaceManagerRpc;
+ private final PacketProcessingService pktService;
+ private final OdlInterfaceRpcService interfaceManagerRpc;
+ private final NaptManager naptManager;
private IInterfaceManager interfaceManager;
- public NaptEventHandler(final DataBroker dataBroker) {
+ public NaptEventHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
+ final NaptManager naptManager,
+ final PacketProcessingService pktService,
+ final OdlInterfaceRpcService interfaceManagerRpc,
+ final IInterfaceManager interfaceManager) {
this.dataBroker = dataBroker;
- }
-
- public void setInterfaceManager(IInterfaceManager interfaceManager) {
- this.interfaceManager = interfaceManager;
- }
-
- public void setMdsalManager(IMdsalApiManager mdsalManager) {
- this.mdsalManager = mdsalManager;
- }
-
- public void setNaptManager(NaptManager naptManager) {
+ NaptEventHandler.mdsalManager = mdsalManager;
this.naptManager = naptManager;
- }
-
- public void setPacketProcessingService(PacketProcessingService packetService) {
- this.pktService = packetService;
- }
-
- public void setInterfaceManagerRpc(OdlInterfaceRpcService interfaceManagerRpc) {
- LOG.trace("Registered interfaceManager successfully");;
+ this.pktService = pktService;
this.interfaceManagerRpc = interfaceManagerRpc;
+ this.interfaceManager = interfaceManager;
}
-
public void handleEvent(NAPTEntryEvent naptEntryEvent){
/*
Flow programming logic of the OUTBOUND NAPT TABLE :
3) Write the router ID to the metadata.
5) Write the flow to the INBOUND NAPT Table and forward to FIB table for routing the traffic.
*/
+ try {
Long routerId = naptEntryEvent.getRouterId();
LOG.info("NAT Service : handleEvent() entry for IP {}, port {}, routerID {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
-
+ // Get the External Gateway MAC Address
+ String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
+ if (extGwMacAddress != null) {
+ LOG.debug("NAT Service : External Gateway MAC address {} found for External Router ID {}", extGwMacAddress, routerId);
+ } else {
+ LOG.error("NAT Service : No External Gateway MAC address found for External Router ID {}", routerId);
+ return;
+ }
//Get the DPN ID
BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
long bgpVpnId = NatConstants.INVALID_ID;
bgpVpnId = routerId;
LOG.debug("NAT Service : BGP VPN ID {}", bgpVpnId);
String vpnName = NatUtil.getRouterName(dataBroker, bgpVpnId);
- String routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+ String routerName = NatUtil.getRouterIdfromVpnInstance(dataBroker, vpnName);
+ if (routerName == null) {
+ LOG.error("NAT Service: Unable to find router for VpnName {}", vpnName);
+ return;
+ }
routerId = NatUtil.getVpnId(dataBroker, routerName);
LOG.debug("NAT Service : Router ID {}", routerId);
dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
return;
}
}
- //Build and install the NAPT translation flows in the Outbound and Inbound NAPT tables
- if(!naptEntryEvent.isPktProcessed()) {
- buildAndInstallNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, internalAddress, externalAddress, protocol);
- buildAndInstallNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, externalAddress, internalAddress, protocol);
+ // Build and install the NAPT translation flows in the Outbound and Inbound NAPT tables
+ if (!naptEntryEvent.isPktProcessed()) {
+ // Added External Gateway MAC Address
+ buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId,
+ internalAddress, externalAddress, protocol, extGwMacAddress);
+ buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId,
+ externalAddress, internalAddress, protocol, extGwMacAddress);
}
//Send Packetout - tcp or udp packets which got punted to controller.
try {
ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
} catch (Exception e) {
- LOG.warn("Failed to decode Packet", e);
+ LOG.warn("NAT Service : Failed to decode Packet", e);
return;
}
}
String interfaceName = getInterfaceNameFromTag(portTag);
LOG.debug("NAT Service : interfaceName fetched from portTag is {}", interfaceName);
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = null;
- long vlanId =0;
+ int vlanId = 0;
iface = interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
if(iface == null) {
LOG.error("NAT Service : Unable to read interface {} from config DataStore", interfaceName);
LOG.debug("NAT Service : vlanId is {}", vlanId);
if(vlanId != 0) {
// Push vlan
- actionInfos.add(new ActionInfo(ActionType.push_vlan, new String[] {}, 0));
- actionInfos.add(new ActionInfo(ActionType.set_field_vlan_vid,
- new String[] { Long.toString(vlanId) }, 1));
+ actionInfos.add(new ActionPushVlan(0));
+ actionInfos.add(new ActionSetFieldVlanVid(1, vlanId));
} else {
LOG.debug("NAT Service : No vlanId {}, may be untagged", vlanId);
}
}else{
LOG.debug("NAT Service : Inside delete Operation of NaptEventHandler");
- removeNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, routerId, naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber());
+ removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId, naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber());
}
- LOG.info("NAT Service : handleNaptEvent() exited for IP, port, routerID : {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
+ LOG.info("NAT Service : handleNaptEvent() exited for IP {}, port {}, routerID : {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
+ } catch (Exception e){
+ LOG.error("NAT Service :Exception in NaptEventHandler.handleEvent() payload {}", naptEntryEvent,e);
+ }
}
- public static void buildAndInstallNatFlows(BigInteger dpnId, short tableId, long vpnId, long routerId, long bgpVpnId, SessionAddress actualSourceAddress,
- SessionAddress translatedSourceAddress, NAPTEntryEvent.Protocol protocol){
+ public static void buildAndInstallNatFlows(BigInteger dpnId, short tableId, long vpnId, long routerId,
+ long bgpVpnId, SessionAddress actualSourceAddress, SessionAddress translatedSourceAddress,
+ NAPTEntryEvent.Protocol protocol, String extGwMacAddress) {
LOG.debug("NAT Service : Build and install NAPT flows in InBound and OutBound tables for dpnId {} and routerId {}", dpnId, routerId);
//Build the flow for replacing the actual IP and port with the translated IP and port.
String actualIp = actualSourceAddress.getIpAddress();
int actualPort = actualSourceAddress.getPortNumber();
String translatedIp = translatedSourceAddress.getIpAddress();
- String translatedPort = String.valueOf(translatedSourceAddress.getPortNumber());
+ int translatedPort = translatedSourceAddress.getPortNumber();
int idleTimeout=0;
- if(tableId == NatConstants.OUTBOUND_NAPT_TABLE) {
+ if(tableId == NwConstants.OUTBOUND_NAPT_TABLE) {
idleTimeout = NatConstants.DEFAULT_NAPT_IDLE_TIMEOUT;
}
long metaDataValue = routerId;
}
LOG.debug("NAT Service : Intranet VPN ID {}", intranetVpnId);
LOG.debug("NAT Service : Router ID {}", routerId);
- FlowEntity snatFlowEntity = MDSALUtil.buildFlowEntity(dpnId, tableId, switchFlowRef, NatConstants.DEFAULT_NAPT_FLOW_PRIORITY, NatConstants.NAPT_FLOW_NAME,
- idleTimeout, 0, NatUtil.getCookieNaptFlow(metaDataValue), buildAndGetMatchInfo(actualIp, actualPort, tableId, protocol, intranetVpnId, vpnId),
- buildAndGetSetActionInstructionInfo(translatedIp, translatedPort, intranetVpnId, vpnId, tableId, protocol));
+ FlowEntity snatFlowEntity = MDSALUtil.buildFlowEntity(dpnId, tableId, switchFlowRef,
+ NatConstants.DEFAULT_NAPT_FLOW_PRIORITY, NatConstants.NAPT_FLOW_NAME, idleTimeout, 0,
+ NatUtil.getCookieNaptFlow(metaDataValue),
+ buildAndGetMatchInfo(actualIp, actualPort, tableId, protocol, intranetVpnId, vpnId),
+ buildAndGetSetActionInstructionInfo(translatedIp, translatedPort, intranetVpnId, vpnId, tableId,
+ protocol, extGwMacAddress));
snatFlowEntity.setSendFlowRemFlag(true);
}
MatchInfo metaDataMatchInfo = null;
- if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+ if(tableId == NwConstants.OUTBOUND_NAPT_TABLE){
ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_source, new String[] {ipAddressAsString, "32" });
if(protocol == NAPTEntryEvent.Protocol.TCP) {
protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.UDP.intValue()});
portMatchInfo = new MatchInfo(MatchFieldType.udp_src, new long[]{port});
}
- metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata, new BigInteger[]{BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID});
+ metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata,
+ new BigInteger[] { MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID });
}else{
- ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_destination, new String[] {ipAddressAsString, "32" });
+ ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_destination, new String[] {ipAddressAsString, "32" });
if(protocol == NAPTEntryEvent.Protocol.TCP) {
protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
portMatchInfo = new MatchInfo(MatchFieldType.tcp_dst, new long[]{port});
matchInfo.add(ipMatchInfo);
matchInfo.add(protocolMatchInfo);
matchInfo.add(portMatchInfo);
- if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+ if(tableId == NwConstants.OUTBOUND_NAPT_TABLE){
matchInfo.add(metaDataMatchInfo);
}
return matchInfo;
}
- private static List<InstructionInfo> buildAndGetSetActionInstructionInfo(String ipAddress, String port, long segmentId, long vpnId, short tableId, NAPTEntryEvent.Protocol protocol) {
+ private static List<InstructionInfo> buildAndGetSetActionInstructionInfo(String ipAddress, int port, long segmentId, long vpnId,
+ short tableId, NAPTEntryEvent.Protocol protocol, String extGwMacAddress) {
ActionInfo ipActionInfo = null;
+ ActionInfo macActionInfo = null;
ActionInfo portActionInfo = null;
ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+ switch (tableId) {
+ case NwConstants.OUTBOUND_NAPT_TABLE:
+ ipActionInfo = new ActionSetSourceIp(ipAddress);
+ // Added External Gateway MAC Address
+ macActionInfo = new ActionSetFieldEthernetSource(new MacAddress(extGwMacAddress));
+ if (protocol == NAPTEntryEvent.Protocol.TCP) {
+ portActionInfo = new ActionSetTcpSourcePort(port);
+ } else if (protocol == NAPTEntryEvent.Protocol.UDP) {
+ portActionInfo = new ActionSetUdpSourcePort(port);
+ }
+ // reset the split-horizon bit to allow traffic from tunnel to be sent back to the provider port
+ instructionInfo.add(new InstructionInfo(InstructionType.write_metadata,
+ new BigInteger[]{MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID.or(MetaDataUtil.METADATA_MASK_SH_FLAG)}));
+ break;
+
+ case NwConstants.INBOUND_NAPT_TABLE:
+ ipActionInfo = new ActionSetDestinationIp(ipAddress);
+ if (protocol == NAPTEntryEvent.Protocol.TCP) {
+ portActionInfo = new ActionSetTcpDestinationPort(port);
+ } else if (protocol == NAPTEntryEvent.Protocol.UDP) {
+ portActionInfo = new ActionSetUdpDestinationPort(port);
+ }
+ instructionInfo.add(new InstructionInfo(InstructionType.write_metadata,
+ new BigInteger[]{MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID}));
+ break;
- if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
- ipActionInfo = new ActionInfo(ActionType.set_source_ip, new String[] {ipAddress});
- if(protocol == NAPTEntryEvent.Protocol.TCP) {
- portActionInfo = new ActionInfo( ActionType.set_tcp_source_port, new String[] {port});
- } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
- portActionInfo = new ActionInfo( ActionType.set_udp_source_port, new String[] {port});
- }
- instructionInfo.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID}));
- }else{
- ipActionInfo = new ActionInfo(ActionType.set_destination_ip, new String[] {ipAddress});
- if(protocol == NAPTEntryEvent.Protocol.TCP) {
- portActionInfo = new ActionInfo( ActionType.set_tcp_destination_port, new String[] {port});
- } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
- portActionInfo = new ActionInfo( ActionType.set_udp_destination_port, new String[] {port});
- }
- instructionInfo.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID}));
+ default:
+ LOG.error("NAT Service : Neither OUTBOUND_NAPT_TABLE nor INBOUND_NAPT_TABLE matches with input table id {}", tableId);
+ return null;
}
listActionInfo.add(ipActionInfo);
listActionInfo.add(portActionInfo);
-
+ if (macActionInfo != null) {
+ listActionInfo.add(macActionInfo);
+ LOG.debug("NAT Service : External GW MAC Address {} is found ", macActionInfo);
+ }
instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
- instructionInfo.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.NAPT_PFIB_TABLE }));
+ instructionInfo.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.NAPT_PFIB_TABLE}));
return instructionInfo;
}
//Build the flow with the port IP and port as the match info.
String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(segmentId), ip, port);
FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
- LOG.debug("NAT Service : Remove the flow in the table {} for the switch with the DPN ID {}", NatConstants.INBOUND_NAPT_TABLE, dpnId);
+ LOG.debug("NAT Service : Remove the flow in the table {} for the switch with the DPN ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId);
mdsalManager.removeFlow(snatFlowEntity);
}
private void sendNaptPacketOut(byte[] pktOut, InterfaceInfo infInfo, List<ActionInfo> actionInfos, Long routerId) {
LOG.trace("NAT Service: Sending packet out DpId {}, interfaceInfo {}", infInfo.getDpId(), infInfo);
- // set in_port, and action as OFPP_TABLE so that it starts from table 0 (lowest table as per spec)
- actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
- BigInteger.valueOf(routerId)}, 2));
- actionInfos.add(new ActionInfo(ActionType.output, new String[] { "0xfffffff9" }, 3));
- NodeConnectorRef in_port = MDSALUtil.getNodeConnRef(infInfo.getDpId(), String.valueOf(infInfo.getPortNo()));
- LOG.debug("NAT Service : in_port for packetout is being set to {}", String.valueOf(infInfo.getPortNo()));
- TransmitPacketInput output = MDSALUtil.getPacketOut(actionInfos, pktOut, infInfo.getDpId().longValue(), in_port);
+ // set inPort, and action as OFPP_TABLE so that it starts from table 0 (lowest table as per spec)
+ actionInfos.add(new ActionSetFieldTunnelId(2, BigInteger.valueOf(routerId)));
+ actionInfos.add(new ActionOutput(3, new Uri("0xfffffff9")));
+ NodeConnectorRef inPort = MDSALUtil.getNodeConnRef(infInfo.getDpId(), String.valueOf(infInfo.getPortNo()));
+ LOG.debug("NAT Service : inPort for packetout is being set to {}", String.valueOf(infInfo.getPortNo()));
+ TransmitPacketInput output = MDSALUtil.getPacketOut(actionInfos, pktOut, infInfo.getDpId().longValue(), inPort);
LOG.trace("NAT Service: Transmitting packet: {}",output);
this.pktService.transmitPacket(output);
}