Index: /branches/rel_avx_2_7_2/3rdpartyappliance/centos-i40e/SOURCES/add_link_down_on_close_feature.patch
===================================================================
--- /branches/rel_avx_2_7_2/3rdpartyappliance/centos-i40e/SOURCES/add_link_down_on_close_feature.patch	(nonexistent)
+++ /branches/rel_avx_2_7_2/3rdpartyappliance/centos-i40e/SOURCES/add_link_down_on_close_feature.patch	(working copy)
@@ -0,0 +1,151 @@
+diff -ru0 src/i40e/i40e.h src_patch/i40e/i40e.h
+--- src/i40e/i40e.h	2024-06-26 14:11:08.931694920 +0800
++++ src_patch/i40e/i40e.h	2024-06-27 13:46:45.404140388 +0800
+@@ -123,0 +124,5 @@
++/* link-down-on-close flag support
++ * The choice of bit position is randomly, so feel free to change
++ * it if this bit position is occupied by other
++ * funtionality */
++#define I40E_FLAG_LINK_DOWN_ON_CLOSE_FLAG   BIT(6)
+@@ -442,0 +448,6 @@
++
++/* link-down-on-close flag support
++ * The choice of bit position is randomly, so feel free to change
++ * it if this bit position is occupied by other
++ * funtionality */
++#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED BIT_ULL(48)
+diff -ru0 src/i40e/i40e_adminq_cmd.h src_patch/i40e/i40e_adminq_cmd.h
+--- src/i40e/i40e_adminq_cmd.h	2024-06-26 14:11:08.941694919 +0800
++++ src_patch/i40e/i40e_adminq_cmd.h	2024-06-26 11:48:25.690625038 +0800
+@@ -1770 +1770,10 @@
+-	u8	reserved[3];
++	u8  phy_type_ext;
++	u8  fec_config;
++#define I40E_AQ_SET_FEC_ABILITY_KR  (1 << 0)
++#define I40E_AQ_SET_FEC_ABILITY_RS  (1 << 1)
++#define I40E_AQ_SET_FEC_REQUEST_KR  (1 << 2)
++#define I40E_AQ_SET_FEC_REQUEST_RS  (1 << 3)
++#define I40E_AQ_SET_FEC_AUTO        (1 << 4)
++#define I40E_AQ_PHY_FEC_CONFIG_SHIFT    0x0
++#define I40E_AQ_PHY_FEC_CONFIG_MASK (0x1F << I40E_AQ_PHY_FEC_CONFIG_SHIFT)
++	u8  reserved;
+diff -ru0 src/i40e/i40e_ethtool.c src_patch/i40e/i40e_ethtool.c
+--- src/i40e/i40e_ethtool.c	2024-06-26 14:11:08.941694919 +0800
++++ src_patch/i40e/i40e_ethtool.c	2024-06-27 13:47:34.574133247 +0800
+@@ -271,0 +272 @@
++    "link-down-on-close",
+@@ -3588,0 +3590,2 @@
++	ret_flags |= pf->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED ?
++		I40E_FLAG_LINK_DOWN_ON_CLOSE_FLAG : 0;
+@@ -3605,0 +3609,5 @@
++
++	if (flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_FLAG)
++		pf->flags |= I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED;
++	else
++		pf->flags &= ~I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED;
+diff -ru0 src/i40e/i40e_main.c src_patch/i40e/i40e_main.c
+--- src/i40e/i40e_main.c	2024-06-26 14:11:08.941694919 +0800
++++ src_patch/i40e/i40e_main.c	2024-06-27 13:50:46.214109003 +0800
+@@ -97,0 +98 @@
++static void i40e_force_link_state(struct i40e_pf *pf, bool is_up);
+@@ -5344 +5345,2 @@
+-			I40E_AQ_QUALIFIED_MODULE)))
++			I40E_AQ_QUALIFIED_MODULE)) &&
++		    (!(pf->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED)))
+@@ -5399,0 +5402,4 @@
++	if (vsi->type == I40E_VSI_MAIN &&
++		(vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED))
++		i40e_force_link_state(vsi->back, true);
++
+@@ -5407,0 +5414,65 @@
++ * i40e_force_link_state - Force the link status
++ * @pf: board private structure
++ * @is_up: whether the link state should be forced up or down
++ **/
++static void i40e_force_link_state(struct i40e_pf *pf, bool is_up)
++{
++    struct i40e_aq_get_phy_abilities_resp abilities;
++    struct i40e_aq_set_phy_config config = {0};
++    struct i40e_hw *hw = &pf->hw;
++    enum i40e_aq_phy_type cnt;
++    __le32 mask = 0;
++    i40e_status err;
++
++    /* Get the current phy config */
++    err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
++                       NULL);
++    if (err)
++        dev_dbg(&pf->pdev->dev,
++            "failed to get phy cap., ret =  %s last_status =  %s\n",
++            i40e_stat_str(hw, err),
++            i40e_aq_str(hw, hw->aq.asq_last_status));
++
++    /* If link needs to go up, but was not forced to go down,
++     * no need for a flap
++     */
++    if (is_up && abilities.phy_type != 0)
++        return;
++
++    /* To enable link, phy_type mask needs to include each type */
++    for (cnt = I40E_PHY_TYPE_SGMII; cnt < I40E_PHY_TYPE_MAX; cnt++)
++        mask |= cpu_to_le32(1 << cnt);
++
++    config.phy_type = is_up ? mask : 0;
++    config.phy_type_ext = is_up ? (I40E_AQ_PHY_TYPE_EXT_25G_KR |
++        I40E_AQ_PHY_TYPE_EXT_25G_CR | I40E_AQ_PHY_TYPE_EXT_25G_SR |
++        I40E_AQ_PHY_TYPE_EXT_25G_LR) : 0;
++    /* Copy the old settings, except of phy_type */
++    config.abilities = abilities.abilities;
++    config.link_speed = abilities.link_speed;
++    config.eee_capability = abilities.eee_capability;
++    config.eeer = abilities.eeer_val;
++    config.low_power_ctrl = abilities.d3_lpan;
++    err = i40e_aq_set_phy_config(hw, &config, NULL);
++
++    if (err)
++        dev_dbg(&pf->pdev->dev,
++            "set phy config ret =  %s last_status =  %s\n",
++            i40e_stat_str(&pf->hw, err),
++            i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
++
++    /* Update the link info */
++    err = i40e_update_link_info(hw);
++    if (err) {
++        /* Wait a little bit (on 40G cards it sometimes takes a really
++         * long time for link to come back from the atomic reset)
++         * and try once more
++         */
++        msleep(1000);
++        i40e_update_link_info(hw);
++    }
++
++    i40e_aq_set_link_restart_an(hw, true, NULL);
++}
++
++/**
+@@ -5423,0 +5495,3 @@
++    if ((vsi->type == I40E_VSI_MAIN) &&
++        (vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED))
++        i40e_force_link_state(vsi->back, false);
+@@ -5522,0 +5597,2 @@
++	i40e_force_link_state(pf, true);
++
+@@ -6405 +6481,10 @@
+-	    (!(status->link_info & I40E_AQ_LINK_UP)))
++	    (!(status->link_info & I40E_AQ_LINK_UP)) &&
++	    (!(pf->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED))) {
++        dev_err(&pf->pdev->dev,
++                "status->link_info %d, status->an_info %d, I40E_AQ_MEDIA_AVAILABLE %d, I40E_AQ_QUALIFIED_MODULE %d, I40E_AQ_LINK_UP %d",
++            status->link_info,
++            status->an_info,
++            I40E_AQ_MEDIA_AVAILABLE,
++            I40E_AQ_QUALIFIED_MODULE,
++            I40E_AQ_LINK_UP
++        );
+@@ -6407,0 +6493 @@
++    }
+@@ -8726,0 +8813,4 @@
++
++    /* Set link-down-on-close flag */
++    /* Not presented in current version (1.4.25) */
++    pf->flags |= I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED;
Index: /branches/rel_avx_2_7_2/3rdpartyappliance/centos-i40e/SPECS/i40e.spec
===================================================================
--- /branches/rel_avx_2_7_2/3rdpartyappliance/centos-i40e/SPECS/i40e.spec	(revision 8834)
+++ /branches/rel_avx_2_7_2/3rdpartyappliance/centos-i40e/SPECS/i40e.spec	(working copy)
@@ -1,7 +1,7 @@
 Name: i40e
 Summary: Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
 Version: 1.4.25
-Release: 11
+Release: 12
 Source: %{name}-%{version}.tar.gz
 Vendor: Intel Corporation
 License: GPL
@@ -33,6 +33,7 @@
 Patch999010: avx_get_i40e_info_bug77356.patch
 Patch999011: allow_vlan0_work.patch
 Patch999012: 25G_support.patch
+Patch999013: add_link_down_on_close_feature.patch
 
 ####
 %description
@@ -52,6 +53,7 @@
 %patch999010 -p2
 %patch999011 -p1
 %patch999012 -p1
+%patch999013 -p0
 
 %build
 make -C src clean
Index: /branches/rel_avx_2_7_2/src/backend/sys_cmd.c
===================================================================
--- /branches/rel_avx_2_7_2/src/backend/sys_cmd.c	(revision 8834)
+++ /branches/rel_avx_2_7_2/src/backend/sys_cmd.c	(working copy)
@@ -83,6 +83,7 @@
 #include "va_xmlrpc.h"
 #include "avx_macpool.h"
 #include "avxbond.h"
+#include "avxpci.h"
 
 #define MAXLEN			8192
 #define MAXUSRPASSLEN		2048
@@ -6603,3 +6604,144 @@
     printf("%s", buff);
     return 0;
 }
+
+int
+set_if_state(char *interface, int up_down)
+{
+    int ret = -1;
+    int len;
+    int port_idx;
+    char if_name[32];
+
+    struct va_port* port_list = NULL;
+    struct pci_root_port *rpt = NULL;
+    pci_dev_info_t* nic_vf_numa = NULL;
+
+    if (!interface) {
+        printf("It seems that you do not give me any port number\n");
+        goto cleanup;
+    } else if (strcmp(interface, "mgmt") == 0) {
+        printf("mgmt port does not support this feature\n");
+        goto cleanup;
+    }
+
+    /* Only parse the first two digits
+     * to prevent buffer overflow.
+     * This is reasonable as many
+     * motherboards do not support
+     * more than 99 devices
+     * attached to PCI-E. */
+    sscanf(interface, "port%2d", &port_idx);
+
+    if(port_idx < 1 || port_idx > 99) {
+        printf("It seems that you provide an invalide port number\n");
+        goto cleanup;
+    }
+
+	/* Find interface name by its port number */
+    rpt = avxpci_module_init();
+    if (!rpt) {
+        printf("avxpci_module_init() failed\n");
+        goto cleanup;
+    }
+
+    port_list = get_va_port(rpt, &len);
+    nic_vf_numa = _CALLOC(pci_dev_info_t, len);
+    if (get_pci_dev_info(nic_vf_numa, VPT_PORT) < 0) {
+        printf("System internal error!\n");
+        goto cleanup;
+    }
+    snprintf(
+        if_name,
+        sizeof(if_name),
+        "enp%ds%df%d",
+        nic_vf_numa[port_idx - 1].bus,
+        nic_vf_numa[port_idx - 1].dev,
+        nic_vf_numa[port_idx - 1].func
+	);
+
+    /* up/down interface */
+    int s;
+    /* Create socket */
+    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        printf("Unable to create socket\n");
+        goto cleanup;
+    }
+
+    /* Setup our control structures */
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    strcpy(ifr.ifr_name, if_name);
+
+    /* Get flags */
+    if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
+        perror("ioctl (SIOCGIFFLAGS)");
+        close(s);
+        goto cleanup;
+    }
+
+    /* Check whether the interface is already in up/down state */
+    int sflags = ifr.ifr_flags;
+    if ((up_down == IFF_UP) && (sflags & IFF_UP)) {
+        printf("Interface %s is already up\n", if_name);
+        goto cleanup;
+    } else if ((up_down == -IFF_UP) && !(sflags && IFF_UP)) {
+        printf("Interface %s is already down\n", if_name);
+        goto cleanup;
+    }
+
+	/* Update interface flag */
+    sflags = 0;
+    if (up_down == -IFF_UP) {
+        printf("Set interface %s to down\n", if_name);
+        up_down = -up_down;
+        sflags &= ~((uint32_t)up_down);
+    } else {
+        printf("Set interface %s to up\n", if_name);
+        sflags |= up_down;
+    }
+    ifr.ifr_flags = sflags;
+
+    /* Set switch_flag */
+    if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
+        perror("ioctl (SIOCSIFFLAGS)");
+        close(s);
+        goto cleanup;
+    }
+
+    close(s);
+
+    if (ifr.ifr_flags & IFF_UP) {
+        printf("Interface %s startup\n", if_name);
+    } else {
+        printf("Interface %s shutdown\n", if_name);
+    }
+
+    /* Grace period for updating interface status */
+    sleep(1);
+
+    ret = 0;
+
+cleanup:
+    _FREE(nic_vf_numa);
+    free_va_port(port_list, len);
+    if(rpt) {
+        avxpci_module_exit(rpt);
+    }
+    if(ret == -1) {
+        printf("Operation of up/down interface is unsuccessful\n");
+    }
+    return ret;
+}
+
+int
+if_shutdown(char *interface)
+{
+    return set_if_state(interface, -IFF_UP);
+}
+
+int
+no_if_shutdown(char *interface)
+{
+    return set_if_state(interface, IFF_UP);
+}
Index: /branches/rel_avx_2_7_2/src/generator/commands.pm
===================================================================
--- /branches/rel_avx_2_7_2/src/generator/commands.pm	(revision 8834)
+++ /branches/rel_avx_2_7_2/src/generator/commands.pm	(working copy)
@@ -7178,6 +7178,34 @@
                         },
                         ],
     },
+    {
+        obj_type => "ITEM",
+        name => "shutdown",
+        help_string => "    Shutdown interface",
+        menu => "root_interface",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "if_shutdown",
+        function_args => [ {
+            type => "STRING",
+            help_string => "Interaface ID (e.g., port1)",
+            optional => "NO",
+        }, ],
+    },
+    {
+        obj_type => "ITEM",
+        name => "shutdown",
+        help_string => "    Startup interface",
+        menu => "root_no_interface",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "no_if_shutdown",
+        function_args => [ {
+            type => "STRING",
+            help_string => "Interface ID (e.g., port1)",
+            optional => "NO",
+        }, ],
+    },
 );
 
 # This method is required to expost the command table to the caller.
Index: /branches/rel_avx_2_7_2/update/avxsystem.ks
===================================================================
--- /branches/rel_avx_2_7_2/update/avxsystem.ks	(revision 8834)
+++ /branches/rel_avx_2_7_2/update/avxsystem.ks	(working copy)
@@ -110,7 +110,7 @@
 bind-libs-lite-9.9.4-29.el7.x86_64
 avx_cli-1.0-2.el7.centos.x86_64
 httpd-tools-2.4.6-40.el7.centos.4.1.x86_64
-i40e-1.4.25-11.x86_64
+i40e-1.4.25-12.x86_64
 flac-libs-1.3.0-5.el7_1.x86_64
 ipmitool-1.8.13-8.el7_1.x86_64
 file-5.11-31.el7.x86_64
