Commit db7019557cb48508f3ff9d6b40c2e967702897a6
Committed by
David S. Miller
1 parent
c1bb279cfa
rocker: Implement FIB offload in deferred work
Convert rocker to offload FIBs in deferred work in a similar fashion to mlxsw, which was converted in the previous commits. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 2 changed files with 51 additions and 8 deletions Side-by-side Diff
drivers/net/ethernet/rocker/rocker_main.c
... | ... | @@ -2166,28 +2166,70 @@ |
2166 | 2166 | .switchdev_port_obj_dump = rocker_port_obj_dump, |
2167 | 2167 | }; |
2168 | 2168 | |
2169 | -static int rocker_router_fib_event(struct notifier_block *nb, | |
2170 | - unsigned long event, void *ptr) | |
2169 | +struct rocker_fib_event_work { | |
2170 | + struct work_struct work; | |
2171 | + struct fib_entry_notifier_info fen_info; | |
2172 | + struct rocker *rocker; | |
2173 | + unsigned long event; | |
2174 | +}; | |
2175 | + | |
2176 | +static void rocker_router_fib_event_work(struct work_struct *work) | |
2171 | 2177 | { |
2172 | - struct rocker *rocker = container_of(nb, struct rocker, fib_nb); | |
2173 | - struct fib_entry_notifier_info *fen_info = ptr; | |
2178 | + struct rocker_fib_event_work *fib_work = | |
2179 | + container_of(work, struct rocker_fib_event_work, work); | |
2180 | + struct rocker *rocker = fib_work->rocker; | |
2174 | 2181 | int err; |
2175 | 2182 | |
2176 | - switch (event) { | |
2183 | + /* Protect internal structures from changes */ | |
2184 | + rtnl_lock(); | |
2185 | + switch (fib_work->event) { | |
2177 | 2186 | case FIB_EVENT_ENTRY_ADD: |
2178 | - err = rocker_world_fib4_add(rocker, fen_info); | |
2187 | + err = rocker_world_fib4_add(rocker, &fib_work->fen_info); | |
2179 | 2188 | if (err) |
2180 | 2189 | rocker_world_fib4_abort(rocker); |
2181 | - else | |
2190 | + fib_info_put(fib_work->fen_info.fi); | |
2182 | 2191 | break; |
2183 | 2192 | case FIB_EVENT_ENTRY_DEL: |
2184 | - rocker_world_fib4_del(rocker, fen_info); | |
2193 | + rocker_world_fib4_del(rocker, &fib_work->fen_info); | |
2194 | + fib_info_put(fib_work->fen_info.fi); | |
2185 | 2195 | break; |
2186 | 2196 | case FIB_EVENT_RULE_ADD: /* fall through */ |
2187 | 2197 | case FIB_EVENT_RULE_DEL: |
2188 | 2198 | rocker_world_fib4_abort(rocker); |
2189 | 2199 | break; |
2190 | 2200 | } |
2201 | + rtnl_unlock(); | |
2202 | + kfree(fib_work); | |
2203 | +} | |
2204 | + | |
2205 | +/* Called with rcu_read_lock() */ | |
2206 | +static int rocker_router_fib_event(struct notifier_block *nb, | |
2207 | + unsigned long event, void *ptr) | |
2208 | +{ | |
2209 | + struct rocker *rocker = container_of(nb, struct rocker, fib_nb); | |
2210 | + struct rocker_fib_event_work *fib_work; | |
2211 | + | |
2212 | + fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC); | |
2213 | + if (WARN_ON(!fib_work)) | |
2214 | + return NOTIFY_BAD; | |
2215 | + | |
2216 | + INIT_WORK(&fib_work->work, rocker_router_fib_event_work); | |
2217 | + fib_work->rocker = rocker; | |
2218 | + fib_work->event = event; | |
2219 | + | |
2220 | + switch (event) { | |
2221 | + case FIB_EVENT_ENTRY_ADD: /* fall through */ | |
2222 | + case FIB_EVENT_ENTRY_DEL: | |
2223 | + memcpy(&fib_work->fen_info, ptr, sizeof(fib_work->fen_info)); | |
2224 | + /* Take referece on fib_info to prevent it from being | |
2225 | + * freed while work is queued. Release it afterwards. | |
2226 | + */ | |
2227 | + fib_info_hold(fib_work->fen_info.fi); | |
2228 | + break; | |
2229 | + } | |
2230 | + | |
2231 | + queue_work(rocker->rocker_owq, &fib_work->work); | |
2232 | + | |
2191 | 2233 | return NOTIFY_DONE; |
2192 | 2234 | } |
2193 | 2235 |
drivers/net/ethernet/rocker/rocker_ofdpa.c