# Neutron Cisco plugin
# ---------------------------

# Save trace setting
CISCO_XTRACE=$(set +o | grep xtrace)
set +o xtrace

# Name of cisco router plugin
Q_CISCO_ROUTER_PLUGIN=${Q_CISCO_ROUTER_PLUGIN:-}

# Indicate if a VSM instance should be created
Q_CISCO_PLUGIN_DEVSTACK_VSM=${Q_CISCO_PLUGIN_DEVSTACK_VSM:-True}

# Specify the VSM image file
Q_CISCO_PLUGIN_VSM_ISO_IMAGE=${Q_CISCO_PLUGIN_VSM_ISO_IMAGE:-}

# Scecify the VSM parameters
Q_CISCO_PLUGIN_VSM_IP=${Q_CISCO_PLUGIN_VSM_IP:-192.168.168.2}

# Specify the VSM username
Q_CISCO_PLUGIN_VSM_USERNAME=${Q_CISCO_PLUGIN_VSM_USERNAME:-admin}

# Specify the VSM passward for above username
Q_CISCO_PLUGIN_VSM_PASSWORD=${Q_CISCO_PLUGIN_VSM_PASSWORD:-Sfish123}

# Specify the uVEM image/module
Q_CISCO_PLUGIN_UVEM_DEB_IMAGE=${Q_CISCO_PLUGIN_UVEM_DEB_IMAGE:-}

# Specify the uVEM integration bridge name
Q_CISCO_PLUGIN_INTEGRATION_BRIDGE=${Q_CISCO_PLUGIN_INTEGRATION_BRIDGE:-br-int}

# Specify the host management interface required by uVEM
Q_CISCO_PLUGIN_HOST_MGMT_INTF=${Q_CISCO_PLUGIN_HOST_MGMT_INTF:-eth0}

# Specify the upstream (public) interface required by uVEM
Q_CISCO_PLUGIN_UPSTREAM_INTF=${Q_CISCO_PLUGIN_UPSTREAM_INTF:-}

# Specify if tunneling is enabled
Q_CISCO_PLUGIN_ENABLE_TUNNELING=${Q_CISCO_PLUGIN_ENABLE_TUNNELING:-True}

# Specify the VXLAN range
Q_CISCO_PLUGIN_VXLAN_ID_RANGES=${Q_CISCO_PLUGIN_VXLAN_ID_RANGES:-5000:10000}

# Specify the VLAN range
Q_CISCO_PLUGIN_VLAN_RANGES=${Q_CISCO_PLUGIN_VLAN_RANGES:-vlan:1:4094}

# Specify if VSM should be restarted
Q_CISCO_PLUGIN_RESTART_VSM=${Q_CISCO_PLUGIN_RESTART_VSM:-no}

# Specify ncclient package information
NCCLIENT_DIR=$DEST/ncclient
NCCLIENT_VERSION=${NCCLIENT_VERSION:-0.3.1}
NCCLIENT_BRANCH=${NCCLIENT_BRANCH:-master}

# This routine put a prefix on an existing function name
function _prefix_function {
    declare -F $1 > /dev/null || die "$1 doesn't exist"
    eval "$(echo "${2}_${1}()"; declare -f ${1} | tail -n +2)"
}

function _has_cisco_router_plugin {
    if [[ "$Q_CISCO_ROUTER_PLUGIN" != "" ]]; then
        return 0
    fi
    return 1
}
# Prefix openvswitch plugin routines with "ovs" in order to differentiate from
# cisco plugin routines. This means, ovs plugin routines will coexist with cisco
# plugin routines in this script.
source $TOP_DIR/lib/neutron_plugins/openvswitch
#_prefix_function net_neutron_plugin_configure_plugin_agent ovs
#_prefix_function net_neutron_plugin_configure_service ovs

# Check the version of the installed ncclient package
function check_ncclient_version {
python << EOF
version = '$NCCLIENT_VERSION'
import sys
try:
    import pkg_resources
    import ncclient
    module_version = pkg_resources.get_distribution('ncclient').version
    if version != module_version:
        sys.exit(1)
except:
    sys.exit(1)
EOF
}

# Install the ncclient package
function install_ncclient {
    sudo -E pip install ncclient
}

# Check if the required version of ncclient has been installed
function is_ncclient_installed {
    # Check if the Cisco ncclient repository exists
    if [[ ! -d $NCCLIENT_DIR ]]; then
        return 1
    fi
    # Check if the ncclient is installed with the right version
    if ! check_ncclient_version; then
        return 1
    fi

    return 0
}

function _configure_cisco_router_plugin {
    # Install a known compatible ncclient from the Cisco repository if necessary
    if ! is_ncclient_installed; then
        install_ncclient
    fi
}

# Return the current VSM state
function _get_vsm_state {
    sudo virsh list --all | awk '(NR > 2) {if ($2 == "DEVSTACK_VSM") {$1="";$2="";print;}}'
}

# This routine keeps contacting the VSM in 10s interval until it responds
function _wait_for_vsm_to_comeup {
    echo "Wait for the VSM to come up; This may take a while"
    sh -c "while ! http_proxy= curl -s -m 5 http://$2:$3@$1; do sleep 10; done" &> /dev/null
}

# Check if the VSM console is on
function _is_vsm_console_on {
    local vnc_no=$(sudo virsh vncdisplay DEVSTACK_VSM 2> /dev/null)
    local running=$(ps --no-headers -o cmd -C krdc | sed -n 's/krdc localhost\(:\d*\)/\1/p' | awk -v vno=$vnc_no '$1 == vno {print}')
    if [[ -n $running ]]; then
        return 0
    else
        return 1
    fi
}

# Open the VSM console
function _open_vsm_console {
    vnc_no=$(sudo virsh vncdisplay DEVSTACK_VSM)
    krdc localhost$vnc_no&
    # remove the process from the current job so that it's not killed at the
    # completion of stack.sh
    disown %%
}

# Close the VSM console
function _close_vsm_console {
    local vnc_no=$(sudo virsh vncdisplay DEVSTACK_VSM 2> /dev/null)
    local console_pid=$(ps --no-headers -o pid,cmd -C krdc | sed -n 's/\(\d*\) krdc localhost\(:\d*\)/\1 \2/p' | awk -v vno=$vnc_no '$2 == vno {print $1}')
    if [[ -n $console_pid ]]; then
        kill $console_pid
    fi
}

function _repackage_iso_with_ovfenv {
    local vsm_tap_ip=$1
    local vsm_ip=$2
    local vsm_iso_image=$3
    local ovf_env_file=$DATA_DIR/neutron/cisco/ovf-env.xml

    if [[ -f $ovf_env_file ]]; then
        rm $ovf_env_file
    fi
    cat > $ovf_env_file <<-EOF
        <?xml version="1.0" encoding="UTF-8"?>
        <Environment
            xmlns="http://schemas.dmtf.org/ovf/environment/1"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
            xmlns:ve="http://www.vmware.com/schema/ovfenv"
            oe:id="">
            <PlatformSection>
                <Kind>KVM</Kind>
                <Locale>en</Locale>
            </PlatformSection>
            <PropertySection>
            <Property oe:key="DomainId" oe:value="1"/>
            <Property oe:key="EnableTelnet" oe:value="True"/>
            <Property oe:key="GatewayIpV4" oe:value="$vsm_tap_ip"/>
            <Property oe:key="HostName" oe:value="OSVSM"/>
            <Property oe:key="ManagementIpV4" oe:value="$vsm_ip"/>
            <Property oe:key="ManagementIpV4Subnet" oe:value="255.255.255.0"/>
            <Property oe:key="OvfDeployment" oe:value="installer"/>
            <Property oe:key="SvsMode" oe:value="L3"/>
            <Property oe:key="Password" oe:value="$Q_CISCO_PLUGIN_VSM_PASSWORD"/>
            <Property oe:key="HARole" oe:value="standalone"/>
            </PropertySection> \n'
        </Environment> \n'
EOF
    local mntdir=$(mktemp -d)
    local ddir=$(mktemp -d)
    sudo /bin/mount -o loop -t iso9660 $Q_CISCO_PLUGIN_VSM_ISO_IMAGE $mntdir
    cp -r $mntdir/* $ddir
    sudo /bin/umount $mntdir
    cp $ovf_env_file $ddir
    if [[ -f $ddir/isolinux/isolinux.bin ]]; then
        (cd $ddir; sudo /usr/bin/mkisofs -uid 0 -gid 0 -J -R -A Cisco_Nexus_1000V_VSM -b isolinux/isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table -o $vsm_iso_image .)
    else
        (cd $ddir; sudo /usr/bin/mkisofs -uid 0 -gid 0 -J -R -A Cisco_Nexus_1000V_VSM -b boot/grub/iso9660_stage1_5 -no-emul-boot -boot-load-size 4 -boot-info-table -o $vsm_iso_image .)
    fi
}

function _get_vsm_net {
    first=$(echo $Q_CISCO_PLUGIN_VSM_IP | sed -n 's/^\([0-9]\{1,3\}\)\.\([0-9]\{1,3\}\)\.\([0-9]\{1,3\}\)\.[0-9]\{1,3\}$/\1/p')
    second=$(echo $Q_CISCO_PLUGIN_VSM_IP | sed -n 's/^\([0-9]\{1,3\}\)\.\([0-9]\{1,3\}\)\.\([0-9]\{1,3\}\)\.[0-9]\{1,3\}$/\2/p')
    third=$(echo $Q_CISCO_PLUGIN_VSM_IP | sed -n 's/^\([0-9]\{1,3\}\)\.\([0-9]\{1,3\}\)\.\([0-9]\{1,3\}\)\.[0-9]\{1,3\}$/\3/p')
    if [[ -z $first || -z $second || -z $third ]]; then
        die $LINENO "Incorrect network address: $Q_CISCO_PLUGIN_VSM_IP"
    fi

    declare -i f=$first
    declare -i s=$second
    declare -i t=$third
    if (( $f > 255 || $s > 255 || $t > 255 )); then
        die $LINENO "Incorrect network address: $Q_CISCO_PLUGIN_VSM_IP"
    fi
    echo $first.$second.$third
}

# This routine retrieves the domain id and the primary mac address from the VSM
function _get_vsm_info {
    # Node: no code with output should be added here. The caller depends on the
    # output from the below expect output
    vsm_ip_addr=$1 user=$2 passwd=$3 expect -c '
        spawn /usr/bin/telnet $env(vsm_ip_addr)
        set timeout 240
        expect {
            -re "Trying.*Connected.*Escape.*Nexus .*login: " {
                send "$env(user)\n"
                exp_continue
                #look for the password prompt
            }

            "*?assword:*" {
                send "$env(passwd)\n"
            }
        }
        expect {
            -re ".*# " {
                send "show interface control 0\n"
                expect -indices -re ".*# "
                puts [string range $expect_out(buffer) \
                           0 [expr $expect_out(0,start) - 1]]
                send "show svs domain\n"
                expect -indices -re ".*# "
                puts [string range $expect_out(buffer) \
                           0 [expr $expect_out(0,start) - 1]]
            }
        }' | sed -n -e 's/  Hardware: Ethernet, address: \(..\)\(..\)\.\(..\)\(..\)\.\(..\)\(..\).*/\1:\2:\3:\4:\5:\6/p' -e 's/  Domain id: *\(\d*\)/\1/p'
    # Node: no code with output should be added here. The caller depends on the
    # output from the above expect output
}

function _configure_vsm {
    install_package expect
    vsm_ip_addr=$1 user=$2 passwd=$3 expect -c '
        spawn /usr/bin/telnet $env(vsm_ip_addr)
        expect {
    -re "Trying.*Connected.*Escape.*Nexus .*login: " {
        send "$env(user)\n"
        exp_continue
        #look for the password prompt
    }

    "*?assword:*" {
        send "$env(passwd)\n"
    }
        }
        expect -re ".*# "

        send "config te\n"
        expect -re ".*# "

        send "feature http-server\n"
        expect -re ".*# "

        send "feature network-segmentation-manager\n"
        expect -re ".*# "

        send "feature segmentation\n"
        expect -re ".*# "

        send "port-profile test-profile\n"
        expect -re ".*# "

        send "no shut\n"
        expect -re ".*# "

        send "state enabled\n"
        expect -re ".*# "

        send "publish port-profile\n"
        expect -re ".*# "

        send "exit\n"
        expect -re ".*# "

        send "port-profile dhcp_pp\n"
        expect -re ".*# "

        send "no shut\n"
        expect -re ".*# "

        send "state enabled\n"
        expect -re ".*# "

        send "publish port-profile\n"
        expect -re ".*# "

        send "end\n"
        expect -re ".*# "

        send "exit\n"
    '
}

function send_vsm_arp {
    set +o xtrace
    sudo sysctl -w net.ipv4.ip_nonlocal_bind=1
    while true; do
        sudo arping -U -A -c 3 -q -I $Q_CISCO_PLUGIN_HOST_MGMT_INTF $Q_CISCO_PLUGIN_VSM_IP
        sleep 5
    done
}

# This routine creates a virtual machine that runs VSM
function _create_devstack_vsm {
    local vsm_image_file=$DATA_DIR/neutron/cisco/DEVSTACK_VSM.img
    local vsm_iso_image
    local vsm_xml_file=$DATA_DIR/neutron/cisco/DEVSTACK_VSM.xml
    local vsm_arp_proc=$DATA_DIR/neutron/cisco/vsm_arp_proc
    local vsm_ip
    local vsm_tap_ip
    local vsm_net
    local vsm_state
    local recreate=no
    local config_vsm=False

    # Intall krdc package. krdc is used to connect to the VSM desktop/console
    install_package krdc

    # Ignore all errors for this function (as latest DevStack will abort on any error)
    set +o errexit

    if [[ -z "$Q_CISCO_PLUGIN_VSM_ISO_IMAGE" ]]; then
        die $LINENO "Please specify your VSM iso image in the localrc/local.conf file!"
    fi
    if [[ ! -f "$Q_CISCO_PLUGIN_VSM_ISO_IMAGE" ]]; then
        die $LINENO "Can't find the VSM iso image file $Q_CISCO_PLUGIN_VSM_ISO_IMAGE!"
    fi

    vsm_iso_image=$DATA_DIR/neutron/cisco/$(basename $Q_CISCO_PLUGIN_VSM_ISO_IMAGE)

    if [[ ! -d $DATA_DIR/neutron/cisco ]]; then
        mkdir -p $DATA_DIR/neutron/cisco
    fi

    vsm_net=$(_get_vsm_net)
    declare -i vsm_ip=${Q_CISCO_PLUGIN_VSM_IP/#$vsm_net./}
    local vsm_tap_ip
    if [[ $vsm_ip != 1 ]]; then
        vsm_tap_ip=${vsm_net}.1
    else
        vsm_tap_ip=${vsm_net}.2
    fi

    vsm_state=$(_get_vsm_state)

    # Check if the vsm image is changed
    if [[ -f $vsm_xml_file ]]; then
        matched=$(grep -c -m 1 "<source file='$vsm_iso_image'/>" $vsm_xml_file)
        # The image file is changed; the VM needs to be recreated
        if [[ "$matched" == "0" ]]; then
            recreate=yes
        fi
    else
        recreate=yes
    fi

    # In case of restart or recreate, kill the console and destroy the VM
    if [[ ( "$vsm_state" == "  running" && "$Q_CISCO_PLUGIN_RESTART_VSM" == "yes" ) || "$recreate" == "yes" ]]; then
        _close_vsm_console
        sudo virsh destroy DEVSTACK_VSM
        if [[ "$recreate" == "yes" ]]; then
            sudo virsh undefine DEVSTACK_VSM
            rm -f $vsm_iso_image
            rm -f $vsm_image_file
        fi
    fi

    vsm_state=$(_get_vsm_state)

    # VSM doesn't exist; create one
    if [[ -z $vsm_state ]]; then
        local vsm_uuid=$(uuidgen -t)
        local libvirt_type=$LIBVIRT_TYPE

        config_vsm=True
        # Prepare for the iso image with ovf-env.xml inserted
        if [[ ! -f $vsm_iso_image ]]; then
            _repackage_iso_with_ovfenv $vsm_tap_ip $Q_CISCO_PLUGIN_VSM_IP $vsm_iso_image
        fi

        # Create the VSM disk image file
        if [[ ! -f $vsm_image_file ]]; then
            sudo qemu-img create $vsm_image_file 8G
        fi

        # Determine the libvirt type
        if [[ "$libvirt_type" == "kvm" ]]; then
            sudo modprobe kvm || true
            if [ ! -e /dev/kvm ]; then
                echo "WARNING: Switching to QEMU for VSM"
                libvirt_type=qemu
            fi
        fi

        # Note, mac addresses for NICs are hard-coded. VSM seems to take MAC
        # addresses in certain ranges. Therefore, random-generated MAC addresses
        # may not work.
cat > $vsm_xml_file <<-EOF
    <domain type='$libvirt_type'>
        <name>DEVSTACK_VSM</name>
        <uuid>$vsm_uuid</uuid>
        <memory unit='KiB'>2048000</memory>
        <currentMemory unit='KiB'>1024000</currentMemory>
        <vcpu placement='static'>1</vcpu>
        <os>
            <type arch='x86_64' machine='pc-1.0'>hvm</type>
            <boot dev='cdrom'/>
            <boot dev='hd'/>
        </os>

        <features> <acpi/> <pae/> </features>

        <clock offset='localtime'/>
        <on_poweroff>destroy</on_poweroff>
        <on_reboot>destroy</on_reboot>
        <on_crash>destroy</on_crash>

        <devices>
            <emulator>/usr/bin/qemu-system-x86_64</emulator>
            <disk type='file' device='disk'>
                <driver name='qemu' type='raw'/>
                <source file='$vsm_image_file'/>
                <target dev='hda' bus='ide'/>
                <alias name='ide0-0-0'/>
                <address type='drive' controller='0' bus='0' target='0' unit='0'/>
            </disk>
            <disk type='file' device='cdrom'>
                <driver name='qemu' type='raw'/>
                <source file='$vsm_iso_image'/>
                <target dev='hdb' bus='ide'/>
                <readonly/>
                <alias name='ide0-0-1'/>
                <address type='drive' controller='0' bus='0' target='0' unit='1'/>
            </disk>

            <controller type='usb' index='0'>
                <alias name='usb0'/>
                <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
            </controller>

            <controller type='ide' index='0'>
                <alias name='ide0'/>
                <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
            </controller>

            <interface type='bridge'>
                <mac address='0e:1f:35:ab:45:2e'/>
                <source bridge='ds-vsm-bridge'/>
                <target dev='ds-vsm-vnet0'/>
                <model type='e1000'/>
                <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
            </interface>

            <interface type='bridge'>
                <mac address='0e:1f:35:ab:45:3e'/>
                <source bridge='ds-vsm-bridge'/>
                <target dev='ds-vsm-vnet1'/>
                <model type='e1000'/>
                <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
            </interface>

            <interface type='bridge'>
                <mac address='0e:1f:35:ab:45:4e'/>
                <source bridge='ds-vsm-bridge'/>
                <target dev='ds-vsm-vnet2'/>
                <model type='e1000'/>
                <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
            </interface>

            <serial type='pty'>
                <target port='0'/>
            </serial>
            <console type='pty'>
                <target type='serial' port='0'/>
            </console>
            <input type='mouse' bus='ps2'/>
            <graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0' keymap='en-us'>
                <listen type='address' address='0.0.0.0'/>
            </graphics>

            <video>
                <model type='cirrus' vram='9216' heads='1'/>
                <alias name='video0'/>
                <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
            </video>

            <memballoon model='virtio'>
                <alias name='balloon0'/>
                <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
            </memballoon>

        </devices>
    </domain>
EOF

        sudo virsh define $vsm_xml_file
        vsm_state=$(_get_vsm_state)
    fi

    if [[ "$vsm_state" == "  shut off" ]]; then
        config_vsm=True

        # Create the VSM bridge
        sudo brctl addbr ds-vsm-bridge
        sudo ip link set ds-vsm-bridge up

        # Create a veth pair for communication between the host and the VSM
        sudo ip link add tap-ds-vsm type veth peer name ds-vsm-veth
        sudo ip link set tap-ds-vsm up
        sudo ip link set tap-ds-vsm promisc on
        sudo ip link set ds-vsm-veth up
        sudo ip link set ds-vsm-veth promisc on
        sudo brctl addif ds-vsm-bridge tap-ds-vsm
        sudo ip -4 addr add $vsm_tap_ip/24 dev ds-vsm-veth

        if sudo virsh start DEVSTACK_VSM; then
            _open_vsm_console
        fi
        _wait_for_vsm_to_comeup $Q_CISCO_PLUGIN_VSM_IP $Q_CISCO_PLUGIN_VSM_USERNAME $Q_CISCO_PLUGIN_VSM_PASSWORD

# In multi-host environment, send gratuitous arp to the management
# network so that the compute nodes can reach the VSM
        MULTI_HOST=`trueorfalse False $MULTI_HOST`
        if [[ "$MULTI_HOST" == "True" ]]; then
            local send_arp=True
            if [[ -e $vsm_arp_proc ]]; then
                local vsm_arp_proc_pid=$(cat $vsm_arp_proc | cut -d" " -f1)
                local vsm_ipaddr=$(cat $vsm_arp_proc | cut -d" " -f2)
                local cmd = $(ps --no-headers -p $vsm_arp_proc_pid -o cmd)
                if [[ -n $cmd ]]; then
                    if [[ $vsm_ipaddr != $Q_CISCO_PLUGIN_VSM_IP ]]; then
                        kill $vsm_arp_proc_pid
                    else
                        send_arp=False
                    fi
                fi
            fi
            if [[ $send_arp == "True" ]]; then
                send_vsm_arp&
                disown %%
                echo "$! $Q_CISCO_PLUGIN_VSM_IP" > $vsm_arp_proc
            fi
        fi
    else
        if ! _is_vsm_console_on; then
            _open_vsm_console
        fi
    fi
    if [[ "$config_vsm" == "True" ]]; then
        _configure_vsm $Q_CISCO_PLUGIN_VSM_IP $Q_CISCO_PLUGIN_VSM_USERNAME $Q_CISCO_PLUGIN_VSM_PASSWORD
    fi
    # Turn exit on error, back on
    set -o errexit
}

function write_n1kv_conf {
    local n1kv_cfg_file=$1
    sudo cat > $n1kv_cfg_file <<-EOF
# This is a sample N1KV configurtion file.
# <n1kv.conf> file contains all the configuration parameters for UVEM operation.
# Please find below a brief explanation of these parameters and their meaning.
# Optional Parameters and Default Values of parameters are explicitly stated.
# Note:
# a) Mandatory parameters are needed for proper UVEM operation.
#   N1KV DP/DPA should start even if these are not specified.
#   But there will be functional impact. For eg: in VSM connectivity
# b)For most of the mandatory parameters, you can use 'vemcmd' configuration mode.
#   But to be persistent, please edit this configuration file.

#
#<vsm-connection-params>
#
# TAG: switch-domain
# Description:
# Optional: No
# Default: 1
switch-domain 1

# TAG: l3control-ipaddr
# Description: IP Address of VSM's Control I/F
# Optional: No
# Default: n/a
l3control-ipaddr 1.2.3.4

# TAG: system-primary-mac
# Description: MAC address of VSM's Control I/F
# Optional: No
# Default: n/a
# system-primary-mac -INTF

# TAG: host-mgmt-intf
# Description: Management interface of the Host
# Optional: No (Even if not on N1KV, we need this
#               for Host Identification on VSM).
# Default: n/a
host-mgmt-intf eth1

#
#<system-port-profile-Info>
# Description:  System Port Profiles.
# Optional: Yes (If there are no System Interfaces: Mgmt I/F etc)
#
#Trunk Profile Format
#profile <name> trunk <vlan>
#profile <name> native-vlan <vlan>
#profile <name> mtu <mtu-size>
#
#Access Profile
#profile <name> access <vlan>
#profile <name> mtu <mtu-size>

#<Port-Profile Mapping>
# Description: Port-Profile mapping for all UVEM managed Interfaces.
# Optional: Uplinks: NO. System-Veth: NO.
#         : Non-System Veth: YES. (Assume it will be populated by 'libvirt')
#
# Format:
# phys <port-name> profile  <profile-name>
# virt <port-name> profile  <profile-name>
# TBD: For uplinks UUID also need to be specified.
#phys eth1 profile sys-uplink
#phys eth2 profile uplink2

# <host-uuid>
# Description: Host UUID
# Optional : YES. If not specified UVEM would pick host UUID using 'dmidecode'.
# host-uuid <host-uuid>

# <dvswitch-uuid>
# Description: N1KV DVS UUID. Not to be confused with Open VSwitch UUID
# Optional : YES.
# dvswitch-uuid <sw-uuid>

# TBD
# <log-path>
# Description: Log Directory Path for DP/DPA
# Optional: YES.
# Default:
# Format:
# log-path:/opt/cisco/n1kv/logs

# <uvem-ovs-brname>
#
# Description: Default Open VSwitch Bridge Name
# Optional: YES.
# Default: n1kvdvs
# Format:
# uvem-ovs-brname n1kvdvs
uvem-ovs-brname br-int

EOF
}

function n1k_iniset {
    local file=$1
    local option=$2
    local value=$3
    if ! grep -q "^$option" "$file"; then
        # Add at the end
        echo "option does not exist-add to bottom"
        echo -e "\n$option $value" >>"$file"
    else
        # Replace it
        echo "n1k_iniset:Replace it $option $value $file"
        sed -i "s/^$option.*/$option $value/" "$file"
    fi
}

# Configure/Install the uVEM
function _configure_uvem {
    # Specify uVEM configuration information
    local N1KV_CONF_DIR=/etc/n1kv
    local N1KV_CONF=$N1KV_CONF_DIR/n1kv.conf
    local UVEM_LOCAL_DIR=$TOP_DIR/files/images/cisco

    install_package expect

    # Put config files in ``N1KV_CONF_DIR``
    if [[ ! -d $N1KV_CONF_DIR ]]; then
        sudo mkdir -p $N1KV_CONF_DIR
        sudo chown $STACK_USER $N1KV_CONF_DIR
    fi

    local n1kv_temp_file=`mktemp`
    if [[ ! -f $N1KV_CONF ]]; then
        write_n1kv_conf $n1kv_temp_file
    else
        cp $N1KV_CONF $n1kv_temp_file
    fi

    # install a route to VSM on a compute node
    if ! is_service_enabled q-svc ; then
        local vsm_net=$(_get_vsm_net)
        sudo ip route add ${vsm_net}.0/24 dev $Q_CISCO_PLUGIN_HOST_MGMT_INTF
        if [[ $? != 0 && $? != 2 ]]; then
            die $LINENO "Cannot add route to the VSM"
        fi
    fi

    # Wait for VSM to come up before requesting information from it
    _wait_for_vsm_to_comeup $Q_CISCO_PLUGIN_VSM_IP $Q_CISCO_PLUGIN_VSM_USERNAME $Q_CISCO_PLUGIN_VSM_PASSWORD
    local vsm_info=($(_get_vsm_info $Q_CISCO_PLUGIN_VSM_IP $Q_CISCO_PLUGIN_VSM_USERNAME $Q_CISCO_PLUGIN_VSM_PASSWORD))

    if [[ "${vsm_info[1]}" != "" ]]; then
        n1k_iniset $n1kv_temp_file switch-domain ${vsm_info[1]}
    fi
    if [[ "$Q_CISCO_PLUGIN_VSM_IP" != "" ]]; then
        n1k_iniset $n1kv_temp_file l3control-ipaddr $Q_CISCO_PLUGIN_VSM_IP
    fi
    if [[ "$Q_CISCO_PLUGIN_HOST_MGMT_INTF" != "" ]]; then
        n1k_iniset $n1kv_temp_file host-mgmt-intf $Q_CISCO_PLUGIN_HOST_MGMT_INTF
    fi
    if [[ "$Q_CISCO_PLUGIN_UPSTREAM_INTF" != "" ]]; then
        n1k_iniset $n1kv_temp_file phys "$Q_CISCO_PLUGIN_UPSTREAM_INTF profile sys-uplink"
    # Make sure we add it to br-int as well, and force it up
        sudo ovs-vsctl -- --may-exist add-port br-int $Q_CISCO_PLUGIN_UPSTREAM_INTF
        sudo ifconfig $Q_CISCO_PLUGIN_UPSTREAM_INTF up
    fi
    if [[ "$Q_CISCO_PLUGIN_INTEGRATION_BRIDGE" != "" ]]; then
        n1k_iniset $n1kv_temp_file uvem-ovs-brname $Q_CISCO_PLUGIN_INTEGRATION_BRIDGE
    fi

    sudo cp $n1kv_temp_file $N1KV_CONF
    sudo chmod a+r $N1KV_CONF
    rm $n1kv_temp_file

    #copy the uVEM image
    if [[ -z "$Q_CISCO_PLUGIN_UVEM_DEB_IMAGE" ]]; then
        die $LINENO "Please specify your UVEM image in the localrc/local.conf file!"
    fi
    if [[ ! -f "$Q_CISCO_PLUGIN_UVEM_DEB_IMAGE" ]]; then
        die $LINENO "Can't find the UVEM image file $Q_CISCO_PLUGIN_UVEM_DEB_IMAGE!"
    fi

    local uvem_image=`basename $Q_CISCO_PLUGIN_UVEM_DEB_IMAGE`

    if [[ ! -f $UVEM_LOCAL_DIR/$uvem_image ]]; then
        mkdir -p $UVEM_LOCAL_DIR

        if sudo dpkg -s nexus1000v; then
            sudo dpkg -r nexus1000v
        fi
        if [[ -e $UVEM_LOCAL_DIR/*.deb ]]; then
            rm $UVEM_LOCAL_DIR/*deb
        fi
        cp $Q_CISCO_PLUGIN_UVEM_DEB_IMAGE $UVEM_LOCAL_DIR

        #install the uVEM
        install_package libnl1
        sudo dpkg -i $UVEM_LOCAL_DIR/$uvem_image
    else
        #restart in case of change in the VSM configuration
        sudo /etc/init.d/n1kv restart
    fi
}

# Configure n1kv plugin
function _configure_n1kv_subplugin {
    local cisco_cfg_file=$1

    # if Embedded VSM is deployed, launch the VSM
    if [[ "$Q_CISCO_PLUGIN_DEVSTACK_VSM" == "True" ]]; then
        _create_devstack_vsm
    fi

    iniset $cisco_cfg_file CISCO_N1K default_policy_profile test-profile
    iniset $cisco_cfg_file CISCO_N1K restrict_network_profiles False

    # Configure uVEM on compute nodes
    if is_service_enabled n-cpu; then
        _configure_uvem
    fi

}

function net_neutron_plugin_configure_plugin_agent {
    # Assuming q-agt will be enabled on all the compute nodes
    # uVEM is only configured/installed with q-agt enabled
    _configure_uvem
}

function net_neutron_plugin_configure_service {
    local cisco_cfg_file
    cisco_cfg_file=/$Q_PLUGIN_CONF_FILE
    if _has_n1kv_subplugin; then
        _configure_n1kv_subplugin $cisco_cfg_file
    fi

    if _has_cisco_router_plugin; then
        _configure_cisco_router_plugin
    fi
}
function _has_n1kv_subplugin {
    local subplugin
    for subplugin in ${Q_CISCO_PLUGIN_SUBPLUGINS[@]}; do
        if [[ "$subplugin" == "n1kv" ]]; then
            return 0
        fi
    done
    return 1
}
# Restore xtrace 
$XTRACE 
