-
Notifications
You must be signed in to change notification settings - Fork 16
zebra: add dplane helpers to provide interface speed #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e8f2bc9
102b3f1
8442588
6aa267e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -64,22 +64,40 @@ static const char *if_zebra_data_state(uint8_t state) | |||||||||||
| static void if_zebra_speed_update(struct event *event) | ||||||||||||
| { | ||||||||||||
| struct interface *ifp = EVENT_ARG(event); | ||||||||||||
| struct zebra_if *zif = ifp->info; | ||||||||||||
|
|
||||||||||||
| dplane_intf_speed_get(ifp); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| static void zebra_if_schedule_speed_update(struct zebra_if *zif, int timeout) | ||||||||||||
| { | ||||||||||||
| event_add_timer(zrouter.master, if_zebra_speed_update, zif->ifp, timeout, | ||||||||||||
| &zif->speed_update); | ||||||||||||
| event_ignore_late_timer(zif->speed_update); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| static void zebra_if_speed_update_ctx(struct zebra_dplane_ctx *ctx, struct interface *ifp) | ||||||||||||
| { | ||||||||||||
| enum zebra_dplane_result dp_res; | ||||||||||||
| bool speed_set, changed = false; | ||||||||||||
| struct zebra_if *zif; | ||||||||||||
| uint32_t new_speed; | ||||||||||||
| bool changed = false; | ||||||||||||
| int error = 0; | ||||||||||||
|
|
||||||||||||
| zif->speed_checked++; | ||||||||||||
| if (!ifp) | ||||||||||||
| return; | ||||||||||||
|
|
||||||||||||
| new_speed = kernel_get_speed(ifp, &error); | ||||||||||||
| zif = ifp->info; | ||||||||||||
| zif->speed_checked++; | ||||||||||||
|
|
||||||||||||
| dp_res = dplane_ctx_get_status(ctx); | ||||||||||||
| /* error may indicate vrf not available or | ||||||||||||
| * interfaces not available. | ||||||||||||
| * note that loopback & virtual interfaces can return 0 as speed | ||||||||||||
| */ | ||||||||||||
| if (error == INTERFACE_SPEED_ERROR_READ) | ||||||||||||
| if (dp_res == ZEBRA_DPLANE_REQUEST_FAILURE) | ||||||||||||
| return; | ||||||||||||
|
|
||||||||||||
| speed_set = dplane_ctx_get_ifp_speed_set(ctx); | ||||||||||||
| new_speed = speed_set ? dplane_ctx_get_ifp_speed(ctx) : 0; | ||||||||||||
| if (new_speed != ifp->speed) { | ||||||||||||
| zlog_info("%s: %s old speed: %u new speed: %u", __func__, | ||||||||||||
| ifp->name, ifp->speed, new_speed); | ||||||||||||
|
|
@@ -88,7 +106,7 @@ static void if_zebra_speed_update(struct event *event) | |||||||||||
| changed = true; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if (changed || error == INTERFACE_SPEED_ERROR_UNKNOWN) { | ||||||||||||
| if (changed || !speed_set) { | ||||||||||||
| #define SPEED_UPDATE_SLEEP_TIME 5 | ||||||||||||
| #define SPEED_UPDATE_COUNT_MAX (4 * 60 / SPEED_UPDATE_SLEEP_TIME) | ||||||||||||
| /* | ||||||||||||
|
|
@@ -103,17 +121,44 @@ static void if_zebra_speed_update(struct event *event) | |||||||||||
| * to not update the system to keep track of that. This | ||||||||||||
| * is far simpler to just stop trying after 4 minutes | ||||||||||||
| */ | ||||||||||||
| if (error == INTERFACE_SPEED_ERROR_UNKNOWN && | ||||||||||||
| zif->speed_update_count == SPEED_UPDATE_COUNT_MAX) | ||||||||||||
| if (!speed_set && zif->speed_update_count == SPEED_UPDATE_COUNT_MAX) | ||||||||||||
| return; | ||||||||||||
|
|
||||||||||||
| zif->speed_update_count++; | ||||||||||||
| event_add_timer(zrouter.master, if_zebra_speed_update, ifp, | ||||||||||||
| SPEED_UPDATE_SLEEP_TIME, &zif->speed_update); | ||||||||||||
| event_ignore_late_timer(zif->speed_update); | ||||||||||||
| zebra_if_schedule_speed_update(zif, SPEED_UPDATE_SLEEP_TIME); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| void zebra_if_speed_process(struct zebra_dplane_ctx *ctx) | ||||||||||||
| { | ||||||||||||
| const char *ifname = dplane_ctx_get_ifname(ctx); | ||||||||||||
| vrf_id_t vrf_id = dplane_ctx_get_vrf(ctx); | ||||||||||||
| uint32_t speed; | ||||||||||||
| int error = 0; | ||||||||||||
|
|
||||||||||||
| speed = kernel_get_speed(vrf_id, ifname, &error); | ||||||||||||
| switch (error) { | ||||||||||||
| case 0: | ||||||||||||
| dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); | ||||||||||||
| dplane_ctx_set_ifp_speed(ctx, speed); | ||||||||||||
| dplane_ctx_set_ifp_speed_set(ctx, true); | ||||||||||||
| return; | ||||||||||||
| case INTERFACE_SPEED_ERROR_UNKNOWN: | ||||||||||||
| dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); | ||||||||||||
| dplane_ctx_set_ifp_speed_set(ctx, false); | ||||||||||||
| return; | ||||||||||||
| case INTERFACE_SPEED_ERROR_READ: | ||||||||||||
| /* INTERFACE_SPEED_ERROR_READ: means no device, no vrf */ | ||||||||||||
| break; | ||||||||||||
| default: | ||||||||||||
| if (IS_ZEBRA_DEBUG_KERNEL) | ||||||||||||
| zlog_debug("kernel_get_speed returned an unknown error %u", error); | ||||||||||||
| break; | ||||||||||||
|
Comment on lines
+154
to
+156
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: zebra/interface.c
Line: 154-156
Comment:
**Format specifier mismatch in default error-case log**
`error` is declared as `int` but formatted with `%u` (unsigned). While benign for small values, a negative `error` code would log as a large unsigned number, making debugging harder.
```suggestion
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("kernel_get_speed returned an unknown error %d", error);
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| static void zebra_if_node_destroy(route_table_delegate_t *delegate, | ||||||||||||
| struct route_table *table, | ||||||||||||
| struct route_node *node) | ||||||||||||
|
|
@@ -159,19 +204,6 @@ static int if_zebra_new_hook(struct interface *ifp) | |||||||||||
|
|
||||||||||||
| ifp->info = zebra_if; | ||||||||||||
|
|
||||||||||||
| /* | ||||||||||||
| * Some platforms are telling us that the interface is | ||||||||||||
| * up and ready to go. When we check the speed we | ||||||||||||
| * sometimes get the wrong value. Wait a couple | ||||||||||||
| * of seconds and ask again. Hopefully it's all settled | ||||||||||||
| * down upon startup. | ||||||||||||
| */ | ||||||||||||
| zebra_if->speed_update_count = 0; | ||||||||||||
| zebra_if->speed_checked = 0; | ||||||||||||
| event_add_timer(zrouter.master, if_zebra_speed_update, ifp, 15, | ||||||||||||
| &zebra_if->speed_update); | ||||||||||||
| event_ignore_late_timer(zebra_if->speed_update); | ||||||||||||
|
|
||||||||||||
| return 0; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
|
|
@@ -933,9 +965,7 @@ static void if_handle_bond_speed_change(struct interface *ifp) | |||||||||||
| if (part_of_bond->bond_if) { | ||||||||||||
| zif = part_of_bond->bond_if->info; | ||||||||||||
|
|
||||||||||||
| if (!event_is_scheduled(zif->speed_update)) | ||||||||||||
| event_add_timer(zrouter.master, if_zebra_speed_update, part_of_bond->bond_if, 1, | ||||||||||||
| &zif->speed_update); | ||||||||||||
| zebra_if_schedule_speed_update(zif, 1); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
|
|
@@ -997,9 +1027,8 @@ void if_up(struct interface *ifp, bool install_connected) | |||||||||||
| if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) | ||||||||||||
| zebra_evpn_mh_uplink_oper_update(zif); | ||||||||||||
|
|
||||||||||||
| event_add_timer(zrouter.master, if_zebra_speed_update, ifp, 0, | ||||||||||||
| &zif->speed_update); | ||||||||||||
| event_ignore_late_timer(zif->speed_update); | ||||||||||||
| event_cancel(&zif->speed_update); | ||||||||||||
| dplane_intf_speed_get(ifp); | ||||||||||||
|
|
||||||||||||
| if_addr_wakeup(ifp); | ||||||||||||
|
|
||||||||||||
|
|
@@ -2026,8 +2055,8 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) | |||||||||||
| uint32_t mtu; | ||||||||||||
| ns_id_t link_nsid; | ||||||||||||
| struct zebra_if *zif; | ||||||||||||
| bool protodown, protodown_set, startup; | ||||||||||||
| uint32_t rc_bitfield; | ||||||||||||
| bool protodown, protodown_set, startup, speed_set; | ||||||||||||
| uint32_t rc_bitfield, speed; | ||||||||||||
| uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; | ||||||||||||
| char *desc; | ||||||||||||
| uint8_t family; | ||||||||||||
|
|
@@ -2054,6 +2083,8 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) | |||||||||||
| desc = dplane_ctx_get_ifp_desc(ctx); | ||||||||||||
| family = dplane_ctx_get_ifp_family(ctx); | ||||||||||||
| change_flags = dplane_ctx_get_ifp_change_flags(ctx); | ||||||||||||
| speed_set = dplane_ctx_get_ifp_speed_set(ctx); | ||||||||||||
| speed = dplane_ctx_get_ifp_speed(ctx); | ||||||||||||
|
|
||||||||||||
| #ifndef AF_BRIDGE | ||||||||||||
| /* | ||||||||||||
|
|
@@ -2092,7 +2123,24 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) | |||||||||||
| if_update_state_mtu(ifp, mtu); | ||||||||||||
| if_update_state_mtu6(ifp, mtu); | ||||||||||||
| if_update_state_metric(ifp, 0); | ||||||||||||
| if_update_state_speed(ifp, kernel_get_speed(ifp, NULL)); | ||||||||||||
| if (!speed_set) { | ||||||||||||
| speed = 0; | ||||||||||||
| /* Query initial speed if not provided by dplane */ | ||||||||||||
| dplane_intf_speed_get(ifp); | ||||||||||||
|
|
||||||||||||
| /* | ||||||||||||
| * Some platforms are telling us that the interface is | ||||||||||||
| * up and ready to go. When we check the speed we | ||||||||||||
| * sometimes get the wrong value. Wait a couple | ||||||||||||
| * of seconds and ask again. Hopefully it's all settled | ||||||||||||
| * down upon startup. | ||||||||||||
| */ | ||||||||||||
| zif->speed_update_count = 0; | ||||||||||||
| zif->speed_checked = 0; | ||||||||||||
| zebra_if_schedule_speed_update(zif, 15); | ||||||||||||
| } else | ||||||||||||
| zif->speed_checked++; | ||||||||||||
| if_update_state_speed(ifp, speed); | ||||||||||||
| ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; | ||||||||||||
| ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); | ||||||||||||
|
|
||||||||||||
|
|
@@ -2196,6 +2244,10 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) | |||||||||||
| if_update_state_mtu(ifp, mtu); | ||||||||||||
| if_update_state_mtu6(ifp, mtu); | ||||||||||||
| if_update_state_metric(ifp, 0); | ||||||||||||
| if (speed_set) { | ||||||||||||
| zif->speed_checked++; | ||||||||||||
| if_update_state_speed(ifp, speed); | ||||||||||||
| } | ||||||||||||
| ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); | ||||||||||||
|
|
||||||||||||
| /* | ||||||||||||
|
|
@@ -2403,6 +2455,8 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) | |||||||||||
| zebra_if_update_ctx(ctx, ifp); | ||||||||||||
| } else if (op == DPLANE_OP_INTF_NETCONFIG) { | ||||||||||||
| zebra_if_netconf_update_ctx(ctx, ifp, ifindex); | ||||||||||||
| } else if (op == DPLANE_OP_INTF_SPEED_GET) { | ||||||||||||
| zebra_if_speed_update_ctx(ctx, ifp); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |
| #include "lib_errors.h" | ||
|
|
||
| #include "zebra/debug.h" | ||
| #include "zebra/interface.h" | ||
| #include "zebra/rib.h" | ||
| #include "zebra/rt.h" | ||
| #include "zebra/kernel_socket.h" | ||
|
|
@@ -383,9 +384,12 @@ extern int kernel_interface_set_master(struct interface *master, | |
| return 0; | ||
| } | ||
|
|
||
| uint32_t kernel_get_speed(struct interface *ifp, int *error) | ||
| uint32_t kernel_get_speed(vrf_id_t vrf_id, const char *ifname, int *error) | ||
| { | ||
| return ifp->speed; | ||
| if (error) | ||
| *error = INTERFACE_SPEED_ERROR_READ; | ||
|
|
||
| return 0; | ||
|
Comment on lines
384
to
+392
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The old stub returned With this change, uint32_t kernel_get_speed(vrf_id_t vrf_id, const char *ifname, int *error)
{
struct interface *ifp;
ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
if (!ifp) {
if (error)
*error = INTERFACE_SPEED_ERROR_READ;
return 0;
}
if (error)
*error = 0;
return ifp->speed;
}Prompt To Fix With AIThis is a comment left during a code review.
Path: zebra/rt_socket.c
Line: 384-392
Comment:
**BSD speed regression: always returning INTERFACE_SPEED_ERROR_READ**
The old stub returned `ifp->speed`, which works correctly on BSD because `kernel_socket.c` populates `ifp->speed` directly from `ifm->ifm_data.ifi_baudrate / 1000000` on RTM_IFINFO messages (`kernel_socket.c` line 730). That assignment does not call `if_update_state_speed`, so the timer-based path was the only way clients received the speed-change notification via `if_add_update`.
With this change, `kernel_get_speed` always returns `INTERFACE_SPEED_ERROR_READ` on BSD. `zebra_if_speed_update_ctx` then hits the `ZEBRA_DPLANE_REQUEST_FAILURE` early-return path, skips the speed update, and never reschedules — leaving BSD clients without any speed-change notification. The correct fix is to restore the `ifp->speed` return for BSD:
```c
uint32_t kernel_get_speed(vrf_id_t vrf_id, const char *ifname, int *error)
{
struct interface *ifp;
ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
if (!ifp) {
if (error)
*error = INTERFACE_SPEED_ERROR_READ;
return 0;
}
if (error)
*error = 0;
return ifp->speed;
}
```
How can I resolve this? If you propose a fix, please make it concise. |
||
| } | ||
|
|
||
| int kernel_upd_mac_nh(uint32_t nh_id, struct ipaddr *vtep_ip) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kernel_get_speedis called withNULLfor theerrorpointer, so any error return (includingEOPNOTSUPPfor virtual/bridge interfaces, which setsspeed=0, error=INTERFACE_SPEED_ERROR_UNKNOWN) is silently swallowed. The caller then unconditionally setsspeed_set=true, which inzebra_if_dplane_ifp_handlingskips bothdplane_intf_speed_getand the 15-second retry timer. An interface that reports the wrong speed at startup will never be corrected.Passing
&errorand treatingINTERFACE_SPEED_ERROR_UNKNOWNasspeed_set=falsewould preserve the retry logic for uncertain speeds:Prompt To Fix With AI