#! /bin/bash
# Copyright 2017,2018,2019,2020 Cumulus Networks, Inc.  All rights reserved.
#
# Record network state for cl-support
#
# Note that cl-support expects the below three flags to be commented
#TIMEOUT=120
#DEFAULT
#ONCORE=switchd,lldpd,ptmd,ssd,zebra,bgpd,ospfd,ospf6d,ripd,ripngd,isisd,pimd,ldpd,nhrpd,eigrpd,babeld

module=${0##*/}

funcs=(kernel ifquery sfp sfphex net_use)
jexec=
ifoutfmt=
jsonkey=

noswitchd=0

func_net_use()
{
    exec_cmd lsof.out lsof -nbw
    exec_cmd ss.out ss -anpeomi
    exec_cmd tc.qdisc tc -s qdisc show
    for swp in $(ip -br link show | grep ^swp | awk '{print $1}'); do
        # evpn-mh rx filters (match bum/es-peer, set fwmark)
        exec_cmd tc.filter.ingress tc -s filter show dev $swp ingress
    done
    for bond in $(ip -br link show type bond | awk '{print $1}'); do
        # evpn-mh rx filters (match bum/es-peer, set fwmark)
        exec_cmd tc.filter.ingress tc -s filter show dev $bond ingress
        # evpn-mh tx filter (match evpn-mh fwmark, action drop)
        exec_cmd tc.filter.egress tc -s filter show dev $bond egress
    done
    for vx in $(ip -br link show type vxlan | awk '{print $1}'); do
        # neighmgrd tx filter (match neighmgrd fwmark, action drop)
        exec_cmd tc.filter.egress tc -s filter show dev $vx egress
    done
    exec_cmd netlink.dbg /usr/lib/cumulus/dbg-nl
    cp -a --parents /proc/net/stat $SUP_TOPDIR
    [ -f /proc/net/nf_conntrack ] && cp -a --parents /proc/net/nf_conntrack $SUP_TOPDIR
}

func_kernel()
{
    local i j
    exec_cmd ip.link ip -d -s link
    exec_cmd ip.addr ip addr
    exec_cmd ip.rule ip rule
    exec_cmd ip6.rule ip -6 rule
    exec_cmd ip.route ip route show table all
    exec_cmd ip.neigh ip -d neigh
    exec_cmd ip6.route ip -6 route show table all
    exec_cmd ip6.routecache ip -6 route list cache table all
    exec_cmd ip6.neigh ip -6 -d neigh
    exec_cmd ip.mroute ip -s mroute
    exec_cmd ip6.mroute ip -6 -s mroute
    exec_cmd ip.mroute-all ip -s mroute show table all
    exec_cmd ip6.mroute-all ip -6 -s mroute show table all
    exec_cmd ip.ntable ip ntable show
    exec_cmd ip.namespaces ip netns list
    exec_cmd $jexec ip.nexthop $jexec ip nexthop
    exec_cmd netstat-i netstat -i
    exec_cmd netstat-s netstat -s
    exec_cmd cl-acltool.list /usr/cumulus/bin/cl-acltool -N -L all
    exec_cmd brctl.show brctl show
    exec_cmd stp.show brctl stpshowall
    exec_cmd $jexec mstp.show mstpctl showall $jsonkey
    exec_cmd $jexec bridge.fdb bridge $jexec -s -d fdb show
    exec_cmd $jexec bridge.mdb bridge $jexec -d -s mdb show
    exec_cmd $jexec bridge.link bridge $jexec -d link
    exec_cmd $jexec bridge.vlan $jexec bridge vlan
    exec_cmd vrf.tasks vrf task ls

    for j in $(ls -d -v1 /sys/class/net/*); do
        i=${j##*/}
        [ $i = "bonding_masters" -o -d $j/bridge -o -d $j/bonding ] && continue;
        [[ $i =~ ^(sw[0-9]*p[0-9]+(s[0-3])?$|eth) ]] && {
            exec_cmd ethtool.link ethtool $i &
            exec_cmd ethtool.stats ethtool -S $i &
            exec_cmd ethtool.fec ethtool --show-fec $i &
	    sleep 0.1
        }
        [ $noswitchd -eq 1 ] && break
    done
    wait
}

func_sfp()
{
    local i j
    [ $noswitchd -eq 1 ] && return
    for j in $(ls -v1 /sys/class/net); do
        [ -d $j/bridge -o -d $j/bonding ] && continue;
        i=${j##*/}
        [[ $i =~ ^(sw[0-9]*p[0-9]+(s0)?$) ]] && {
            exec_cmd ethtool.module ethtool -m $i &
	    sleep 0.1
        }
        [ $noswitchd -eq 1 ] && break
    done
    wait
}

func_sfphex()
{
    [ $noswitchd -eq 1 ] && return
    for j in $(ls -v1 /sys/class/net); do
        [ -d $j/bridge -o -d $j/bonding ] && continue;
        i=${j##*/}
        [[ $i =~ ^(sw[0-9]*p[0-9]+(s0)?$) ]] && {
            exec_cmd ethtool.module-hex ethtool -m $i hex on &
	    sleep 0.1
        }
        [ $noswitchd -eq 1 ] && break
    done
    wait
}

func_ifquery()
{
	exec_cmd $jexec ifquery ifquery -a $ifoutfmt
	exec_cmd $jexec ifquery-ra ifquery -ra $ifoutfmt
}

# main
while getopts "c:jl" Option; do
    case $Option in
    c) [ $SUP_VERBOSE -eq 1 ] && # default submods
        echo ${module}: Invoked for "$OPTARG" core dumps 1>&2 ;;
    j) jexec=-j ifoutfmt='-o json' jsonkey=json ;;
    l) echo ${funcs[@]}
       exit 0 ;;
    *) ;;
    esac
done
shift $((OPTIND - 1))

main()
{
    local -r TIMEFORMAT='%2R seconds' tfile=/run/${module}_funcstime$$
    local secs
    if [ $# -ne 0 ]; then # only run specified sub-modules
       [ $SUP_VERBOSE -eq 1 ] && echo ${module}: run only submodules: $@ 1>&$stderr
       funcs=($@)
    fi

    for func in ${funcs[@]}; do
        [ $SUP_VERBOSE -eq 1 ] && echo "$module.$func" 1>&2
        date +"### $module.$func Started at %F-%T.%N"
        { time func_$func 2>&$stderr  ; } 2>$tfile
        read secs < $tfile
        echo "### $module.$func Completed in $secs"
    done
    rm $tfile
}

TIMEFORMAT="Module $module Completed in %2R seconds"
exec 42>&2
stderr=42

{ time main $@ 2>&$stderr ; } 2>&1

exit 0
