@Test
  public void testGetVMac() throws Exception {
    vr.createInterface("if1", "t1|netVirt1", null, true);
    vr.createInterface("if2", "t1|netVirt2", null, true);
    vr.createInterface("if3", "t1|netVirt3", null, false);
    vr.createInterface("ifs", null, "system|rs", true);
    vr.assignInterfaceAddr("if1", "10.1.1.1", "255.255.255.0");
    vr.assignInterfaceAddr("if1", "10.2.1.1", "255.255.255.0");
    vr.assignInterfaceAddr("if2", "10.1.2.1", "255.255.255.0");
    vr.assignInterfaceAddr("if3", "10.1.3.1", "255.255.255.0");
    vr.assignInterfaceAddr("ifs", "192.168.1.1", "255.255.255.0");

    int ip = IPv4.toIPv4Address("10.1.1.1");
    long vMac = vr.getVMac("t1|netVirt1", ip);
    long expectedVMac = Ethernet.toLong(Ethernet.toMACAddress("00:11:22:33:44:55"));
    assertEquals(expectedVMac, vMac);

    ip = IPv4.toIPv4Address("10.2.1.1");
    vMac = vr.getVMac("t1|netVirt1", ip);
    assertEquals(expectedVMac, vMac);

    ip = IPv4.toIPv4Address("10.1.3.1");
    vMac = vr.getVMac("t1|netVirt3", ip);
    assertEquals(expectedVMac, vMac);

    ip = IPv4.toIPv4Address("192.168.1.1");
    vMac = vr.getVMac("system|rs", ip);
    assertEquals(expectedVMac, vMac);

    ip = IPv4.toIPv4Address("10.2.1.1");
    vMac = vr.getVMac("netVirt1", ip);
    assertEquals(0, vMac);

    ip = IPv4.toIPv4Address("10.2.1.2");
    vMac = vr.getVMac("t1|netVirt1", ip);
    assertEquals(0, vMac);
  }
  /**
   * Generates a DHCP request Ethernet frame.
   *
   * @param hostMac The host MAC address of for the request.
   * @returnAn An Ethernet frame that contains a DHCP request packet.
   */
  public static Ethernet DhcpDiscoveryRequestEthernet(MACAddress hostMac) {
    List<DHCPOption> optionList = new ArrayList<DHCPOption>();

    byte[] requestValue = new byte[4];
    requestValue[0] = requestValue[1] = requestValue[2] = requestValue[3] = 0;
    DHCPOption requestOption =
        new DHCPOption()
            .setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue())
            .setLength((byte) 4)
            .setData(requestValue);

    byte[] msgTypeValue = new byte[1];
    msgTypeValue[0] = 1; // DHCP request
    DHCPOption msgTypeOption =
        new DHCPOption()
            .setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue())
            .setLength((byte) 1)
            .setData(msgTypeValue);

    byte[] reqParamValue = new byte[4];
    reqParamValue[0] = 1; // subnet mask
    reqParamValue[1] = 3; // Router
    reqParamValue[2] = 6; // Domain Name Server
    reqParamValue[3] = 42; // NTP Server
    DHCPOption reqParamOption =
        new DHCPOption()
            .setCode(DHCP.DHCPOptionCode.OptionCode_RequestedParameters.getValue())
            .setLength((byte) 4)
            .setData(reqParamValue);

    byte[] clientIdValue = new byte[7];
    clientIdValue[0] = 1; // Ethernet
    System.arraycopy(hostMac.toBytes(), 0, clientIdValue, 1, 6);
    DHCPOption clientIdOption =
        new DHCPOption()
            .setCode(DHCP.DHCPOptionCode.OptionCode_ClientID.getValue())
            .setLength((byte) 7)
            .setData(clientIdValue);

    DHCPOption endOption =
        new DHCPOption()
            .setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue())
            .setLength((byte) 0)
            .setData(null);

    optionList.add(requestOption);
    optionList.add(msgTypeOption);
    optionList.add(reqParamOption);
    optionList.add(clientIdOption);
    optionList.add(endOption);

    Ethernet requestPacket = new Ethernet();
    requestPacket
        .setSourceMACAddress(hostMac.toBytes())
        .setDestinationMACAddress(broadcastMac)
        .setEtherType(Ethernet.TYPE_IPv4)
        .setPayload(
            new IPv4()
                .setVersion((byte) 4)
                .setDiffServ((byte) 0)
                .setIdentification((short) 100)
                .setFlags((byte) 0)
                .setFragmentOffset((short) 0)
                .setTtl((byte) 250)
                .setProtocol(IPv4.PROTOCOL_UDP)
                .setChecksum((short) 0)
                .setSourceAddress(0)
                .setDestinationAddress(broadcastIp)
                .setPayload(
                    new UDP()
                        .setSourcePort(UDP.DHCP_CLIENT_PORT)
                        .setDestinationPort(UDP.DHCP_SERVER_PORT)
                        .setChecksum((short) 0)
                        .setPayload(
                            new DHCP()
                                .setOpCode(DHCP.OPCODE_REQUEST)
                                .setHardwareType(DHCP.HWTYPE_ETHERNET)
                                .setHardwareAddressLength((byte) 6)
                                .setHops((byte) 0)
                                .setTransactionId(0x00003d1d)
                                .setSeconds((short) 0)
                                .setFlags((short) 0)
                                .setClientIPAddress(0)
                                .setYourIPAddress(0)
                                .setServerIPAddress(0)
                                .setGatewayIPAddress(0)
                                .setClientHardwareAddress(hostMac.toBytes())
                                .setOptions(optionList))));

    return requestPacket;
  }
public class VRouterTest extends PlatformTestCase {
  private VRouterImpl vr;
  private static Long vMac1 = Ethernet.toLong(Ethernet.toMACAddress("00:11:22:33:44:55"));
  VirtualRouterManager vRtrManager;

  @Before
  public void setUp() throws Exception {
    super.setUp();
    vRtrManager = createMock(VirtualRouterManager.class);
    vr = new VRouterImpl("r1", "t1", vMac1, vRtrManager);
  }

  @Test
  public void testGetters() {
    assertEquals("r1", vr.getName());
    assertEquals("t1", vr.getTenant());
  }

  @Test
  /* This test tests internal working of the class alone */
  public void testCreateInterface() {
    vr.createInterface("if1", "netVirt1", null, true);
    assertNotNull(vr.getInterfaceMap().get("if1"));
    assertEquals(true, vr.getInterfaceMap().get("if1").isNetVirt());

    vr.createInterface("if2", null, "rtr1", true);
    assertNotNull(vr.getInterfaceMap().get("if2"));
    assertEquals(false, vr.getInterfaceMap().get("if2").isNetVirt());

    assertEquals(2, vr.getInterfaceMap().size());
  }

  @Test
  /* This test tests internal working of the class alone */
  public void testAssignInterfaceAddr() throws Exception {
    try {
      vr.assignInterfaceAddr("if1", "10.10.1.1", "255.255.0.0");
      fail();
    } catch (IllegalArgumentException e) {
      /* An exception must have been thrown */
    }
    vr.createInterface("if1", "netVirt1", null, true);
    vr.createInterface("if2", null, "rtr1", true);
    vr.assignInterfaceAddr("if1", "10.10.1.1", "255.255.0.0");
    IPV4Subnet addr = new IPV4Subnet("10.10.1.1/16");
    assertNotNull(vr.getInterfaceMap().get("if1").getAddrs().contains(addr));

    vr.assignInterfaceAddr("if2", "200.10.1.1", "255.255.255.0");
    addr = new IPV4Subnet("200.10.1.1/24");
    assertNotNull(vr.getInterfaceMap().get("if2").getAddrs().contains(addr));

    vr.assignInterfaceAddr("if1", "10.20.1.1", "255.255.0.0");
    addr = new IPV4Subnet("10.20.1.1/16");
    assertNotNull(vr.getInterfaceMap().get("if1").getAddrs().contains(addr));
    assertEquals(2, vr.getInterfaceMap().get("if1").getAddrs().size());
  }

  @Test
  /* This test tests internal working of the class alone */
  public void testAddRoutingRule() throws Exception {
    vr.createInterface("if1", "netVirt1", null, true);
    vr.createInterface("if2", "netVirt2", null, true);
    vr.createInterface("ifs", null, "rtr1", true);

    /* Test putting rules in the SrcHostRuleMap */
    vr.addRoutingRule(
        null, null, "10.10.1.1", "0.0.0.0", null, "netVirt1", null, null, null, null, "permit");
    assertEquals(1, vr.getSrcHostRuleMap().get("10.10.1.1").ruleSet.size());
    vr.addRoutingRule(
        null, null, "10.10.1.1", "0.0.0.0", "tenant1", null, null, null, null, null, "permit");
    assertEquals(2, vr.getSrcHostRuleMap().get("10.10.1.1").ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.1.1",
        "0.0.0.0",
        null,
        null,
        "10.20.1.1",
        "0.0.0.0",
        null,
        null,
        "permit");
    assertEquals(3, vr.getSrcHostRuleMap().get("10.10.1.1").ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.1.1",
        "0.0.0.0",
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        null,
        "permit");
    assertEquals(1, vr.getSrcHostRuleMap().get("10.10.1.1").subnetTrie.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.1.1",
        "0.0.0.0",
        null,
        null,
        "255.255.255.255",
        "255.255.255.255",
        null,
        null,
        "deny");
    assertEquals(2, vr.getSrcHostRuleMap().get("10.10.1.1").subnetTrie.size());

    /* Test putting rules in the SrcNetVirtRuleMap */
    vr.addRoutingRule(
        null, "netVirt1", null, null, null, "netVirt2", null, null, "if2", null, "deny");
    assertEquals(1, vr.getSrcNetVirtRuleMap().get("netVirt1").ruleSet.size());
    vr.addRoutingRule(
        null, "netVirt1", null, null, null, null, "10.20.1.1", "0.0.0.0", "if2", null, "deny");
    assertEquals(2, vr.getSrcNetVirtRuleMap().get("netVirt1").ruleSet.size());
    vr.addRoutingRule(
        null, "netVirt1", null, null, "Tenant2", null, null, null, "if2", null, "permit");
    assertEquals(3, vr.getSrcNetVirtRuleMap().get("netVirt1").ruleSet.size());
    vr.addRoutingRule(
        null,
        "netVirt1",
        null,
        null,
        null,
        null,
        "10.30.0.0",
        "0.0.255.255",
        "ifs",
        "10.30.1.1",
        "permit");
    assertEquals(1, vr.getSrcNetVirtRuleMap().get("netVirt1").subnetTrie.size());
    vr.addRoutingRule(
        null, "netVirt1", null, null, null, null, "0.0.0.0", "255.255.255.255", null, null, "deny");
    assertEquals(2, vr.getSrcNetVirtRuleMap().get("netVirt1").subnetTrie.size());

    /* Test putting rules in the SrcTenantRuleMap */
    vr.addRoutingRule(
        "t1", null, null, null, null, null, "10.30.1.1", "0.0.0.0", "ifs", null, "permit");
    assertEquals(1, vr.getSrcTenantRuleMap().get("t1").ruleSet.size());
    vr.addRoutingRule("t1", null, null, null, "t2", null, null, null, null, null, "permit");
    assertEquals(2, vr.getSrcTenantRuleMap().get("t1").ruleSet.size());
    vr.addRoutingRule("t1", null, null, null, null, "netVirt4", null, null, null, null, "permit");
    assertEquals(3, vr.getSrcTenantRuleMap().get("t1").ruleSet.size());
    vr.addRoutingRule(
        "t1", null, null, null, null, null, "10.30.0.0", "0.0.255.255", null, null, "deny");
    assertEquals(1, vr.getSrcTenantRuleMap().get("t1").subnetTrie.size());
    vr.addRoutingRule(
        "t1",
        null,
        null,
        null,
        null,
        null,
        "255.255.255.255",
        "255.255.255.255",
        "ifs",
        null,
        "permit");
    assertEquals(2, vr.getSrcTenantRuleMap().get("t1").subnetTrie.size());

    /* Test putting rules in the srcSubnetRuleTrie */
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        null,
        "10.30.0.1",
        "0.0.0.0",
        "ifs",
        null,
        "permit");
    IPV4Subnet addr = new IPV4Subnet("10.10.0.0/16");
    assertEquals(1, vr.getSrcSubnetRuleTrie().get(addr).ruleSet.size());
    vr.addRoutingRule(
        null, null, "10.10.0.0", "0.0.255.255", "t2", null, null, null, "ifs", null, "permit");
    assertEquals(2, vr.getSrcSubnetRuleTrie().get(addr).ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        "netVirt4",
        null,
        null,
        "ifs",
        null,
        "permit");
    assertEquals(3, vr.getSrcSubnetRuleTrie().get(addr).ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        null,
        "10.30.0.1",
        "0.0.255.255",
        null,
        null,
        "deny");
    assertEquals(1, vr.getSrcSubnetRuleTrie().get(addr).subnetTrie.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        null,
        "255.255.255.255",
        "255.255.255.255",
        null,
        null,
        "permit");
    assertEquals(2, vr.getSrcSubnetRuleTrie().get(addr).subnetTrie.size());

    try {
      /* Use an invalid interface and see whether there is an exception */
      vr.addRoutingRule(
          null, "netVirt1", null, null, "t2", null, null, null, "if3", null, "permit");
      fail();
    } catch (IllegalArgumentException e) {
      /* Exception should be thrown */
    }
  }

  @Test
  public void testAddRoutingRuleWithNextHopGatewayPool() throws Exception {
    vr.createInterface("if1", "netVirt1", null, true);
    vr.createInterface("if2", "netVirt2", null, true);
    vr.createInterface("ifs", null, "rtr1", true);

    /* Test putting rules in the SrcHostRuleMap */
    vr.addRoutingRule(
        null,
        null,
        "10.10.1.1",
        "0.0.0.0",
        null,
        "netVirt1",
        null,
        null,
        null,
        null,
        "permit",
        "testpool");
    assertEquals(1, vr.getSrcHostRuleMap().get("10.10.1.1").ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.1.1",
        "0.0.0.0",
        "tenant1",
        null,
        null,
        null,
        null,
        null,
        "permit",
        "testpool");
    assertEquals(2, vr.getSrcHostRuleMap().get("10.10.1.1").ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.1.1",
        "0.0.0.0",
        null,
        null,
        "10.20.1.1",
        "0.0.0.0",
        null,
        null,
        "permit",
        "testpool");
    assertEquals(3, vr.getSrcHostRuleMap().get("10.10.1.1").ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.1.1",
        "0.0.0.0",
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        null,
        "permit",
        "testpool");
    assertEquals(1, vr.getSrcHostRuleMap().get("10.10.1.1").subnetTrie.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.1.1",
        "0.0.0.0",
        null,
        null,
        "255.255.255.255",
        "255.255.255.255",
        null,
        null,
        "deny",
        "testpool");
    assertEquals(2, vr.getSrcHostRuleMap().get("10.10.1.1").subnetTrie.size());

    /* Test putting rules in the SrcNetVirtRuleMap */
    vr.addRoutingRule(
        null,
        "netVirt1",
        null,
        null,
        null,
        "netVirt2",
        null,
        null,
        "if2",
        null,
        "deny",
        "testpool");
    assertEquals(1, vr.getSrcNetVirtRuleMap().get("netVirt1").ruleSet.size());
    vr.addRoutingRule(
        null,
        "netVirt1",
        null,
        null,
        null,
        null,
        "10.20.1.1",
        "0.0.0.0",
        "if2",
        null,
        "deny",
        "testpool");
    assertEquals(2, vr.getSrcNetVirtRuleMap().get("netVirt1").ruleSet.size());
    vr.addRoutingRule(
        null,
        "netVirt1",
        null,
        null,
        "Tenant2",
        null,
        null,
        null,
        "if2",
        null,
        "permit",
        "testpool");
    assertEquals(3, vr.getSrcNetVirtRuleMap().get("netVirt1").ruleSet.size());
    vr.addRoutingRule(
        null,
        "netVirt1",
        null,
        null,
        null,
        null,
        "10.30.0.0",
        "0.0.255.255",
        "ifs",
        "10.30.1.1",
        "permit",
        null);
    assertEquals(1, vr.getSrcNetVirtRuleMap().get("netVirt1").subnetTrie.size());
    vr.addRoutingRule(
        null,
        "netVirt1",
        null,
        null,
        null,
        null,
        "0.0.0.0",
        "255.255.255.255",
        null,
        null,
        "deny",
        "testpool");
    assertEquals(2, vr.getSrcNetVirtRuleMap().get("netVirt1").subnetTrie.size());

    /* Test putting rules in the SrcTenantRuleMap */
    vr.addRoutingRule(
        "t1",
        null,
        null,
        null,
        null,
        null,
        "10.30.1.1",
        "0.0.0.0",
        "ifs",
        null,
        "permit",
        "testpool");
    assertEquals(1, vr.getSrcTenantRuleMap().get("t1").ruleSet.size());
    vr.addRoutingRule(
        "t1", null, null, null, "t2", null, null, null, null, null, "permit", "testpool");
    assertEquals(2, vr.getSrcTenantRuleMap().get("t1").ruleSet.size());
    vr.addRoutingRule(
        "t1", null, null, null, null, "netVirt4", null, null, null, null, "permit", "testpool");
    assertEquals(3, vr.getSrcTenantRuleMap().get("t1").ruleSet.size());
    vr.addRoutingRule(
        "t1",
        null,
        null,
        null,
        null,
        null,
        "10.30.0.0",
        "0.0.255.255",
        null,
        null,
        "deny",
        "testpool");
    assertEquals(1, vr.getSrcTenantRuleMap().get("t1").subnetTrie.size());
    vr.addRoutingRule(
        "t1",
        null,
        null,
        null,
        null,
        null,
        "255.255.255.255",
        "255.255.255.255",
        "ifs",
        null,
        "permit",
        "testpool");
    assertEquals(2, vr.getSrcTenantRuleMap().get("t1").subnetTrie.size());

    /* Test putting rules in the srcSubnetRuleTrie */
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        null,
        "10.30.0.1",
        "0.0.0.0",
        "ifs",
        null,
        "permit",
        "testpool");
    IPV4Subnet addr = new IPV4Subnet("10.10.0.0/16");
    assertEquals(1, vr.getSrcSubnetRuleTrie().get(addr).ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        "t2",
        null,
        null,
        null,
        "ifs",
        null,
        "permit",
        "testpool");
    assertEquals(2, vr.getSrcSubnetRuleTrie().get(addr).ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        "netVirt4",
        null,
        null,
        "ifs",
        null,
        "permit",
        "testpool");
    assertEquals(3, vr.getSrcSubnetRuleTrie().get(addr).ruleSet.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        null,
        "10.30.0.1",
        "0.0.255.255",
        null,
        null,
        "deny",
        "testpool");
    assertEquals(1, vr.getSrcSubnetRuleTrie().get(addr).subnetTrie.size());
    vr.addRoutingRule(
        null,
        null,
        "10.10.0.0",
        "0.0.255.255",
        null,
        null,
        "255.255.255.255",
        "255.255.255.255",
        null,
        null,
        "permit",
        "testpool");
    assertEquals(2, vr.getSrcSubnetRuleTrie().get(addr).subnetTrie.size());

    try {
      /* Use an invalid interface and see whether there is an exception */
      vr.addRoutingRule(
          null, "netVirt1", null, null, "t2", null, null, null, "if3", null, "permit", "testpool");
      fail();
    } catch (IllegalArgumentException e) {
      /* Exception should be thrown */
    }
  }

  @Test
  public void testIsIfaceDown() {
    vr.createInterface("if1", "t1|netVirt1", null, true);
    vr.createInterface("if2", "t1|netVirt2", null, false);
    vr.createInterface("if3", null, "t2|r2", true);
    vr.createInterface("if4", null, "t2|r3", false);
    boolean down;
    down = vr.isIfaceDown("t1|netVirt1");
    assertEquals(false, down);
    down = vr.isIfaceDown("t1|netVirt2");
    assertEquals(true, down);
    down = vr.isIfaceDown("t2|r2");
    assertEquals(false, down);
    down = vr.isIfaceDown("t2|r3");
    assertEquals(true, down);
    down = vr.isIfaceDown("t2|r4");
    assertEquals(true, down);
  }

  @Test
  public void testGetForwardingAction() throws Exception {
    vr.createInterface("if1", "t1|netVirt1", null, true);
    vr.createInterface("if2", "t1|netVirt2", null, true);
    vr.createInterface("if3", "t1|netVirt3", null, false);
    vr.createInterface("ifs", null, "system|rs", true);
    vr.assignInterfaceAddr("if1", "10.1.1.1", "0.0.0.255");
    vr.assignInterfaceAddr("if2", "10.1.2.1", "0.0.0.255");
    vr.assignInterfaceAddr("if3", "10.1.3.1", "0.0.0.255");

    VRouterImpl vr2 = new VRouterImpl("r2", "t2", vMac1, vRtrManager);
    vr2.createInterface("if1", "t2|netVirt1", null, true);
    vr2.createInterface("if2", "t2|netVirt2", null, true);
    vr2.createInterface("if3", "t2|netVirt3", null, true);
    vr2.createInterface("ifs", null, "system|rs", true);

    /* External tenant router */
    VRouterImpl vrx = new VRouterImpl("rx", "tx", vMac1, vRtrManager);
    vrx.createInterface("if1", "tx|netVirtx", null, true);
    vrx.createInterface("ifs", null, "system|rs", true);

    /* System Router */
    VRouterImpl vrs = new VRouterImpl("rs", "system", vMac1, vRtrManager);
    vrs.createInterface("if1", null, "t1|r1", true);
    vrs.createInterface("if2", null, "t2|r2", true);
    vrs.createInterface("ifx", null, "tx|rx", true);

    VNS netVirtA1 = new VNS("t1|netVirt1");
    VNS netVirtA2 = new VNS("t1|netVirt2");
    VNS netVirtA3 = new VNS("t1|netVirt3");
    VNS netVirtB1 = new VNS("t2|netVirt1");
    VNS netVirtx = new VNS("tx|netVirtx");
    int ip1, ip2;
    ip1 = IPv4.toIPv4Address("10.1.1.2");
    ip2 = IPv4.toIPv4Address("10.1.2.2");
    ForwardingAction action;

    /* There is no routing rule so packet is dropped */
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtA2, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());

    vr.addRoutingRule(
        null,
        null,
        "10.1.1.2",
        "0.0.0.0",
        null,
        null,
        "0.0.0.0",
        "255.255.255.255",
        null,
        null,
        "permit");
    /* Test routing between NetVirts on the same tenant */
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtA2, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals(null, action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals("t1|netVirt2", action.getDstNetVirtName());
    assertEquals(vMac1.longValue(), action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Since interface if3 is down, the packet is dropped */
    ip2 = IPv4.toIPv4Address("10.1.3.2");
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtA3, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());

    /* The interface to the system router is picked by default */
    ip2 = IPv4.toIPv4Address("10.2.1.2");
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("system|rs", action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    vr.addRoutingRule(
        null, null, "10.1.1.2", "0.0.0.0", null, null, "10.2.1.0", "0.0.0.255", null, null, "deny");
    /* The same connection above is denied. Tests whether we pick the
     *  longest prefix match
     */
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());

    vr.addRoutingRule(
        null,
        null,
        "10.1.1.2",
        "0.0.0.0",
        null,
        null,
        "10.2.1.0",
        "0.0.0.127",
        null,
        null,
        "permit");
    /* Longer prefix match still */
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("system|rs", action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    vr.addRoutingRule(
        null, null, "10.1.1.2", "0.0.0.0", "t2", null, null, null, null, null, "deny");
    /* Tenant rule is given more priority */
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());

    vr.addRoutingRule(
        null, null, "10.1.1.2", "0.0.0.0", null, "t2|netVirt1", null, null, null, null, "permit");
    /* NetVirt rule is higher priority */
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("system|rs", action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Host rule has higher priority */
    int ip3 = IPv4.toIPv4Address("11.11.11.11");
    vr.addRoutingRule(
        null,
        null,
        "10.1.1.2",
        "0.0.0.0",
        null,
        null,
        "10.2.1.2",
        "0.0.0.0",
        "if2",
        "11.11.11.11",
        "permit");
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals(null, action.getNextRtrName());
    assertEquals(ip3, action.getNextHopIp());
    assertEquals("t1|netVirt2", action.getDstNetVirtName());
    assertEquals(vMac1.longValue(), action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    vr.addRoutingRule(
        null,
        "t1|netVirt2",
        null,
        null,
        null,
        null,
        "10.2.1.2",
        "0.0.0.0",
        "if2",
        "11.11.11.11",
        "permit");
    /* We dont send packet out of the interface it came in */
    ip1 = IPv4.toIPv4Address("10.1.2.2");
    action = vr.getForwardingAction("t1|netVirt2", netVirtA2, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());

    /* A more traditional routing config */
    vr.addRoutingRule(
        null, "t1|netVirt2", null, null, "t2", null, null, null, null, null, "permit");
    ip2 = IPv4.toIPv4Address("10.2.1.4");
    action = vr.getForwardingAction("t1|netVirt2", netVirtA2, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("system|rs", action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Try this out in the system router policy */
    vrs.addRoutingRule("t1", null, null, null, "t2", null, null, null, null, null, "permit");
    action = vrs.getForwardingAction("t1|r1", netVirtA2, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("t2|r2", action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Handle the packet at the ingress of t2|r2 */
    vr2.addRoutingRule(
        "t1", null, null, null, null, "t2|netVirt1", null, null, null, null, "permit");
    action = vr2.getForwardingAction("system|rs", netVirtA2, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals(null, action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals("t2|netVirt1", action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Check that an invalid input interface is handled correctly */
    action = vrs.getForwardingAction("system|rs", netVirtA2, ip1, netVirtB1, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());

    /* Check that the packet is dropped if there isnt any rule found */
    ip1 = IPv4.toIPv4Address("10.2.1.5");
    ip2 = IPv4.toIPv4Address("192.168.0.20");
    action = vr2.getForwardingAction("t2|netVirt1", netVirtB1, ip1, netVirtx, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());

    vr2.addRoutingRule(
        "t2", null, null, null, null, "t1|netVirt1", null, null, null, null, "permit");
    action = vr2.getForwardingAction("t2|netVirt1", netVirtB1, ip1, netVirtx, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());

    vr2.addRoutingRule(
        null,
        null,
        "10.2.1.0",
        "0.0.0.255",
        null,
        null,
        "192.168.0.0",
        "0.0.255.255",
        null,
        null,
        "permit");
    action = vr2.getForwardingAction("t2|netVirt1", netVirtB1, ip1, netVirtx, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("system|rs", action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* A more specific subnet match will take precedence */
    vr2.addRoutingRule(
        null,
        null,
        "10.2.1.0",
        "0.0.0.255",
        null,
        null,
        "192.168.0.0",
        "0.0.0.255",
        null,
        null,
        "drop");
    action = vr2.getForwardingAction("t2|netVirt1", netVirtB1, ip1, netVirtx, ip2);
    assertEquals(RoutingAction.DROP, action.getAction());
  }

  @Test
  public void testGetForwardingActionSilentHost() throws Exception {
    expect(vRtrManager.findSubnetOwner(EasyMock.anyObject(IPV4Subnet.class)))
        .andReturn("t2|r2")
        .times(2);
    expect(vRtrManager.findSubnetOwner(EasyMock.anyObject(IPV4Subnet.class)))
        .andReturn(null)
        .once();
    vRtrManager.addSubnetOwner(
        EasyMock.anyObject(IPV4Subnet.class), EasyMock.anyObject(String.class));
    expectLastCall().times(3);
    vRtrManager.addIfaceIpMap(EasyMock.anyInt(), EasyMock.anyObject(VRouterInterface.class));
    expectLastCall().anyTimes();
    replay(vRtrManager);

    vr.createInterface("if1", "t1|netVirt1", null, true);
    vr.createInterface("if2", "t1|netVirt2", null, true);
    vr.createInterface("ifs", null, "system|rs", true);
    vr.assignInterfaceAddr("if1", "10.1.1.1", "0.0.0.255");
    vr.assignInterfaceAddr("if2", "10.1.2.1", "0.0.0.255");

    VRouterImpl vr2 = new VRouterImpl("r2", "t2", vMac1, vRtrManager);
    vr2.createInterface("if1", "t2|netVirt1", null, true);
    vr2.createInterface("if2", "t2|netVirt2", null, true);
    vr2.createInterface("ifs", null, "system|rs", true);
    vr2.assignInterfaceAddr("if1", "10.2.1.1", "0.0.0.255");

    /* External tenant router */
    VRouterImpl vrx = new VRouterImpl("rx", "tx", vMac1, vRtrManager);
    vrx.createInterface("if1", "tx|netVirtx", null, true);
    vrx.createInterface("ifs", null, "system|rs", true);

    /* System Router */
    VRouterImpl vrs = new VRouterImpl("rs", "system", vMac1, vRtrManager);
    vrs.createInterface("if1", null, "t1|r1", true);
    vrs.createInterface("if2", null, "t2|r2", true);
    vrs.createInterface("ifx", null, "tx|rx", true);

    VNS netVirtA1 = new VNS("t1|netVirt1");
    int ip1, ip2, ip3;
    ip1 = IPv4.toIPv4Address("10.1.1.2");
    ip2 = IPv4.toIPv4Address("10.1.2.2");
    ip3 = IPv4.toIPv4Address("10.2.1.2");
    ForwardingAction action;

    /* Allow host 10.1.1.2 to talk to all other hosts */
    vr.addRoutingRule(
        null,
        null,
        "10.1.1.2",
        "0.0.0.0",
        null,
        null,
        "255.255.255.255",
        "255.255.255.255",
        null,
        null,
        "permit");
    /* Testing for a silent host. The dest device entity is null */
    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, null, ip2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals(null, action.getNextRtrName());
    assertEquals(ip2, action.getNextHopIp());
    assertEquals("t1|netVirt2", action.getDstNetVirtName());
    assertEquals(vMac1.longValue(), action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    action = vr.getForwardingAction("t1|netVirt1", netVirtA1, ip1, null, ip3);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("system|rs", action.getNextRtrName());
    assertEquals(ip3, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Allow all hosts in NetVirtA1 subnet to talk to any other hosts */
    vrs.addRoutingRule(
        null,
        null,
        "10.1.1.0",
        "0.0.0.255",
        null,
        null,
        "0.0.0.0",
        "255.255.255.255",
        null,
        null,
        "permit");
    action = vrs.getForwardingAction("t1|r1", netVirtA1, ip1, null, ip3);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("t2|r2", action.getNextRtrName());
    assertEquals(ip3, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Send a packet to an unknown subnet and see that it is dropped
     * Note that we have set the vRtrManager object to return null for the
     * call to findSubnetOwner after the second time.
     */
    ip3 = IPv4.toIPv4Address("192.168.0.1");
    action = vrs.getForwardingAction("t1|r1", netVirtA1, ip1, null, ip3);
    assertEquals(RoutingAction.DROP, action.getAction());

    verify(vRtrManager);
  }

  /* Test the working of the system router when it is configured to allow all
   * traffic (full mesh)
   */
  @Test
  public void testGetForwardingActionSystemRtr() throws Exception {
    expect(vRtrManager.findSubnetOwner(EasyMock.anyObject(IPV4Subnet.class)))
        .andReturn(null)
        .once();
    expect(vRtrManager.findSubnetOwner(EasyMock.anyObject(IPV4Subnet.class)))
        .andReturn("B|vrB")
        .times(1);
    replay(vRtrManager);

    /* System Router */
    VRouterImpl vrs = new VRouterImpl("rs", "system", vMac1, vRtrManager);
    vrs.createInterface("if1", null, "A|vrA", true);
    vrs.createInterface("if2", null, "B|vrB", true);
    vrs.createInterface("ifexternal", null, "external|vrX", true);

    VNS netVirtA1 = new VNS("A|netVirtA1");
    int ipA1, ipB1, ipX;
    ipA1 = IPv4.toIPv4Address("10.1.1.2");
    ipB1 = IPv4.toIPv4Address("10.1.2.2");
    ipX = IPv4.toIPv4Address("8.8.8.8");
    ForwardingAction action;

    /* Allow all communication */
    vrs.addRoutingRule(
        null,
        null,
        "10.0.0.0",
        "255.255.255.255",
        null,
        null,
        "10.0.0.0",
        "255.255.255.255",
        null,
        null,
        "permit");
    /* Testing for a silent host. The dest device entity is null */
    action = vrs.getForwardingAction("A|vrA", netVirtA1, ipA1, null, ipX);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("external|vrX", action.getNextRtrName());
    assertEquals(ipX, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Inter tenant communication is allowed */
    action = vrs.getForwardingAction("A|vrA", netVirtA1, ipA1, null, ipB1);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("B|vrB", action.getNextRtrName());
    assertEquals(ipB1, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    /* Communication from external tenant is correctly routed */
    VNS netVirtX = new VNS("external|netVirtX");
    action = vrs.getForwardingAction("external|vrX", netVirtX, ipX, netVirtA1, ipA1);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("A|vrA", action.getNextRtrName());
    assertEquals(ipA1, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());

    verify(vRtrManager);
  }

  /* Test the working of the system router when it is configured to allow only
   * external NetVirt traffic
   */
  @Test
  public void testGetForwardingActionSystemRtr2() throws Exception {
    /* System Router */
    VRouterImpl vrs = new VRouterImpl("rs", "system", vMac1, vRtrManager);
    vrs.createInterface("if1", null, "A|vrA", true);
    vrs.createInterface("if2", null, "B|vrB", true);
    vrs.createInterface("ifexternal", null, "external|vrX", true);

    VNS netVirtA1 = new VNS("A|netVirtA1");
    int ipA1, ipB1, ipX;
    ipA1 = IPv4.toIPv4Address("10.1.1.2");
    ipB1 = IPv4.toIPv4Address("10.1.2.2");
    ipX = IPv4.toIPv4Address("8.8.8.8");
    ForwardingAction action;

    /* any to any go to external router */
    vrs.addRoutingRule(
        null,
        null,
        "10.0.0.0",
        "255.255.255.255",
        null,
        null,
        "10.0.0.0",
        "255.255.255.255",
        "ifexternal",
        null,
        "permit");
    /* External to any allow */
    vrs.addRoutingRule(
        "external",
        null,
        null,
        null,
        null,
        null,
        "10.0.0.0",
        "255.255.255.255",
        null,
        null,
        "permit");

    /* Testing for a silent host. The dest device entity is null */
    action = vrs.getForwardingAction("A|vrA", netVirtA1, ipA1, null, ipX);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("external|vrX", action.getNextRtrName());
    assertEquals(ipX, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());

    /* Inter tenant communication is sent to external router as well */
    action = vrs.getForwardingAction("A|vrA", netVirtA1, ipA1, null, ipB1);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("external|vrX", action.getNextRtrName());
    assertEquals(ipB1, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());

    /* Communication from external tenant is correctly routed */
    VNS netVirtX = new VNS("external|netVirtX");
    action = vrs.getForwardingAction("external|vrX", netVirtX, ipX, netVirtA1, ipA1);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals("A|vrA", action.getNextRtrName());
    assertEquals(ipA1, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals(0, action.getNewSrcMac());
    assertEquals(null, action.getNextHopGatewayPool());
    assertEquals(null, action.getNextHopGatewayPoolRouter());
  }

  /* Test the working of the router when it is configured with a rule having
   * a next hop IP
   */
  @Test
  public void testGetForwardingActionNHIp() throws Exception {
    vr.createInterface("if1", "A|netVirtA1", null, true);
    vr.createInterface("if2", "A|netVirtA2", null, true);
    vr.createInterface("ifs", null, "system|rs", true);
    vr.assignInterfaceAddr("if1", "10.1.1.1", "0.0.0.255");
    vr.assignInterfaceAddr("if2", "10.1.2.1", "0.0.0.255");

    String ipA1str, ipA2str, ipnhstr, ipXstr;
    ipA1str = "10.1.1.2";
    ipA2str = "10.1.2.12";
    ipnhstr = "10.1.2.2";
    ipXstr = "192.168.1.1";
    int ipA1, ipA2, ipnh, ipX;
    ipA1 = IPv4.toIPv4Address(ipA1str);
    ipA2 = IPv4.toIPv4Address(ipA2str);
    ipnh = IPv4.toIPv4Address(ipnhstr);
    ipX = IPv4.toIPv4Address(ipXstr);

    ForwardingAction action;
    VNS netVirtA1 = new VNS("A|netVirtA1");
    VNS netVirtA2 = new VNS("A|netVirtA2");
    VNS netVirtX = new VNS("X|netVirtX");

    /* Tenant A to any send to next hop ip */
    vr.addRoutingRule(
        "A", null, null, null, null, null, "10.0.0.0", "255.255.255.255", null, ipnhstr, "permit");
    /* Next hop is in the same NetVirt as the dest NetVirt */
    action = vr.getForwardingAction("A|netVirtA1", netVirtA1, ipA1, netVirtA2, ipA2);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals(null, action.getNextRtrName());
    assertEquals(ipnh, action.getNextHopIp());
    assertEquals("A|netVirtA2", action.getDstNetVirtName());
    assertEquals(vMac1.longValue(), action.getNewSrcMac());

    /* Next hop is in a different NetVirt as the dest NetVirt */
    action = vr.getForwardingAction("A|netVirtA1", netVirtA1, ipA1, netVirtX, ipX);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals(null, action.getNextRtrName());
    assertEquals(ipnh, action.getNextHopIp());
    assertEquals("A|netVirtA2", action.getDstNetVirtName());
    assertEquals(vMac1.longValue(), action.getNewSrcMac());

    /* The next hop is not connected to any subnet of the router */
    /* netVirtA1 to any send to ipX */
    vr.addRoutingRule(
        null,
        "A|netVirtA1",
        null,
        null,
        null,
        null,
        "10.0.0.0",
        "255.255.255.255",
        null,
        ipXstr,
        "permit");
    action = vr.getForwardingAction("A|netVirtA1", netVirtA1, ipA1, netVirtA2, ipA2);
    assertEquals(RoutingAction.DROP, action.getAction());
    assertEquals(null, action.getNextRtrName());
    assertEquals(0, action.getNextHopIp());
    assertEquals(null, action.getDstNetVirtName());
    assertEquals((long) 0, action.getNewSrcMac());
  }

  @Test
  public void testGetForwardingActionNextHopGatewayPool() {
    /* External router belonging to an external tenant */
    VRouterImpl vrx = new VRouterImpl("rx", "tx", vMac1, vRtrManager);
    vrx.createInterface("if-external", "tx|netVirtx", null, true);
    vrx.createInterface("if-system", null, "rs", true);

    /* NetVirt attached to the tenant "t1" */
    VNS netVirtA1 = new VNS("t1|netVirt1");

    /* Source IP of the packet */
    int ip1 = IPv4.toIPv4Address("10.0.0.1");

    /* NetVirt attached to the external tenant */
    VNS netVirtX1 = new VNS("tx|netVirtx");

    /* Destination IP of the packet */
    int ipx = IPv4.toIPv4Address("8.8.8.8");

    /*
     * Setup a routing rule to permit traffic from
     * tenant|netVirt = "t1"|"netVirt1" to tenant|netVirt = "tx|netVirtx" and send it to
     * the gateway pool "test-gateway-pool"
     */
    vrx.addRoutingRule(
        "t1",
        "t1|netVirt1",
        null,
        null,
        "tx",
        "tx|netVirtx",
        null,
        null,
        "if-external",
        null,
        "permit",
        "test-gateway-pool");
    /*
     * Now, invoke getForwardingAction on the virtual router object
     * corresponding to the external virtual router to determine
     * the forwarding action for traffic from tenant("t1")|netVirt("netVirt1")
     * to the tenant("tx")|netVirt("netVirtx")
     */
    ForwardingAction action = vrx.getForwardingAction("rs", netVirtA1, ip1, netVirtX1, ipx);
    assertEquals(RoutingAction.FORWARD, action.getAction());
    assertEquals(null, action.getNextRtrName());
    assertEquals(0, action.getNextHopIp());
    assertEquals("tx|netVirtx", action.getDstNetVirtName());
    assertEquals((long) 0, action.getNewSrcMac());
    assertEquals("test-gateway-pool", action.getNextHopGatewayPool());
    assertEquals(vrx, action.getNextHopGatewayPoolRouter());
  }

  @Test
  public void testGetVMac() throws Exception {
    vr.createInterface("if1", "t1|netVirt1", null, true);
    vr.createInterface("if2", "t1|netVirt2", null, true);
    vr.createInterface("if3", "t1|netVirt3", null, false);
    vr.createInterface("ifs", null, "system|rs", true);
    vr.assignInterfaceAddr("if1", "10.1.1.1", "255.255.255.0");
    vr.assignInterfaceAddr("if1", "10.2.1.1", "255.255.255.0");
    vr.assignInterfaceAddr("if2", "10.1.2.1", "255.255.255.0");
    vr.assignInterfaceAddr("if3", "10.1.3.1", "255.255.255.0");
    vr.assignInterfaceAddr("ifs", "192.168.1.1", "255.255.255.0");

    int ip = IPv4.toIPv4Address("10.1.1.1");
    long vMac = vr.getVMac("t1|netVirt1", ip);
    long expectedVMac = Ethernet.toLong(Ethernet.toMACAddress("00:11:22:33:44:55"));
    assertEquals(expectedVMac, vMac);

    ip = IPv4.toIPv4Address("10.2.1.1");
    vMac = vr.getVMac("t1|netVirt1", ip);
    assertEquals(expectedVMac, vMac);

    ip = IPv4.toIPv4Address("10.1.3.1");
    vMac = vr.getVMac("t1|netVirt3", ip);
    assertEquals(expectedVMac, vMac);

    ip = IPv4.toIPv4Address("192.168.1.1");
    vMac = vr.getVMac("system|rs", ip);
    assertEquals(expectedVMac, vMac);

    ip = IPv4.toIPv4Address("10.2.1.1");
    vMac = vr.getVMac("netVirt1", ip);
    assertEquals(0, vMac);

    ip = IPv4.toIPv4Address("10.2.1.2");
    vMac = vr.getVMac("t1|netVirt1", ip);
    assertEquals(0, vMac);
  }

  @Test
  public void testGetRtrIp() throws Exception {
    String if1ip1str = "10.1.1.1";
    String if1ip2str = "10.2.1.1";
    String if2ipstr = "10.1.2.1";
    String if3ipstr = "10.1.3.1";
    String ifsipstr = "192.168.1.1";
    int if1ip1 = IPv4.toIPv4Address(if1ip1str);
    int if1ip2 = IPv4.toIPv4Address(if1ip2str);
    vr.createInterface("if1", "t1|netVirt1", null, true);
    vr.createInterface("if2", "t1|netVirt2", null, true);
    vr.createInterface("if3", "t1|netVirt3", null, false);
    vr.createInterface("ifs", null, "system|rs", true);
    vr.assignInterfaceAddr("if1", if1ip1str, "0.0.0.255");
    vr.assignInterfaceAddr("if1", if1ip2str, "0.0.0.255");
    vr.assignInterfaceAddr("if2", if2ipstr, "0.0.0.255");
    vr.assignInterfaceAddr("if3", if3ipstr, "0.0.0.255");
    vr.assignInterfaceAddr("ifs", ifsipstr, "0.0.0.255");

    int ip, retIp;
    /* The IP belongs to the first subnet of if1 */
    ip = IPv4.toIPv4Address("10.1.1.3");
    retIp = vr.getRtrIp("t1|netVirt1", ip);
    assertEquals(if1ip1, retIp);

    /* The IP belongs to the second subnet of if1 */
    ip = IPv4.toIPv4Address("10.2.1.3");
    retIp = vr.getRtrIp("t1|netVirt1", ip);
    assertEquals(if1ip2, retIp);

    /* The IP does not belong to any subnet of the router */
    ip = IPv4.toIPv4Address("10.10.2.3");
    retIp = vr.getRtrIp("t1|netVirt1", ip);
    assertEquals(0, retIp);

    /* The NetVirt is not attached to the router */
    ip = IPv4.toIPv4Address("10.1.1.3");
    retIp = vr.getRtrIp("t1|netVirtX", ip);
    assertEquals(0, retIp);
  }

  /*
   * Note: The following tests on the gateway pool/node related APIs in
   * VirutalRouterImpl class ensure only that the IGatewayPool API usage is
   * correct. It does not cover in detail the test cases for the IGatewayPool
   * APIs. Please refer GatewayPoolTest.java for detailed tests on the
   * IGatewayPool interface.
   */
  @Test
  public void testCreateGatewayPool() {
    String gatewayPoolName1 = "testGatewayPool1";
    vr.createGatewayPool(gatewayPoolName1);
    GatewayPoolImpl gatewayPool1 = vr.getGatewayPool(gatewayPoolName1);
    assertNotNull(gatewayPool1);
    assertEquals("testGatewayPool1", gatewayPool1.getName());

    String gatewayPoolName2 = "testGatewayPool2";
    vr.createGatewayPool(gatewayPoolName2);
    GatewayPoolImpl gatewayPool2 = vr.getGatewayPool(gatewayPoolName2);
    assertNotNull(gatewayPool2);
    assertEquals("testGatewayPool2", gatewayPool2.getName());
  }

  @Test
  public void testAddGatewayNode() {
    String gatewayPoolName = "testGatewayPool";
    vr.createGatewayPool(gatewayPoolName);
    vr.addGatewayPoolNode(gatewayPoolName, "10.0.0.1");
    vr.addGatewayPoolNode(gatewayPoolName, "10.0.0.2");

    GatewayPoolImpl gatewayPool = vr.getGatewayPool(gatewayPoolName);
    assertNotNull(gatewayPool);
    assertEquals("testGatewayPool", gatewayPool.getName());

    Map<String, GatewayNode> nodes = gatewayPool.getGatewayNodes();
    assertNotNull(nodes);
    assertEquals(2, nodes.size());
    GatewayNode node1 = nodes.get("10.0.0.1");
    assertEquals("10.0.0.1", IPv4.fromIPv4Address(node1.getIp()));
    GatewayNode node2 = nodes.get("10.0.0.2");
    assertEquals("10.0.0.2", IPv4.fromIPv4Address(node2.getIp()));
  }

  @Test
  public void testAddGatewayNodeInvalidPool() throws Exception {
    try {
      vr.addGatewayPoolNode("nonExistentGatewayPool", "10.0.0.1");
      fail();
    } catch (IllegalArgumentException e) {
      assertEquals(IllegalArgumentException.class, e.getClass());
    }
  }

  @Test
  public void getOptimalGatewayNodeIPInvalidPool() throws Exception {
    try {
      vr.getOptimalGatewayNodeInfo("nonExistentGatewayPool", null, (short) 1);
      fail();
    } catch (IllegalArgumentException e) {
      assertEquals(IllegalArgumentException.class, e.getClass());
    }
  }
}