/* * Copyright (c) 2014 NEC Corporation 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.openflowplugin.openflow.md.core.sal.convertor.match; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.junit.Before; import org.junit.Test; import org.opendaylight.openflowplugin.api.OFConstants; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManager; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManagerFactory; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; 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.flow.types.rev131026.flow.Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.EtherType; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowWildcardsV10; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumber; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.EthDst; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.EthSrc; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.EthType; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.InPort; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.MatchField; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OpenflowBasicClass; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OxmMatchType; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.VlanVid; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntryBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.EthDstCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.EthSrcCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.EthTypeCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.InPortCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.VlanVidCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.eth.dst._case.EthDstBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.eth.src._case.EthSrcBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.eth.type._case.EthTypeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.in.port._case.InPortBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.vlan.vid._case.VlanVidBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.v10.grouping.MatchV10; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.v10.grouping.MatchV10Builder; /** * Unit test for {@link MatchConvertorImpl}. */ public class MatchResponseConvertorTest { private static final BigInteger DPID = BigInteger.TEN; private static final Long IN_PORT = 6L; private static final String URI_IN_PORT = "openflow:" + DPID + ":" + IN_PORT; private static final MacAddress MAC_SRC = MacAddress.getDefaultInstance("00:11:22:33:44:55"); private static final MacAddress MAC_DST = MacAddress.getDefaultInstance("fa:fb:fc:fd:fe:ff"); private static final int ETHTYPE_IPV4 = 0x800; private static final short VLAN_PCP = 7; private static final Ipv4Address IPV4_SRC = Ipv4Address.getDefaultInstance("192.168.10.254"); private static final Ipv4Address IPV4_DST = Ipv4Address.getDefaultInstance("10.1.2.3"); private static final int DL_VLAN_NONE = 0xffff; private ConvertorManager convertorManager; @Before public void setUp() { convertorManager = ConvertorManagerFactory.createDefaultManager(); } /** * Test method for {@link org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchResponseConvertor#convert(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.MatchEntriesGrouping, org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData)} }. */ @Test public void testFromOFMatchToSALMatch() { List<MatchEntry> entries = createDefaultMatchEntry(); int[] vids = { // Match packet with VLAN tag regardless of its value. -1, // Match untagged frame. 0, // Match packet with VLAN tag and VID equals the specified value. 1, 20, 4095, }; for (int vid : vids) { List<MatchEntry> MatchEntry = new ArrayList<MatchEntry>(entries); MatchEntry.add(toOfVlanVid(vid)); org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.Match ofMatch = createOFMatch(MatchEntry); final VersionDatapathIdConvertorData data = new VersionDatapathIdConvertorData(OFConstants.OFP_VERSION_1_3); data.setDatapathId(DPID); final MatchBuilder builder = convert(ofMatch, data); checkDefault(builder); VlanMatch vlanMatch = builder.getVlanMatch(); int expectedVid = (vid < 0) ? 0 : vid; Boolean expectedCfi = vid != 0; assertEquals(expectedVid, vlanMatch.getVlanId().getVlanId(). getValue().intValue()); assertEquals(expectedCfi, vlanMatch.getVlanId().isVlanIdPresent()); assertEquals(null, vlanMatch.getVlanPcp()); } } /** * Test method for {@link org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchV10ResponseConvertor#convert(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.v10.grouping.MatchV10, org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData)} }. */ @Test public void testFromOFMatchV10ToSALMatch() { int[] vids = { // Match untagged frame. DL_VLAN_NONE, // Match packet with VLAN tag and VID equals the specified value. 1, 20, 4095, }; short[] dscps = { 0, 1, 20, 40, 62, 63, }; FlowWildcardsV10Builder wcBuilder = new FlowWildcardsV10Builder(); for (int vid : vids) { for (short dscp : dscps) { short tos = (short) (dscp << 2); MatchV10Builder builder = new MatchV10Builder(); builder.setDlSrc(MAC_SRC).setDlDst(MAC_DST).setDlVlan(vid). setDlVlanPcp(VLAN_PCP).setDlType(ETHTYPE_IPV4). setInPort(IN_PORT.intValue()). setNwSrc(IPV4_SRC).setNwDst(IPV4_DST).setNwTos(tos); wcBuilder.setAll(false).setNwProto(true).setTpSrc(true). setTpDst(true); if (vid == DL_VLAN_NONE) { wcBuilder.setDlVlanPcp(true); } FlowWildcardsV10 wc = wcBuilder.build(); MatchV10 ofMatch = builder.setWildcards(wc).build(); final VersionDatapathIdConvertorData data = new VersionDatapathIdConvertorData(OFConstants.OFP_VERSION_1_0); data.setDatapathId(DPID); Match match = convert(ofMatch, data).build(); checkDefaultV10(match, wc, vid); IpMatch ipMatch = match.getIpMatch(); assertEquals(null, ipMatch.getIpProtocol()); assertEquals(dscp, ipMatch.getIpDscp().getValue().shortValue()); assertEquals(null, ipMatch.getIpEcn()); // Set all wildcard bits. wc = wcBuilder.setAll(true).build(); ofMatch = builder.setWildcards(wc).build(); match = convert(ofMatch, data).build(); checkDefaultV10(match, wc, vid); assertEquals(null, match.getIpMatch()); } } } private static void checkDefault(final MatchBuilder builder) { EthernetMatch ethMatch = builder.getEthernetMatch(); assertEquals(MAC_SRC, ethMatch.getEthernetSource().getAddress()); assertEquals(null, ethMatch.getEthernetSource().getMask()); assertEquals(MAC_DST, ethMatch.getEthernetDestination().getAddress()); assertEquals(null, ethMatch.getEthernetDestination().getMask()); assertEquals(ETHTYPE_IPV4, ethMatch.getEthernetType().getType(). getValue().intValue()); NodeConnectorId inPort = builder.getInPort(); assertEquals(URI_IN_PORT, inPort.getValue()); } private static org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.Match createOFMatch(final List<MatchEntry> entries) { org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.MatchBuilder builder = new org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.MatchBuilder(); return builder.setType(OxmMatchType.class).setMatchEntry(entries). build(); } private static List<MatchEntry> createDefaultMatchEntry() { List<MatchEntry> entries = new ArrayList<>(); entries.add(toOfPort(InPort.class, IN_PORT)); MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder(); EthSrcCaseBuilder ethSrcCaseBuilder = new EthSrcCaseBuilder(); EthSrcBuilder ethSrcBuilder = new EthSrcBuilder(); ethSrcBuilder.setMacAddress(MAC_SRC); ethSrcCaseBuilder.setEthSrc(ethSrcBuilder.build()); matchEntryBuilder.setMatchEntryValue(ethSrcCaseBuilder.build()); matchEntryBuilder.setOxmMatchField(EthSrc.class); entries.add(matchEntryBuilder.build()); EthDstCaseBuilder ethDstCaseBuilder = new EthDstCaseBuilder(); EthDstBuilder ethDstBuilder = new EthDstBuilder(); ethDstBuilder.setMacAddress(MAC_DST); ethDstCaseBuilder.setEthDst(ethDstBuilder.build()); matchEntryBuilder.setMatchEntryValue(ethDstCaseBuilder.build()); matchEntryBuilder.setOxmMatchField(EthDst.class); entries.add(matchEntryBuilder.build()); entries.add(toOfEthernetType(ETHTYPE_IPV4)); return entries; } private static MatchEntry toOfEthernetType(final int ethType) { MatchEntryBuilder builder = new MatchEntryBuilder(); builder.setOxmClass(OpenflowBasicClass.class); builder.setHasMask(false); builder.setOxmMatchField(EthType.class); EthTypeCaseBuilder ethTypeCaseBuilder = new EthTypeCaseBuilder(); EthTypeBuilder ethTypeBuilder = new EthTypeBuilder(); EtherType etherType = new EtherType(ethType); ethTypeBuilder.setEthType(etherType); ethTypeCaseBuilder.setEthType(ethTypeBuilder.build()); builder.setMatchEntryValue(ethTypeCaseBuilder.build()); return builder.build(); } private static MatchEntry toOfPort(final Class<? extends MatchField> field, final Long portNumber) { MatchEntryBuilder builder = new MatchEntryBuilder(); builder.setOxmClass(OpenflowBasicClass.class); builder.setHasMask(false); builder.setOxmMatchField(field); InPortCaseBuilder inPortCaseBuilder = new InPortCaseBuilder(); InPortBuilder portBuilder = new InPortBuilder(); portBuilder.setPortNumber(new PortNumber(portNumber)); inPortCaseBuilder.setInPort(portBuilder.build()); builder.setMatchEntryValue(inPortCaseBuilder.build()); return builder.build(); } private static MatchEntry toOfVlanVid(final int vid) { MatchEntryBuilder builder = new MatchEntryBuilder(); boolean cfi = true; Integer vidValue = vid; byte[] mask = null; builder.setOxmClass(OpenflowBasicClass.class); builder.setOxmMatchField(VlanVid.class); VlanVidCaseBuilder vlanVidCaseBuilder = new VlanVidCaseBuilder(); if (vid == 0) { // Match untagged frame. cfi = false; } else if (vid < 0) { // Match packet with VLAN tag regardless of its value. mask = new byte[]{0x10, 0x00}; vidValue = 0; } VlanVidBuilder vlanVidBuilder = new VlanVidBuilder(); vlanVidBuilder.setCfiBit(cfi); vlanVidBuilder.setVlanVid(vidValue); boolean hasMask = mask != null; if (hasMask) { vlanVidBuilder.setMask(mask); } vlanVidCaseBuilder.setVlanVid(vlanVidBuilder.build()); builder.setHasMask(hasMask); builder.setMatchEntryValue(vlanVidCaseBuilder.build()); return builder.build(); } private static void checkDefaultV10(final Match match, final FlowWildcardsV10 wc, final int vid) { EthernetMatch ethMatch = match.getEthernetMatch(); if (wc.isDLSRC()) { if (ethMatch != null) { assertEquals(null, ethMatch.getEthernetSource()); } } else { assertEquals(MAC_SRC, ethMatch.getEthernetSource().getAddress()); } if (ethMatch != null) { if (wc.isDLDST()) { assertEquals(null, ethMatch.getEthernetDestination()); } else { assertNotEquals(null, ethMatch.getEthernetDestination()); assertEquals(MAC_DST, ethMatch.getEthernetDestination().getAddress()); } } if (wc.isDLTYPE()) { if (ethMatch != null) { assertEquals(null, ethMatch.getEthernetType()); } assertEquals(null, match.getLayer3Match()); } else { assert ethMatch != null; assertEquals(ETHTYPE_IPV4, ethMatch.getEthernetType().getType(). getValue().intValue()); Ipv4Match ipv4Match = (Ipv4Match) match.getLayer3Match(); assertEquals(IPV4_SRC.getValue() + "/32", ipv4Match.getIpv4Source().getValue()); assertEquals(IPV4_DST.getValue() + "/32", ipv4Match.getIpv4Destination().getValue()); } VlanMatch vlanMatch = match.getVlanMatch(); if (wc.isDLVLAN()) { assertEquals(null, vlanMatch); } else { int expectedVid; Boolean expectedCfi; if (vid == DL_VLAN_NONE) { expectedVid = 0; expectedCfi = Boolean.FALSE; } else { expectedVid = vid; expectedCfi = Boolean.TRUE; } assertEquals(expectedVid, vlanMatch.getVlanId().getVlanId(). getValue().intValue()); assertEquals(expectedCfi, vlanMatch.getVlanId().isVlanIdPresent()); if (wc.isDLVLANPCP()) { assertEquals(null, vlanMatch.getVlanPcp()); } else { assertEquals(VLAN_PCP, vlanMatch.getVlanPcp().getValue().shortValue()); } } } private MatchBuilder convert(MatchV10 match, VersionDatapathIdConvertorData data) { final Optional<MatchBuilder> salMatchOptional = convertorManager.convert(match, data); return salMatchOptional.orElse(new MatchBuilder()); } private MatchBuilder convert(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.grouping.Match match, VersionDatapathIdConvertorData data) { final Optional<MatchBuilder> salMatchOptional = convertorManager.convert(match, data); return salMatchOptional.orElse(new MatchBuilder()); } }