@Override
protected void programIcmpv6RARule(AclInterface port, List<SubnetInfo> subnets, int addOrRemove) {
- // Allow ICMPv6 Router Advertisement packets from external routers only if ipv6_ra_mode is not
- // specified for an IPv6 subnet.
- if (!AclServiceUtils.isIpv6RaAllowedFromExternalRouters(subnets)) {
- return;
+ if (AclServiceUtils.isIpv6Subnet(subnets)) {
+ /* Allow ICMPv6 Router Advertisement packets from external routers as well as internal routers
+ * if subnet is configured with IPv6 version
+ * Allow ICMPv6 Router Advertisement packets if originating from any LinkLocal Address.
+ */
+ List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
+ List<MatchInfoBase> matches =
+ AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_RA, 0,
+ port.getLPortTag(), serviceMode);
+ matches.addAll(AclServiceUtils.buildIpMatches(
+ new IpPrefixOrAddress(new IpPrefix(AclConstants.IPV6_LINK_LOCAL_PREFIX.toCharArray())),
+ AclServiceManager.MatchCriteria.MATCH_SOURCE));
+ String flowName = "Ingress_ICMPv6" + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
+ + AclConstants.ICMPV6_TYPE_RA + "_LinkLocal_Permit_";
+ syncFlow(port.getDpId(), getAclAntiSpoofingTable(), flowName,
+ AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL", 0,
+ 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
}
- List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
- List<MatchInfoBase> matches =
- AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_RA, 0, port.getLPortTag(), serviceMode);
- // Allow ICMPv6 Router Advertisement packets if originating from any LinkLocal Address.
- matches.addAll(AclServiceUtils.buildIpMatches(
- new IpPrefixOrAddress(new IpPrefix(AclConstants.IPV6_LINK_LOCAL_PREFIX.toCharArray())),
- AclServiceManager.MatchCriteria.MATCH_SOURCE));
-
- String flowName = "Ingress_ICMPv6" + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
- + AclConstants.ICMPV6_TYPE_RA + "_LinkLocal_Permit_";
- syncFlow(port.getDpId(), getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL",
- 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
}
/**
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
return inetAddress;
}
- public static Boolean isIpv6RaAllowedFromExternalRouters(List<SubnetInfo> subnetInfoList) {
+ public static Boolean isIpv6Subnet(List<SubnetInfo> subnetInfoList) {
if (subnetInfoList != null && !subnetInfoList.isEmpty()) {
for (SubnetInfo subnetInfo : subnetInfoList) {
- if (subnetInfo != null && IpVersionV6.class.equals(subnetInfo.getIpVersion())
- && subnetInfo.getIpv6RaMode() == null) {
+ if (subnetInfo != null && IpVersionV6.class.equals(subnetInfo.getIpVersion())) {
return true;
}
}
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.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.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
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.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-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.netvirt.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
}
private void transmitRouterAdvertisement(VirtualPort intf, Ipv6RtrAdvertType advType) {
- Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt(packetService);
+ Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt(packetService, this);
- LOG.debug("in transmitRouterAdvertisement for {}", advType);
VirtualNetwork vnet = getNetwork(intf.getNetworkID());
if (vnet != null) {
- String nodeName;
- String outPort;
+ long elanTag = vnet.getElanTag();
Collection<VirtualNetwork.DpnInterfaceInfo> dpnIfaceList = vnet.getDpnIfaceList();
for (VirtualNetwork.DpnInterfaceInfo dpnIfaceInfo : dpnIfaceList) {
- nodeName = Ipv6Constants.OPENFLOW_NODE_PREFIX + dpnIfaceInfo.getDpId();
- List<NodeConnectorRef> ncRefList = new ArrayList<>();
- for (Long ofPort: dpnIfaceInfo.ofPortList) {
- outPort = nodeName + ":" + ofPort;
- LOG.debug("Transmitting RA {} for node {}, port {}", advType, nodeName, outPort);
- InstanceIdentifier<NodeConnector> outPortId = InstanceIdentifier.builder(Nodes.class)
- .child(Node.class, new NodeKey(new NodeId(nodeName)))
- .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(outPort)))
- .build();
- ncRefList.add(new NodeConnectorRef(outPortId));
- }
- if (!ncRefList.isEmpty()) {
- ipv6RouterAdvert.transmitRtrAdvertisement(advType, intf, ncRefList, null);
+ LOG.debug("transmitRouterAdvertisement: Transmitting RA {} for ELAN Tag {}",
+ advType, elanTag);
+ if (dpnIfaceInfo.getDpId() != null) {
+ ipv6RouterAdvert.transmitRtrAdvertisement(advType, intf, elanTag, null,
+ dpnIfaceInfo.getDpId(), intf.getIntfUUID());
}
}
}
}
return virtualRouter;
}
+
+ public List<Action> getEgressAction(String interfaceName) {
+ List<Action> actions = null;
+ try {
+ GetEgressActionsForInterfaceInputBuilder egressAction =
+ new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName);
+ Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
+ interfaceManagerRpc.getEgressActionsForInterface(egressAction.build());
+ RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
+ if (!rpcResult.isSuccessful()) {
+ LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}",
+ interfaceName, rpcResult.getErrors());
+ } else {
+ actions = rpcResult.getResult().getAction();
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception when egress actions for interface {}", interfaceName, e);
+ }
+ return actions;
+ }
}
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
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.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.Ipv6Header;
BigInteger metadata = packet.getMatch().getMetadata().getMetadata();
long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
String interfaceName = ifMgr.getInterfaceNameFromTag(portTag);
- VirtualPort port = ifMgr.obtainV6Interface(new Uuid(interfaceName));
+ Uuid portId = new Uuid(interfaceName);
+ VirtualPort port = ifMgr.obtainV6Interface(portId);
if (port == null) {
pktProccessedCounter.incrementAndGet();
LOG.info("Port {} not found, skipping.", interfaceName);
LOG.warn("Port for networkId {} is not associated to a Router, skipping.", port.getNetworkID());
return;
}
- Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt(pktService);
- List<NodeConnectorRef> ncRefList = new ArrayList<>();
- ncRefList.add(packet.getIngress());
+ Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt(pktService, ifMgr);
+ LOG.debug("Sending Solicited Router Advertisement for the port {} belongs to the network {}", port,
+ port.getNetworkID());
ipv6RouterAdvert.transmitRtrAdvertisement(Ipv6RtrAdvertType.SOLICITED_ADVERTISEMENT,
- routerPort, ncRefList, rsPdu);
+ routerPort, 0, rsPdu, port.getDpId(), port.getIntfUUID());
pktProccessedCounter.incrementAndGet();
}
package org.opendaylight.netvirt.ipv6service;
+import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants.Ipv6RtrAdvertType;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+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.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterAdvertisementPacket;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterAdvertisementPacketBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterSolicitationPacket;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.router.advertisement.packet.PrefixListBuilder;
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.packet.service.rev130709.TransmitPacketInputBuilder;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
public class Ipv6RouterAdvt {
private static final Logger LOG = LoggerFactory.getLogger(Ipv6RouterAdvt.class);
private final PacketProcessingService packetService;
+ private final IfMgr ifMgr;
- public Ipv6RouterAdvt(PacketProcessingService packetService) {
+ public Ipv6RouterAdvt(PacketProcessingService packetService, IfMgr ifMgr) {
this.packetService = packetService;
+ this.ifMgr = ifMgr;
}
public boolean transmitRtrAdvertisement(Ipv6RtrAdvertType raType, VirtualPort routerPort,
- List<NodeConnectorRef> outportList, RouterSolicitationPacket rsPdu) {
+ long elanTag, RouterSolicitationPacket rsPdu,
+ BigInteger dpnId, Uuid port) {
RouterAdvertisementPacketBuilder raPacket = new RouterAdvertisementPacketBuilder();
updateRAResponse(raType, rsPdu, raPacket, routerPort);
// Serialize the response packet
byte[] txPayload = fillRouterAdvertisementPacket(raPacket.build());
- for (NodeConnectorRef outport: outportList) {
- InstanceIdentifier<Node> outNode = outport.getValue().firstIdentifierOf(Node.class);
- TransmitPacketInput input = new TransmitPacketInputBuilder().setPayload(txPayload)
- .setNode(new NodeRef(outNode))
- .setEgress(outport).build();
- LOG.debug("Transmitting the Router Advt packet out {}", outport);
- JdkFutures.addErrorLogging(packetService.transmitPacket(input), LOG, "transmitPacket");
+ TransmitPacketInput input = null;
+ /* Send solicited router advertisement to requested VM port only.
+ * Send periodic unsolicited router advertisement to ELAN broadcast group.
+ */
+ if (raType == Ipv6RtrAdvertType.SOLICITED_ADVERTISEMENT) {
+ List<Action> actions = ifMgr.getEgressAction(port.getValue());
+ if (actions == null || actions.isEmpty()) {
+ LOG.error("Unable to send solicited router advertisement packet out. Since Egress "
+ + "action is empty for interface {}. ", port.getValue());
+ return false;
+ }
+ input = MDSALUtil.getPacketOut(actions, txPayload, dpnId);
+ LOG.debug("Transmitting the Router Advt packet out to port {}", port.getValue());
+ } else {
+ /* Here we handle UNSOLICITED_ADVERTISEMENT, CEASE_ADVERTISEMENT */
+ long elanGroupId = Ipv6ServiceUtils.getRemoteBCGroup(elanTag);
+ List<ActionInfo> lstActionInfo = new ArrayList<>();
+ lstActionInfo.add(new ActionGroup(elanGroupId));
+ input = MDSALUtil.getPacketOutDefault(lstActionInfo, txPayload, dpnId);
+ LOG.debug("Transmitting the Router Advt packet out to ELAN Group ID {}", elanGroupId);
}
+ JdkFutures.addErrorLogging(packetService.transmitPacket(input), LOG, "transmitPacket");
return true;
}
String DEF_MCAST_MAC = "33:33:00:00:00:01";
//default periodic RA transmission interval. timeunit in sec
long PERIODIC_RA_INTERVAL = 60;
+ int ELAN_GID_MIN = 200000;
enum Ipv6RtrAdvertType {
UNSOLICITED_ADVERTISEMENT,
buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.IPV6_SERVICE_NAME,
NwConstants.IPV6_SERVICE_INDEX)));
}
+
+ public static long getRemoteBCGroup(long elanTag) {
+ return Ipv6Constants.ELAN_GID_MIN + elanTag % Ipv6Constants.ELAN_GID_MIN * 2;
+ }
}
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
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.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
@Test
public void testonPacketReceivedRouterSolicitationWithSingleSubnet() throws Exception {
VirtualPort intf = Mockito.mock(VirtualPort.class);
+ when(intf.getDpId()).thenReturn(new BigInteger(String.valueOf(1)));
+ when(intf.getIntfUUID()).thenReturn(Uuid.getDefaultInstance("ddec9dba-d831-4ad7-84b9-00d7f65f052f"));
when(intf.getMacAddress()).thenReturn("fa:16:3e:4e:18:0c");
when(ifMgrInstance.getInterfaceNameFromTag(anyLong())).thenReturn("ddec9dba-d831-4ad7-84b9-00d7f65f052f");
+ List<Action> actions = new ArrayList<>();
+ actions.add(new ActionNxResubmit(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE).buildAction());
+ when(ifMgrInstance.getEgressAction(any())).thenReturn(actions);
when(ifMgrInstance.obtainV6Interface(any())).thenReturn(intf);
when(ifMgrInstance.getRouterV6InterfaceForNetwork(any())).thenReturn(intf);
"20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 00" // Prefix
);
verify(pktProcessService).transmitPacket(new TransmitPacketInputBuilder().setPayload(expectedPayload)
- .setNode(new NodeRef(ncId)).setEgress(ncRef).build());
+ .setNode(new NodeRef(ncId)).setEgress(ncRef).setIngress(ncRef).setAction(any(List.class)).build());
}
@Test
public void testonPacketReceivedRouterSolicitationWithMultipleSubnets() throws Exception {
VirtualPort intf = Mockito.mock(VirtualPort.class);
+ when(intf.getDpId()).thenReturn(new BigInteger(String.valueOf(1)));
when(intf.getMacAddress()).thenReturn("50:7B:9D:78:54:F3");
+ when(intf.getIntfUUID()).thenReturn(Uuid.getDefaultInstance("ddec9dba-d831-4ad7-84b9-00d7f65f052f"));
when(ifMgrInstance.obtainV6Interface(any())).thenReturn(intf);
when(ifMgrInstance.getInterfaceNameFromTag(anyLong())).thenReturn("ddec9dba-d831-4ad7-84b9-00d7f65f052f");
when(ifMgrInstance.getRouterV6InterfaceForNetwork(any())).thenReturn(intf);
+ List<Action> actions = new ArrayList<>();
+ actions.add(new ActionNxResubmit(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE).buildAction());
+ when(ifMgrInstance.getEgressAction(any())).thenReturn(actions);
IpAddress gwIpAddress = Mockito.mock(IpAddress.class);
when(gwIpAddress.getIpv4Address()).thenReturn(null);
verify(pktProcessService).transmitPacket(new TransmitPacketInputBuilder().setPayload(expectedPayload)
.setNode(new NodeRef(ncId))
- .setEgress(ncRef).build());
+ .setEgress(ncRef).setIngress(ncRef).setAction(any(List.class)).build());
}
private void waitForPacketProcessing() throws InterruptedException {