Changeset View
Changeset View
Standalone View
Standalone View
sys/net/route/route_helpers.c
| Show First 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | nh = fib6_lookup(fibnum, &a->sin6_addr, a->sin6_scope_id, | ||||
| flags, flowid); | flags, flowid); | ||||
| break; | break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| return (nh); | return (nh); | ||||
| } | } | ||||
| #ifdef ROUTE_MPATH | |||||
| static void | |||||
| decompose_change_notification(struct rib_cmd_info *rc, route_notification_t *cb, | |||||
| void *cbdata) | |||||
| { | |||||
| uint32_t num_old, num_new; | |||||
| uint32_t nh_idx_old, nh_idx_new; | |||||
| struct weightened_nhop *wn_old, *wn_new; | |||||
| struct weightened_nhop tmp = { NULL, 0 }; | |||||
| uint32_t idx_old = 0, idx_new = 0; | |||||
| struct rib_cmd_info rc_del = { .rc_cmd = RTM_DELETE, .rc_rt = rc->rc_rt }; | |||||
| struct rib_cmd_info rc_add = { .rc_cmd = RTM_ADD, .rc_rt = rc->rc_rt }; | |||||
| if (NH_IS_NHGRP(rc->rc_nh_old)) { | |||||
| wn_old = nhgrp_get_nhops((struct nhgrp_object *)rc->rc_nh_old, &num_old); | |||||
| } else { | |||||
| tmp.nh = rc->rc_nh_old; | |||||
| tmp.weight = rc->rc_nh_weight; | |||||
| wn_old = &tmp; | |||||
| num_old = 1; | |||||
| } | |||||
| if (NH_IS_NHGRP(rc->rc_nh_new)) { | |||||
| wn_new = nhgrp_get_nhops((struct nhgrp_object *)rc->rc_nh_new, &num_new); | |||||
| } else { | |||||
| tmp.nh = rc->rc_nh_new; | |||||
| tmp.weight = rc->rc_nh_weight; | |||||
| wn_new = &tmp; | |||||
| num_new = 1; | |||||
| } | |||||
| /* Use the fact that each @wn array is sorted */ | |||||
| /* | |||||
| * Want to convert into set of add and delete operations | |||||
| * [1] -> [1, 2] = A{2} | |||||
| * [2] -> [1, 2] = A{1} | |||||
| * [1, 2, 4]->[1, 3, 4] = A{2}, D{3} | |||||
| * [1, 2, 4]->[1, 4] = D{2} | |||||
| * [1, 2, 4] -> [3, 4] = D{1}, C{2,3} OR C{1,3}, D{2} OR D{1},D{2},A{3} | |||||
| * [1, 2] -> [3, 4] = | |||||
| * | |||||
| */ | |||||
| idx_old = 0; | |||||
| while ((idx_old < num_old) && (idx_new < num_new)) { | |||||
| nh_idx_old = wn_old[idx_old].nh->nh_priv->nh_idx; | |||||
| nh_idx_new = wn_new[idx_new].nh->nh_priv->nh_idx; | |||||
| if (nh_idx_old == nh_idx_new) { | |||||
| if (wn_old[idx_old].weight != wn_new[idx_new].weight) { | |||||
| /* Update weight by providing del/add notifications */ | |||||
| rc_del.rc_nh_old = wn_old[idx_old].nh; | |||||
| rc_del.rc_nh_weight = wn_old[idx_old].weight; | |||||
| cb(&rc_del, cbdata); | |||||
| rc_add.rc_nh_new = wn_new[idx_new].nh; | |||||
| rc_add.rc_nh_weight = wn_new[idx_new].weight; | |||||
| cb(&rc_add, cbdata); | |||||
| } | |||||
| idx_old++; | |||||
| idx_new++; | |||||
| } else if (nh_idx_old < nh_idx_new) { | |||||
| /* | |||||
| * [1, ~2~, 4], [1, ~3~, 4] | |||||
| * [1, ~2~, 5], [1, ~3~, 4] | |||||
| * [1, ~2~], [1, ~3~, 4] | |||||
| */ | |||||
| if ((idx_old + 1 >= num_old) || | |||||
| (wn_old[idx_old + 1].nh->nh_priv->nh_idx > nh_idx_new)) { | |||||
| /* Add new unless the next old item is still <= new */ | |||||
| rc_add.rc_nh_new = wn_new[idx_new].nh; | |||||
| rc_add.rc_nh_weight = wn_new[idx_new].weight; | |||||
| cb(&rc_add, cbdata); | |||||
| idx_new++; | |||||
| } | |||||
| /* In any case, delete current old */ | |||||
| rc_del.rc_nh_old = wn_old[idx_old].nh; | |||||
| rc_del.rc_nh_weight = wn_old[idx_old].weight; | |||||
| cb(&rc_del, cbdata); | |||||
| idx_old++; | |||||
| } else { | |||||
| /* | |||||
| * nh_idx_old > nh_idx_new | |||||
| * | |||||
| * [1, ~3~, 4], [1, ~2~, 4] | |||||
| * [1, ~3~, 5], [1, ~2~, 4] | |||||
| * [1, ~3~, 4], [1, ~2~] | |||||
| */ | |||||
| if ((idx_new + 1 >= num_new) || | |||||
| (wn_new[idx_new + 1].nh->nh_priv->nh_idx > nh_idx_old)) { | |||||
| /* No next item or next item is > current one */ | |||||
| rc_add.rc_nh_new = wn_new[idx_new].nh; | |||||
| rc_add.rc_nh_weight = wn_new[idx_new].weight; | |||||
| cb(&rc_add, cbdata); | |||||
| idx_new++; | |||||
| } | |||||
| /* In any case, delete current old */ | |||||
| rc_del.rc_nh_old = wn_old[idx_old].nh; | |||||
| rc_del.rc_nh_weight = wn_old[idx_old].weight; | |||||
| cb(&rc_del, cbdata); | |||||
| idx_old++; | |||||
| } | |||||
| } | |||||
| while (idx_old < num_old) { | |||||
| rc_del.rc_nh_old = wn_old[idx_old].nh; | |||||
| rc_del.rc_nh_weight = wn_old[idx_old].weight; | |||||
| cb(&rc_del, cbdata); | |||||
| idx_old++; | |||||
| } | |||||
| while (idx_new < num_new) { | |||||
| rc_add.rc_nh_new = wn_new[idx_new].nh; | |||||
| rc_add.rc_nh_weight = wn_new[idx_new].weight; | |||||
| cb(&rc_add, cbdata); | |||||
| idx_new++; | |||||
| } | |||||
| } | |||||
| /* | |||||
| * Decompose multipath cmd info @rc into a list of add/del/change | |||||
| * single-path operations, calling @cb callback for each operation. | |||||
| * Assumes at least one of the nexthops in @rc is multipath. | |||||
| */ | |||||
| void | |||||
| rib_decompose_notification(struct rib_cmd_info *rc, route_notification_t *cb, | |||||
| void *cbdata) | |||||
| { | |||||
| struct weightened_nhop *wn; | |||||
| uint32_t num_nhops; | |||||
| struct rib_cmd_info rc_new; | |||||
| rc_new = *rc; | |||||
| DPRINTF("cb=%p cmd=%d nh_old=%p nh_new=%p", | |||||
| cb, rc->cmd, rc->nh_old, rc->nh_new); | |||||
| switch (rc->rc_cmd) { | |||||
| case RTM_ADD: | |||||
| if (!NH_IS_NHGRP(rc->rc_nh_new)) | |||||
| return; | |||||
| wn = nhgrp_get_nhops((struct nhgrp_object *)rc->rc_nh_new, &num_nhops); | |||||
| for (uint32_t i = 0; i < num_nhops; i++) { | |||||
| rc_new.rc_nh_new = wn[i].nh; | |||||
| rc_new.rc_nh_weight = wn[i].weight; | |||||
| cb(&rc_new, cbdata); | |||||
| } | |||||
| break; | |||||
| case RTM_DELETE: | |||||
| if (!NH_IS_NHGRP(rc->rc_nh_old)) | |||||
| return; | |||||
| wn = nhgrp_get_nhops((struct nhgrp_object *)rc->rc_nh_old, &num_nhops); | |||||
| for (uint32_t i = 0; i < num_nhops; i++) { | |||||
| rc_new.rc_nh_old = wn[i].nh; | |||||
| rc_new.rc_nh_weight = wn[i].weight; | |||||
| cb(&rc_new, cbdata); | |||||
| } | |||||
| break; | |||||
| case RTM_CHANGE: | |||||
| if (!NH_IS_NHGRP(rc->rc_nh_old) && !NH_IS_NHGRP(rc->rc_nh_new)) | |||||
| return; | |||||
| decompose_change_notification(rc, cb, cbdata); | |||||
| break; | |||||
| } | |||||
| } | |||||
| #endif | |||||