3. LAN接口状态管理

LAN接口状态管理 学习卡片

任务目标

实现一个LAN接口状态机,用于管理多个LAN口的启用、禁用、协商速率变化等状态,并在状态变化时联动VLAN配置。状态机需要处理外部事件(如用户命令、链路协商结果),维护每个LAN口的当前状态,并确保VLAN配置与接口状态保持一致。

核心设计

每个LAN口的状态由管理状态(Admin:up/down)和链路状态(Link:up/down)组合而成。状态机在以下事件驱动下迁移:

  • ADMIN_UP / ADMIN_DOWN:用户或上层应用修改管理状态
  • LINK_UP / LINK_DOWN:物理层协商结果
  • RATE_CHANGE:协商速率变化(仅在链路up时有效)

状态迁移规则:

  • 管理down时,无论链路如何,接口强制为DOWN,VLAN不参与转发
  • 管理up且链路up时,接口为UP,VLAN成员生效
  • 管理up但链路down时,接口为DOWN,VLAN成员保留但标记为未激活
  • 速率变化仅在UP状态被接受,并同步更新VLAN端口速率配置

完整实现

#include <stdio.h>
#include <string.h>
#include <stdint.h>

#define MAX_LAN_PORTS 4
#define MAX_VLANS 8

typedef enum { ADMIN_DOWN = 0, ADMIN_UP = 1 } admin_state_t;
typedef enum { LINK_DOWN = 0, LINK_UP = 1 } link_state_t;
typedef enum { PORT_DOWN = 0, PORT_UP = 1 } port_state_t;

typedef enum {
    EV_ADMIN_UP,
    EV_ADMIN_DOWN,
    EV_LINK_UP,
    EV_LINK_DOWN,
    EV_RATE_CHANGE
} lan_event_t;

typedef struct {
    uint16_t vid;
    uint8_t  member_ports;  // bitmask: bit n = port n is member
    uint32_t port_rate[MAX_LAN_PORTS]; // Mbps per port
} vlan_cfg_t;

typedef struct {
    admin_state_t admin;
    link_state_t  link;
    port_state_t  state;
    uint32_t      rate_mbps;
} lan_port_t;

typedef struct {
    lan_port_t ports[MAX_LAN_PORTS];
    vlan_cfg_t vlans[MAX_VLANS];
    int        vlan_count;
} lan_system_t;

static void vlan_apply_port_state(lan_system_t *sys, int port_idx) {
    for (int v = 0; v < sys->vlan_count; v++) {
        vlan_cfg_t *vlan = &sys->vlans[v];
        if (vlan->member_ports & (1 << port_idx)) {
            if (sys->ports[port_idx].state == PORT_UP) {
                vlan->port_rate[port_idx] = sys->ports[port_idx].rate_mbps;
            } else {
                vlan->port_rate[port_idx] = 0; // inactive
            }
        }
    }
}

static void lan_port_update(lan_system_t *sys, int port_idx) {
    lan_port_t *p = &sys->ports[port_idx];
    port_state_t new_state = (p->admin == ADMIN_UP && p->link == LINK_UP)
                             ? PORT_UP : PORT_DOWN;
    if (new_state != p->state) {
        p->state = new_state;
        vlan_apply_port_state(sys, port_idx);
    }
}

void lan_init(lan_system_t *sys) {
    memset(sys, 0, sizeof(*sys));
    for (int i = 0; i < MAX_LAN_PORTS; i++) {
        sys->ports[i].admin = ADMIN_DOWN;
        sys->ports[i].link  = LINK_DOWN;
        sys->ports[i].state = PORT_DOWN;
        sys->ports[i].rate_mbps = 0;
    }
}

int lan_add_vlan(lan_system_t *sys, uint16_t vid, uint8_t member_mask) {
    if (sys->vlan_count >= MAX_VLANS) return -1;
    vlan_cfg_t *v = &sys->vlans[sys->vlan_count++];
    memset(v, 0, sizeof(*v));
    v->vid = vid;
    v->member_ports = member_mask;
    for (int i = 0; i < MAX_LAN_PORTS; i++) {
        if (member_mask & (1 << i)) {
            v->port_rate[i] = sys->ports[i].state == PORT_UP
                              ? sys->ports[i].rate_mbps : 0;
        }
    }
    return 0;
}

int lan_handle_event(lan_system_t *sys, int port_idx, lan_event_t ev, uint32_t rate) {
    if (port_idx < 0 || port_idx >= MAX_LAN_PORTS) return -1;
    lan_port_t *p = &sys->ports[port_idx];

    switch (ev) {
    case EV_ADMIN_UP:
        p->admin = ADMIN_UP;
        break;
    case EV_ADMIN_DOWN:
        p->admin = ADMIN_DOWN;
        p->rate_mbps = 0;
        break;
    case EV_LINK_UP:
        if (p->admin != ADMIN_UP) return 0; // ignore when admin down
        p->link = LINK_UP;
        if (rate > 0) p->rate_mbps = rate;
        break;
    case EV_LINK_DOWN:
        p->link = LINK_DOWN;
        p->rate_mbps = 0;
        break;
    case EV_RATE_CHANGE:
        if (p->state != PORT_UP) return 0; // only when active
        p->rate_mbps = rate;
        break;
    default:
        return -1;
    }
    lan_port_update(sys, port_idx);
    return 0;
}

void lan_dump_state(const lan_system_t *sys) {
    for (int i = 0; i < MAX_LAN_PORTS; i++) {
        const lan_port_t *p = &sys->ports[i];
        printf("Port %d: admin=%s link=%s state=%s rate=%u Mbps\n",
               i,
               p->admin == ADMIN_UP ? "UP" : "DOWN",
               p->link  == LINK_UP ? "UP" : "DOWN",
               p->state == PORT_UP ? "UP" : "DOWN",
               p->rate_mbps);
    }
    for (int v = 0; v < sys->vlan_count; v++) {
        const vlan_cfg_t *vlan = &sys->vlans[v];
        printf("VLAN %u members=0x%02X rates=[%u %u %u %u]\n",
               vlan->vid, vlan->member_ports,
               vlan->port_rate[0], vlan->port_rate[1],
               vlan->port_rate[2], vlan->port_rate[3]);
    }
}

int main(void) {
    lan_system_t sys;
    lan_init(&sys);

    // 配置:VLAN 10 包含端口0、1、2
    lan_add_vlan(&sys, 10, 0x07);

    // 端口0:管理up,链路协商1Gbps
    lan_handle_event(&sys, 0, EV_ADMIN_UP, 0);
    lan_handle_event(&sys, 0, EV_LINK_UP, 1000);

    // 端口1:管理up,链路协商100Mbps
    lan_handle_event(&sys, 1, EV_ADMIN_UP, 0);
    lan_handle_event(&sys, 1, EV_LINK_UP, 100);

    // 端口2:管理up,链路down
    lan_handle_event(&sys, 2, EV_ADMIN_UP, 0);

    printf("=== After link events ===\n");
    lan_dump_state(&sys);

    // 端口0速率变化为2.5Gbps
    lan_handle_event(&sys, 0, EV_RATE_CHANGE, 2500);

    // 端口1链路down
    lan_handle_event(&sys, 1, EV_LINK_DOWN, 0);

    printf("\n=== After rate change & link down ===\n");
    lan_dump_state(&sys);

    return 0;
}

编译与运行

gcc -Wall -O2 lan_state_machine.c -o lan_state_machine
./lan_state_machine

验证方法

程序输出应满足以下判定条件:

  • 初始事件处理后,端口0和端口1状态为UP,端口2为DOWN(管理up但链路down)
  • VLAN 10中,端口0速率为1000,端口1速率为100,端口2速率为0(未激活)
  • 端口0速率变化后,VLAN中端口0速率更新为2500
  • 端口1链路down后,端口1状态变为DOWN,VLAN中端口1速率变为0

预期输出(与代码逻辑严格一致):

=== After link events ===
Port 0: admin=UP link=UP state=UP rate=1000 Mbps
Port 1: admin=UP link=UP state=UP rate=100 Mbps
Port 2: admin=UP link=DOWN state=DOWN rate=0 Mbps
VLAN 10 members=0x07 rates=[1000 100 0 0]

=== After rate change & link down ===
Port 0: admin=UP link=UP state=UP rate=2500 Mbps
Port 1: admin=UP link=DOWN state=DOWN rate=0 Mbps
Port 2: admin=UP link=DOWN state=DOWN rate=0 Mbps
VLAN 10 members=0x07 rates=[2500 0 0 0]

关键说明

  • 状态机核心逻辑在lan_handle_event中:事件先修改端口内部状态,再通过lan_port_update统一计算最终端口状态,避免状态不一致
  • VLAN联动通过vlan_apply_port_state实现:端口状态变化时,自动更新该端口在所有VLAN中的速率配置(0表示不参与转发)
  • 速率变化事件仅在端口处于UP状态时被接受,防止链路down时写入无效速率
  • 管理down会清除速率并强制端口进入DOWN,即使物理链路仍然up