# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB)
# Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved.  See COPYING file

import unittest
import errno

from pyverbs.pyverbs_error import PyverbsError, PyverbsRDMAError
from pyverbs.addr import GlobalRoute, AHAttr, AH
from tests.base import PyverbsAPITestCase
import pyverbs.enums as e
from pyverbs.pd import PD
import tests.utils as u


class AHTest(PyverbsAPITestCase):
    """
    Test various functionalities of the AH class.
    """
    def test_create_ah(self):
        """
        Test ibv_create_ah.
        """
        done = 0
        for ctx, attr, attr_ex in self.devices:
            pd = PD(ctx)
            for port_num in range(1, 1 + attr.phys_port_cnt):
                state = ctx.query_port(port_num).state
                if state != e.IBV_PORT_ACTIVE and state != e.IBV_PORT_INIT:
                    continue
                gr = u.get_global_route(ctx, port_num=port_num)
                ah_attr = AHAttr(gr=gr, is_global=1, port_num=port_num)
                try:
                    with AH(pd, attr=ah_attr):
                        done += 1
                except PyverbsRDMAError as ex:
                    if ex.error_code == errno.EOPNOTSUPP:
                        raise unittest.SkipTest('Create AH is not supported')
                    raise ex
        if done == 0:
            raise unittest.SkipTest('No port is up, can\'t create AH')
    # TODO: Test ibv_create_ah_from_wc once we have traffic

    def test_create_ah_roce(self):
        """
        Verify that AH can't be created without GRH in RoCE
        """
        done = 0
        for ctx, attr, attr_ex in self.devices:
            pd = PD(ctx)
            for port_num in range(1, 1 + attr.phys_port_cnt):
                port_attr = ctx.query_port(port_num)
                if port_attr.state != e.IBV_PORT_ACTIVE and \
                   port_attr.state != e.IBV_PORT_INIT:
                    continue
                if port_attr.link_layer != e.IBV_LINK_LAYER_ETHERNET:
                    raise unittest.SkipTest('RoCE tests are only supported on Ethernet link layer')
                ah_attr = AHAttr(is_global=0, port_num=port_num)
                try:
                    ah = AH(pd, attr=ah_attr)
                except PyverbsRDMAError as ex:
                    if ex.error_code == errno.EOPNOTSUPP:
                        raise unittest.SkipTest('Create AH is not supported')
                    assert 'Failed to create AH' in str(ex)
                    done +=1
                else:
                    raise PyverbsError('Created a non-global AH on RoCE')
        if done == 0:
            raise unittest.SkipTest('No port is up, can\'t create AH')

    def test_destroy_ah(self):
        """
        Test ibv_destroy_ah.
        """
        done = 0
        for ctx, attr, attr_ex in self.devices:
            pd = PD(ctx)
            for port_num in range(1, 1 + attr.phys_port_cnt):
                state = ctx.query_port(port_num).state
                if state != e.IBV_PORT_ACTIVE and state != e.IBV_PORT_INIT:
                    continue
                gr = u.get_global_route(ctx)
                ah_attr = AHAttr(gr=gr, is_global=1, port_num=port_num)
                try:
                    with AH(pd, attr=ah_attr) as ah:
                        ah.close()
                        done += 1
                except PyverbsRDMAError as ex:
                    if ex.error_code == errno.EOPNOTSUPP:
                        raise unittest.SkipTest('Create AH is not supported')
                    raise ex
        if done == 0:
            raise unittest.SkipTest('No port is up, can\'t create AH')
