// Package lacp contains an integration test for our custom LACP patches.
// It tests relevant behavior that other parts of the Monogon network stack
// rely on, like proper carrier state indications.
package lacp

import (
	"hash/fnv"
	"math"
	"net"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/vishvananda/netlink"
	"golang.org/x/sys/unix"
)

// createVethPair is a helper creating a pair of virtual network interfaces
// acting as a cable (i.e. traffic going in one interface comes back out on
// the other one). Both ends are returned.
func createVethPair(t *testing.T, name string) (*netlink.Veth, *netlink.Veth) {
	t.Helper()
	vethLink := netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{
			Name:    name + "a",
			NetNsID: -1,
			TxQLen:  -1,
		},
		PeerName: name + "b",
	}
	if err := netlink.LinkAdd(&vethLink); err != nil {
		t.Fatalf("while creating veth pair: %v", err)
	}
	vethLinkB, err := netlink.LinkByName(name + "b")
	if err != nil {
		t.Fatalf("while creating veth pair: while getting veth peer: %v", err)
	}

	return &vethLink, vethLinkB.(*netlink.Veth)
}

// setupNetem is a helper for setting up Linux's network emulation queuing
// discipline on a network interface, which can simulate various network
// imperfections like extra latency, reordering or packet loss on packets
// transmitted on the interface specified. As it is internally implemented
// as a queuing discipline it only affects transmitted packets.
func setupNetem(t *testing.T, link netlink.Link, conf netlink.NetemQdiscAttrs) *netlink.Netem {
	t.Helper()
	h := fnv.New32a()
	h.Write([]byte(link.Attrs().Name))
	qdisc := netlink.NewNetem(netlink.QdiscAttrs{
		LinkIndex: link.Attrs().Index,
		Handle:    netlink.MakeHandle(uint16(h.Sum32()%math.MaxUint16), 0),
		Parent:    netlink.HANDLE_ROOT,
	}, conf)
	if err := netlink.QdiscAdd(qdisc); err != nil {
		t.Fatalf("while setting up qdisc netem for %q: %v", link.Attrs().Name, err)
	}
	return qdisc
}

// changeNetem is a helper for reconfiguring an existing netem instance
// on-the-fly with new parameters.
func changeNetem(t *testing.T, qdisc *netlink.Netem, conf netlink.NetemQdiscAttrs) {
	t.Helper()
	changedQd := netlink.NewNetem(qdisc.QdiscAttrs, conf)
	if err := netlink.QdiscChange(changedQd); err != nil {
		t.Fatalf("while changing qdisc netem for link index %v: %v", qdisc.LinkIndex, err)
	}
}

func createBond(t *testing.T, name string, links ...netlink.Link) *netlink.Bond {
	t.Helper()
	bondLink := netlink.NewLinkBond(netlink.LinkAttrs{
		Name:    name,
		NetNsID: -1,
		TxQLen:  -1,
		Flags:   net.FlagUp,
	})
	bondLink.Mode = netlink.BOND_MODE_802_3AD
	bondLink.LacpRate = netlink.BOND_LACP_RATE_FAST
	bondLink.MinLinks = 1
	bondLink.AdSelect = netlink.BOND_AD_SELECT_BANDWIDTH
	if err := netlink.LinkAdd(bondLink); err != nil {
		t.Fatalf("while creating bond: %v", err)
	}
	for _, l := range links {
		if err := netlink.LinkSetBondSlave(l, bondLink); err != nil {
			t.Fatalf("while enslaving link to bond %q: %v", name, err)
		}
	}
	return bondLink
}

// assertRunning is a helper for asserting an interface's IFF_RUNNING state.
func assertRunning(t *testing.T, l netlink.Link, expected bool) {
	t.Helper()
	linkCurrent, err := netlink.LinkByIndex(l.Attrs().Index)
	if err != nil {
		t.Fatalf("while checking if link %q is running: %v", l.Attrs().Name, err)
	}
	is := linkCurrent.Attrs().RawFlags&unix.IFF_RUNNING != 0
	if expected != is {
		t.Errorf("expected interface %q running state to be %v, is %v", l.Attrs().Name, expected, is)
	}
}

func TestLACP(t *testing.T) {
	if os.Getenv("IN_KTEST") != "true" {
		t.Skip("Not in ktest")
	}

	if err := os.WriteFile("/sys/kernel/debug/dynamic_debug/control", []byte("module bonding +p"), 0); err != nil {
		t.Fatal(err)
	}
	// Log dynamic debug to console
	if err := os.WriteFile("/proc/sys/kernel/printk", []byte("8"), 0); err != nil {
		t.Fatal(err)
	}

	link1a, link1b := createVethPair(t, "link1")
	link2a, link2b := createVethPair(t, "link2")

	// Drop all traffic
	l1aq := setupNetem(t, link1a, netlink.NetemQdiscAttrs{Loss: 100.0})
	l1bq := setupNetem(t, link1b, netlink.NetemQdiscAttrs{Loss: 100.0})
	l2aq := setupNetem(t, link2a, netlink.NetemQdiscAttrs{Loss: 100.0})
	l2bq := setupNetem(t, link2b, netlink.NetemQdiscAttrs{Loss: 100.0})

	bondA := createBond(t, "bonda", link1a, link2a)
	bondB := createBond(t, "bondb", link1b, link2b)

	time.Sleep(5 * time.Second)

	// Bonds should not come up with links dropping all traffic
	assertRunning(t, bondA, false)
	assertRunning(t, bondB, false)

	changeNetem(t, l1aq, netlink.NetemQdiscAttrs{Loss: 0.0})
	changeNetem(t, l1bq, netlink.NetemQdiscAttrs{Loss: 0.0})
	t.Log("Enabled L1")

	time.Sleep(5 * time.Second)

	// Bonds should come up with one link working
	assertRunning(t, bondA, true)
	assertRunning(t, bondB, true)

	changeNetem(t, l2aq, netlink.NetemQdiscAttrs{Loss: 0.0})
	changeNetem(t, l2bq, netlink.NetemQdiscAttrs{Loss: 0.0})
	t.Log("Enabled L2")

	time.Sleep(3 * time.Second)

	// Bonds be up with both links
	assertRunning(t, bondA, true)
	assertRunning(t, bondB, true)

	bondAState, err := os.ReadFile("/proc/net/bonding/bonda")
	if err != nil {
		panic(err)
	}
	t.Log(string(bondAState))
	if !strings.Contains(string(bondAState), "Number of ports: 2") {
		t.Errorf("bonda aggregator should contain two ports")
	}
	if !strings.Contains(string(bondAState), "port state: 63") {
		t.Errorf("bonda port state should be 63")
	}
	t.Log("------------")
	bondBState, err := os.ReadFile("/proc/net/bonding/bondb")
	if err != nil {
		panic(err)
	}
	t.Log(string(bondBState))
	if !strings.Contains(string(bondBState), "Number of ports: 2") {
		t.Errorf("bondb aggregator should contain two ports")
	}
	if !strings.Contains(string(bondBState), "port state: 63") {
		t.Errorf("bondb port state should be 63")
	}
	changeNetem(t, l1aq, netlink.NetemQdiscAttrs{Loss: 100.0})
	changeNetem(t, l1bq, netlink.NetemQdiscAttrs{Loss: 100.0})
	changeNetem(t, l2aq, netlink.NetemQdiscAttrs{Loss: 100.0})
	changeNetem(t, l2bq, netlink.NetemQdiscAttrs{Loss: 100.0})
	t.Log("Disabled both links")

	time.Sleep(5 * time.Second)

	// Bonds should be back down
	assertRunning(t, bondA, false)
	assertRunning(t, bondB, false)
}
