3. 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