#!/bin/bash

if ! grep -qs Aboot /proc/cmdline; then
   exit 0
fi

touch /run/lc-interface-config-$1
exec 9<"/run/lc-interface-config-$1"
flock -x 9

VLAN_ID="42"

log() {
   logger --id=$$ -t lc-interface-config -p INFO "$@"
   echo "$@"
}

get_interface_slot_id() {
   local intf="$1"

   if ! [ -e "/sys/class/net/$intf/device" ]; then
      return
   fi

   local pci_id=$(readlink -f /sys/class/net/$intf/device |
                  sed -n -E 's#/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/0000:06:([0-9a-fA-F]*).*#\1#p')

   if [ -z "$pci_id" ]; then
      return
   fi

   local dev_pci_id=$((16#$pci_id))
   local slot_id=$(($dev_pci_id - 4))

   if [ "$slot_id" -ge 0 ]; then
      echo "$slot_id"
   fi
}

config_lc_interface() {
   local old_intf="$1"
   local slot_id="$2"
   local new_intf="lc$slot_id"

   log "interface to be configured: $new_intf from $old_intf"

   ip link set dev "$old_intf" down
   ip link set dev "$old_intf" name "$new_intf"
   ip link set dev "$new_intf" master eth0
   ip link set dev "$new_intf" up

   local vlan_intf="$new_intf.$VLAN_ID"

   ip link add link "$new_intf" name "$vlan_intf" type vlan id "$VLAN_ID"
   ip link set dev "$vlan_intf" master br1
   ip link set dev "$vlan_intf" up

   ebtables -I FORWARD 1 -p ARP -j ACCEPT -i ma1 -o "$new_intf"
   ebtables -I FORWARD 1 -p ARP -j ACCEPT -i "$new_intf" -o ma1

   log "interface $new_intf ready"
}

do_supervisor_mode() {
   local intf="$1"
   local action="$2"
   slot_id=$(get_interface_slot_id "$intf")
   log "$action interface $intf slot_id=$slot_id"
   case "$action" in
      add)
         if [ -n "$slot_id" ]; then
            config_lc_interface "$intf" "$slot_id"
         fi
         ;;
      move|remove)
         echo "nothing to do"
         ;;
      *)
         exit 1
         ;;
   esac
}

do_linecard_mode() {
   local vlan_intf="eth1-midplane"

   log "setting up $vlan_intf"

   ip link set dev eth0 up
   ip link add link eth0 name "$vlan_intf" type vlan id "$VLAN_ID"
   ip link set dev "$vlan_intf" up
   echo 1 > /proc/sys/net/ipv4/conf/$vlan_intf/route_localnet

   local lc_slot_id=$(sed -n -E 's/.*slot_id=([0-9]*).*/\1/p' /proc/cmdline)

   if [ -z "$lc_slot_id" ]; then
      return
   fi

   log "slot id = $lc_slot_id"
   ip addr add 127.100.$lc_slot_id.1/16 dev "$vlan_intf"

   # XXX: The linecard needs to be the first one to establish the connection with
   # the sup for the inter link to work. This is a temporary discovery method.
   log "attempting supervisor ping"

   # The underlying management port might not be ready, wait for it to be. If we
   # don't, the following ping command may not succeed, resulting in linecards not
   # "discovered" by the sup.
   for i in `seq 20`; do
      operstate=$(cat /sys/class/net/eth0/operstate)
      if [ "$operstate" == "up" ]; then
         break
      fi
      sleep 1
   done

   if ping -c 3 127.100.1.1; then
      log "internal management network configured on $vlan_intf"
   else
      log "failed to reach the suppervisor on $vlan_intf"
   fi
}

sonic_mode=$(sed -n -E 's/.*sonic.mode=([^ ]+).*/\1/p' /proc/cmdline)

case "$sonic_mode" in
   supervisor)
      # In supervisor mode, this script is invoked when a sup GMAC interface shows
      # up. The goal is to rename whatever ethX showed up ($1) to lcY, where Y is
      # the slot id of the linecard (determined from the sysfs path).
      #
      # In addition to that the resulting lcY is added to eth0 and lcY.42 vlan is
      # created and added to br1
      do_supervisor_mode "$1" "$2"
      ;;
   linecard)
      # In linecard mode, this script is invoked to configure the management port.
      # This configuration involves the following actions:
      # - Create vlan 42 on eth0 (eth0.42) & allow it to route local IPs
      # - Assign 127.100.<SLOT_ID>.1/16 to eth0.42
      # - Ping the sup to establish the connectivity
      do_linecard_mode
      ;;
   *)
      echo "Unkown mode: $sonic_mode"
      exit 1
      ;;
esac
