1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
3
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/rhashtable.h>
7 #include <linux/bitops.h>
8 #include <linux/in6.h>
9 #include <linux/notifier.h>
10 #include <linux/inetdevice.h>
11 #include <linux/netdevice.h>
12 #include <linux/if_bridge.h>
13 #include <linux/socket.h>
14 #include <linux/route.h>
15 #include <linux/gcd.h>
16 #include <linux/random.h>
17 #include <linux/if_macvlan.h>
18 #include <net/netevent.h>
19 #include <net/neighbour.h>
20 #include <net/arp.h>
21 #include <net/ip_fib.h>
22 #include <net/ip6_fib.h>
23 #include <net/fib_rules.h>
24 #include <net/ip_tunnels.h>
25 #include <net/l3mdev.h>
26 #include <net/addrconf.h>
27 #include <net/ndisc.h>
28 #include <net/ipv6.h>
29 #include <net/fib_notifier.h>
30 #include <net/switchdev.h>
31
32 #include "spectrum.h"
33 #include "core.h"
34 #include "reg.h"
35 #include "spectrum_cnt.h"
36 #include "spectrum_dpipe.h"
37 #include "spectrum_ipip.h"
38 #include "spectrum_mr.h"
39 #include "spectrum_mr_tcam.h"
40 #include "spectrum_router.h"
41 #include "spectrum_span.h"
42
43 struct mlxsw_sp_fib;
44 struct mlxsw_sp_vr;
45 struct mlxsw_sp_lpm_tree;
46 struct mlxsw_sp_rif_ops;
47
48 struct mlxsw_sp_router {
49 struct mlxsw_sp *mlxsw_sp;
50 struct mlxsw_sp_rif **rifs;
51 struct mlxsw_sp_vr *vrs;
52 struct rhashtable neigh_ht;
53 struct rhashtable nexthop_group_ht;
54 struct rhashtable nexthop_ht;
55 struct list_head nexthop_list;
56 struct {
57 /* One tree for each protocol: IPv4 and IPv6 */
58 struct mlxsw_sp_lpm_tree *proto_trees[2];
59 struct mlxsw_sp_lpm_tree *trees;
60 unsigned int tree_count;
61 } lpm;
62 struct {
63 struct delayed_work dw;
64 unsigned long interval; /* ms */
65 } neighs_update;
66 struct delayed_work nexthop_probe_dw;
67 #define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
68 struct list_head nexthop_neighs_list;
69 struct list_head ipip_list;
70 bool aborted;
71 struct notifier_block fib_nb;
72 struct notifier_block netevent_nb;
73 const struct mlxsw_sp_rif_ops **rif_ops_arr;
74 const struct mlxsw_sp_ipip_ops **ipip_ops_arr;
75 };
76
77 struct mlxsw_sp_rif {
78 struct list_head nexthop_list;
79 struct list_head neigh_list;
80 struct net_device *dev;
81 struct mlxsw_sp_fid *fid;
82 unsigned char addr[ETH_ALEN];
83 int mtu;
84 u16 rif_index;
85 u16 vr_id;
86 const struct mlxsw_sp_rif_ops *ops;
87 struct mlxsw_sp *mlxsw_sp;
88
89 unsigned int counter_ingress;
90 bool counter_ingress_valid;
91 unsigned int counter_egress;
92 bool counter_egress_valid;
93 };
94
95 struct mlxsw_sp_rif_params {
96 struct net_device *dev;
97 union {
98 u16 system_port;
99 u16 lag_id;
100 };
101 u16 vid;
102 bool lag;
103 };
104
105 struct mlxsw_sp_rif_subport {
106 struct mlxsw_sp_rif common;
107 union {
108 u16 system_port;
109 u16 lag_id;
110 };
111 u16 vid;
112 bool lag;
113 };
114
115 struct mlxsw_sp_rif_ipip_lb {
116 struct mlxsw_sp_rif common;
117 struct mlxsw_sp_rif_ipip_lb_config lb_config;
118 u16 ul_vr_id; /* Reserved for Spectrum-2. */
119 };
120
121 struct mlxsw_sp_rif_params_ipip_lb {
122 struct mlxsw_sp_rif_params common;
123 struct mlxsw_sp_rif_ipip_lb_config lb_config;
124 };
125
126 struct mlxsw_sp_rif_ops {
127 enum mlxsw_sp_rif_type type;
128 size_t rif_size;
129
130 void (*setup)(struct mlxsw_sp_rif *rif,
131 const struct mlxsw_sp_rif_params *params);
132 int (*configure)(struct mlxsw_sp_rif *rif);
133 void (*deconfigure)(struct mlxsw_sp_rif *rif);
134 struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif,
135 struct netlink_ext_ack *extack);
136 void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
137 };
138
139 static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree);
140 static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
141 struct mlxsw_sp_lpm_tree *lpm_tree);
142 static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
143 const struct mlxsw_sp_fib *fib,
144 u8 tree_id);
145 static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
146 const struct mlxsw_sp_fib *fib);
147
148 static unsigned int *
mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir)149 mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif,
150 enum mlxsw_sp_rif_counter_dir dir)
151 {
152 switch (dir) {
153 case MLXSW_SP_RIF_COUNTER_EGRESS:
154 return &rif->counter_egress;
155 case MLXSW_SP_RIF_COUNTER_INGRESS:
156 return &rif->counter_ingress;
157 }
158 return NULL;
159 }
160
161 static bool
mlxsw_sp_rif_counter_valid_get(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir)162 mlxsw_sp_rif_counter_valid_get(struct mlxsw_sp_rif *rif,
163 enum mlxsw_sp_rif_counter_dir dir)
164 {
165 switch (dir) {
166 case MLXSW_SP_RIF_COUNTER_EGRESS:
167 return rif->counter_egress_valid;
168 case MLXSW_SP_RIF_COUNTER_INGRESS:
169 return rif->counter_ingress_valid;
170 }
171 return false;
172 }
173
174 static void
mlxsw_sp_rif_counter_valid_set(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir,bool valid)175 mlxsw_sp_rif_counter_valid_set(struct mlxsw_sp_rif *rif,
176 enum mlxsw_sp_rif_counter_dir dir,
177 bool valid)
178 {
179 switch (dir) {
180 case MLXSW_SP_RIF_COUNTER_EGRESS:
181 rif->counter_egress_valid = valid;
182 break;
183 case MLXSW_SP_RIF_COUNTER_INGRESS:
184 rif->counter_ingress_valid = valid;
185 break;
186 }
187 }
188
mlxsw_sp_rif_counter_edit(struct mlxsw_sp * mlxsw_sp,u16 rif_index,unsigned int counter_index,bool enable,enum mlxsw_sp_rif_counter_dir dir)189 static int mlxsw_sp_rif_counter_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
190 unsigned int counter_index, bool enable,
191 enum mlxsw_sp_rif_counter_dir dir)
192 {
193 char ritr_pl[MLXSW_REG_RITR_LEN];
194 bool is_egress = false;
195 int err;
196
197 if (dir == MLXSW_SP_RIF_COUNTER_EGRESS)
198 is_egress = true;
199 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
200 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
201 if (err)
202 return err;
203
204 mlxsw_reg_ritr_counter_pack(ritr_pl, counter_index, enable,
205 is_egress);
206 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
207 }
208
mlxsw_sp_rif_counter_value_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir,u64 * cnt)209 int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp,
210 struct mlxsw_sp_rif *rif,
211 enum mlxsw_sp_rif_counter_dir dir, u64 *cnt)
212 {
213 char ricnt_pl[MLXSW_REG_RICNT_LEN];
214 unsigned int *p_counter_index;
215 bool valid;
216 int err;
217
218 valid = mlxsw_sp_rif_counter_valid_get(rif, dir);
219 if (!valid)
220 return -EINVAL;
221
222 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
223 if (!p_counter_index)
224 return -EINVAL;
225 mlxsw_reg_ricnt_pack(ricnt_pl, *p_counter_index,
226 MLXSW_REG_RICNT_OPCODE_NOP);
227 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ricnt), ricnt_pl);
228 if (err)
229 return err;
230 *cnt = mlxsw_reg_ricnt_good_unicast_packets_get(ricnt_pl);
231 return 0;
232 }
233
mlxsw_sp_rif_counter_clear(struct mlxsw_sp * mlxsw_sp,unsigned int counter_index)234 static int mlxsw_sp_rif_counter_clear(struct mlxsw_sp *mlxsw_sp,
235 unsigned int counter_index)
236 {
237 char ricnt_pl[MLXSW_REG_RICNT_LEN];
238
239 mlxsw_reg_ricnt_pack(ricnt_pl, counter_index,
240 MLXSW_REG_RICNT_OPCODE_CLEAR);
241 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ricnt), ricnt_pl);
242 }
243
mlxsw_sp_rif_counter_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir)244 int mlxsw_sp_rif_counter_alloc(struct mlxsw_sp *mlxsw_sp,
245 struct mlxsw_sp_rif *rif,
246 enum mlxsw_sp_rif_counter_dir dir)
247 {
248 unsigned int *p_counter_index;
249 int err;
250
251 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
252 if (!p_counter_index)
253 return -EINVAL;
254 err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
255 p_counter_index);
256 if (err)
257 return err;
258
259 err = mlxsw_sp_rif_counter_clear(mlxsw_sp, *p_counter_index);
260 if (err)
261 goto err_counter_clear;
262
263 err = mlxsw_sp_rif_counter_edit(mlxsw_sp, rif->rif_index,
264 *p_counter_index, true, dir);
265 if (err)
266 goto err_counter_edit;
267 mlxsw_sp_rif_counter_valid_set(rif, dir, true);
268 return 0;
269
270 err_counter_edit:
271 err_counter_clear:
272 mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
273 *p_counter_index);
274 return err;
275 }
276
mlxsw_sp_rif_counter_free(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir)277 void mlxsw_sp_rif_counter_free(struct mlxsw_sp *mlxsw_sp,
278 struct mlxsw_sp_rif *rif,
279 enum mlxsw_sp_rif_counter_dir dir)
280 {
281 unsigned int *p_counter_index;
282
283 if (!mlxsw_sp_rif_counter_valid_get(rif, dir))
284 return;
285
286 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
287 if (WARN_ON(!p_counter_index))
288 return;
289 mlxsw_sp_rif_counter_edit(mlxsw_sp, rif->rif_index,
290 *p_counter_index, false, dir);
291 mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
292 *p_counter_index);
293 mlxsw_sp_rif_counter_valid_set(rif, dir, false);
294 }
295
mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif * rif)296 static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif *rif)
297 {
298 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
299 struct devlink *devlink;
300
301 devlink = priv_to_devlink(mlxsw_sp->core);
302 if (!devlink_dpipe_table_counter_enabled(devlink,
303 MLXSW_SP_DPIPE_TABLE_NAME_ERIF))
304 return;
305 mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
306 }
307
mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif * rif)308 static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif *rif)
309 {
310 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
311
312 mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
313 }
314
315 #define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE + 1)
316
317 struct mlxsw_sp_prefix_usage {
318 DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
319 };
320
321 #define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
322 for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
323
324 static bool
mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage * prefix_usage1,struct mlxsw_sp_prefix_usage * prefix_usage2)325 mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage *prefix_usage1,
326 struct mlxsw_sp_prefix_usage *prefix_usage2)
327 {
328 return !memcmp(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
329 }
330
331 static void
mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage * prefix_usage1,struct mlxsw_sp_prefix_usage * prefix_usage2)332 mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1,
333 struct mlxsw_sp_prefix_usage *prefix_usage2)
334 {
335 memcpy(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
336 }
337
338 static void
mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage * prefix_usage,unsigned char prefix_len)339 mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage *prefix_usage,
340 unsigned char prefix_len)
341 {
342 set_bit(prefix_len, prefix_usage->b);
343 }
344
345 static void
mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage * prefix_usage,unsigned char prefix_len)346 mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage *prefix_usage,
347 unsigned char prefix_len)
348 {
349 clear_bit(prefix_len, prefix_usage->b);
350 }
351
352 struct mlxsw_sp_fib_key {
353 unsigned char addr[sizeof(struct in6_addr)];
354 unsigned char prefix_len;
355 };
356
357 enum mlxsw_sp_fib_entry_type {
358 MLXSW_SP_FIB_ENTRY_TYPE_REMOTE,
359 MLXSW_SP_FIB_ENTRY_TYPE_LOCAL,
360 MLXSW_SP_FIB_ENTRY_TYPE_TRAP,
361
362 /* This is a special case of local delivery, where a packet should be
363 * decapsulated on reception. Note that there is no corresponding ENCAP,
364 * because that's a type of next hop, not of FIB entry. (There can be
365 * several next hops in a REMOTE entry, and some of them may be
366 * encapsulating entries.)
367 */
368 MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP,
369 };
370
371 struct mlxsw_sp_nexthop_group;
372
373 struct mlxsw_sp_fib_node {
374 struct list_head entry_list;
375 struct list_head list;
376 struct rhash_head ht_node;
377 struct mlxsw_sp_fib *fib;
378 struct mlxsw_sp_fib_key key;
379 };
380
381 struct mlxsw_sp_fib_entry_decap {
382 struct mlxsw_sp_ipip_entry *ipip_entry;
383 u32 tunnel_index;
384 };
385
386 struct mlxsw_sp_fib_entry {
387 struct list_head list;
388 struct mlxsw_sp_fib_node *fib_node;
389 enum mlxsw_sp_fib_entry_type type;
390 struct list_head nexthop_group_node;
391 struct mlxsw_sp_nexthop_group *nh_group;
392 struct mlxsw_sp_fib_entry_decap decap; /* Valid for decap entries. */
393 };
394
395 struct mlxsw_sp_fib4_entry {
396 struct mlxsw_sp_fib_entry common;
397 u32 tb_id;
398 u32 prio;
399 u8 tos;
400 u8 type;
401 };
402
403 struct mlxsw_sp_fib6_entry {
404 struct mlxsw_sp_fib_entry common;
405 struct list_head rt6_list;
406 unsigned int nrt6;
407 };
408
409 struct mlxsw_sp_rt6 {
410 struct list_head list;
411 struct fib6_info *rt;
412 };
413
414 struct mlxsw_sp_lpm_tree {
415 u8 id; /* tree ID */
416 unsigned int ref_count;
417 enum mlxsw_sp_l3proto proto;
418 unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
419 struct mlxsw_sp_prefix_usage prefix_usage;
420 };
421
422 struct mlxsw_sp_fib {
423 struct rhashtable ht;
424 struct list_head node_list;
425 struct mlxsw_sp_vr *vr;
426 struct mlxsw_sp_lpm_tree *lpm_tree;
427 enum mlxsw_sp_l3proto proto;
428 };
429
430 struct mlxsw_sp_vr {
431 u16 id; /* virtual router ID */
432 u32 tb_id; /* kernel fib table id */
433 unsigned int rif_count;
434 struct mlxsw_sp_fib *fib4;
435 struct mlxsw_sp_fib *fib6;
436 struct mlxsw_sp_mr_table *mr_table[MLXSW_SP_L3_PROTO_MAX];
437 };
438
439 static const struct rhashtable_params mlxsw_sp_fib_ht_params;
440
mlxsw_sp_fib_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr,enum mlxsw_sp_l3proto proto)441 static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
442 struct mlxsw_sp_vr *vr,
443 enum mlxsw_sp_l3proto proto)
444 {
445 struct mlxsw_sp_lpm_tree *lpm_tree;
446 struct mlxsw_sp_fib *fib;
447 int err;
448
449 lpm_tree = mlxsw_sp->router->lpm.proto_trees[proto];
450 fib = kzalloc(sizeof(*fib), GFP_KERNEL);
451 if (!fib)
452 return ERR_PTR(-ENOMEM);
453 err = rhashtable_init(&fib->ht, &mlxsw_sp_fib_ht_params);
454 if (err)
455 goto err_rhashtable_init;
456 INIT_LIST_HEAD(&fib->node_list);
457 fib->proto = proto;
458 fib->vr = vr;
459 fib->lpm_tree = lpm_tree;
460 mlxsw_sp_lpm_tree_hold(lpm_tree);
461 err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, lpm_tree->id);
462 if (err)
463 goto err_lpm_tree_bind;
464 return fib;
465
466 err_lpm_tree_bind:
467 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
468 err_rhashtable_init:
469 kfree(fib);
470 return ERR_PTR(err);
471 }
472
mlxsw_sp_fib_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib * fib)473 static void mlxsw_sp_fib_destroy(struct mlxsw_sp *mlxsw_sp,
474 struct mlxsw_sp_fib *fib)
475 {
476 mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
477 mlxsw_sp_lpm_tree_put(mlxsw_sp, fib->lpm_tree);
478 WARN_ON(!list_empty(&fib->node_list));
479 rhashtable_destroy(&fib->ht);
480 kfree(fib);
481 }
482
483 static struct mlxsw_sp_lpm_tree *
mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp * mlxsw_sp)484 mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp)
485 {
486 static struct mlxsw_sp_lpm_tree *lpm_tree;
487 int i;
488
489 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
490 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
491 if (lpm_tree->ref_count == 0)
492 return lpm_tree;
493 }
494 return NULL;
495 }
496
mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_lpm_tree * lpm_tree)497 static int mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp *mlxsw_sp,
498 struct mlxsw_sp_lpm_tree *lpm_tree)
499 {
500 char ralta_pl[MLXSW_REG_RALTA_LEN];
501
502 mlxsw_reg_ralta_pack(ralta_pl, true,
503 (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
504 lpm_tree->id);
505 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
506 }
507
mlxsw_sp_lpm_tree_free(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_lpm_tree * lpm_tree)508 static void mlxsw_sp_lpm_tree_free(struct mlxsw_sp *mlxsw_sp,
509 struct mlxsw_sp_lpm_tree *lpm_tree)
510 {
511 char ralta_pl[MLXSW_REG_RALTA_LEN];
512
513 mlxsw_reg_ralta_pack(ralta_pl, false,
514 (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
515 lpm_tree->id);
516 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
517 }
518
519 static int
mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_prefix_usage * prefix_usage,struct mlxsw_sp_lpm_tree * lpm_tree)520 mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp *mlxsw_sp,
521 struct mlxsw_sp_prefix_usage *prefix_usage,
522 struct mlxsw_sp_lpm_tree *lpm_tree)
523 {
524 char ralst_pl[MLXSW_REG_RALST_LEN];
525 u8 root_bin = 0;
526 u8 prefix;
527 u8 last_prefix = MLXSW_REG_RALST_BIN_NO_CHILD;
528
529 mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage)
530 root_bin = prefix;
531
532 mlxsw_reg_ralst_pack(ralst_pl, root_bin, lpm_tree->id);
533 mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) {
534 if (prefix == 0)
535 continue;
536 mlxsw_reg_ralst_bin_pack(ralst_pl, prefix, last_prefix,
537 MLXSW_REG_RALST_BIN_NO_CHILD);
538 last_prefix = prefix;
539 }
540 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
541 }
542
543 static struct mlxsw_sp_lpm_tree *
mlxsw_sp_lpm_tree_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_prefix_usage * prefix_usage,enum mlxsw_sp_l3proto proto)544 mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
545 struct mlxsw_sp_prefix_usage *prefix_usage,
546 enum mlxsw_sp_l3proto proto)
547 {
548 struct mlxsw_sp_lpm_tree *lpm_tree;
549 int err;
550
551 lpm_tree = mlxsw_sp_lpm_tree_find_unused(mlxsw_sp);
552 if (!lpm_tree)
553 return ERR_PTR(-EBUSY);
554 lpm_tree->proto = proto;
555 err = mlxsw_sp_lpm_tree_alloc(mlxsw_sp, lpm_tree);
556 if (err)
557 return ERR_PTR(err);
558
559 err = mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp, prefix_usage,
560 lpm_tree);
561 if (err)
562 goto err_left_struct_set;
563 memcpy(&lpm_tree->prefix_usage, prefix_usage,
564 sizeof(lpm_tree->prefix_usage));
565 memset(&lpm_tree->prefix_ref_count, 0,
566 sizeof(lpm_tree->prefix_ref_count));
567 lpm_tree->ref_count = 1;
568 return lpm_tree;
569
570 err_left_struct_set:
571 mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
572 return ERR_PTR(err);
573 }
574
mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_lpm_tree * lpm_tree)575 static void mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp *mlxsw_sp,
576 struct mlxsw_sp_lpm_tree *lpm_tree)
577 {
578 mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
579 }
580
581 static struct mlxsw_sp_lpm_tree *
mlxsw_sp_lpm_tree_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_prefix_usage * prefix_usage,enum mlxsw_sp_l3proto proto)582 mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
583 struct mlxsw_sp_prefix_usage *prefix_usage,
584 enum mlxsw_sp_l3proto proto)
585 {
586 struct mlxsw_sp_lpm_tree *lpm_tree;
587 int i;
588
589 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
590 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
591 if (lpm_tree->ref_count != 0 &&
592 lpm_tree->proto == proto &&
593 mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
594 prefix_usage)) {
595 mlxsw_sp_lpm_tree_hold(lpm_tree);
596 return lpm_tree;
597 }
598 }
599 return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto);
600 }
601
mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree * lpm_tree)602 static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree)
603 {
604 lpm_tree->ref_count++;
605 }
606
mlxsw_sp_lpm_tree_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_lpm_tree * lpm_tree)607 static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
608 struct mlxsw_sp_lpm_tree *lpm_tree)
609 {
610 if (--lpm_tree->ref_count == 0)
611 mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree);
612 }
613
614 #define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */
615
mlxsw_sp_lpm_init(struct mlxsw_sp * mlxsw_sp)616 static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
617 {
618 struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } };
619 struct mlxsw_sp_lpm_tree *lpm_tree;
620 u64 max_trees;
621 int err, i;
622
623 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LPM_TREES))
624 return -EIO;
625
626 max_trees = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LPM_TREES);
627 mlxsw_sp->router->lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
628 mlxsw_sp->router->lpm.trees = kcalloc(mlxsw_sp->router->lpm.tree_count,
629 sizeof(struct mlxsw_sp_lpm_tree),
630 GFP_KERNEL);
631 if (!mlxsw_sp->router->lpm.trees)
632 return -ENOMEM;
633
634 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
635 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
636 lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
637 }
638
639 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
640 MLXSW_SP_L3_PROTO_IPV4);
641 if (IS_ERR(lpm_tree)) {
642 err = PTR_ERR(lpm_tree);
643 goto err_ipv4_tree_get;
644 }
645 mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4] = lpm_tree;
646
647 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
648 MLXSW_SP_L3_PROTO_IPV6);
649 if (IS_ERR(lpm_tree)) {
650 err = PTR_ERR(lpm_tree);
651 goto err_ipv6_tree_get;
652 }
653 mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6] = lpm_tree;
654
655 return 0;
656
657 err_ipv6_tree_get:
658 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
659 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
660 err_ipv4_tree_get:
661 kfree(mlxsw_sp->router->lpm.trees);
662 return err;
663 }
664
mlxsw_sp_lpm_fini(struct mlxsw_sp * mlxsw_sp)665 static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp)
666 {
667 struct mlxsw_sp_lpm_tree *lpm_tree;
668
669 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6];
670 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
671
672 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
673 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
674
675 kfree(mlxsw_sp->router->lpm.trees);
676 }
677
mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr * vr)678 static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr)
679 {
680 return !!vr->fib4 || !!vr->fib6 ||
681 !!vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] ||
682 !!vr->mr_table[MLXSW_SP_L3_PROTO_IPV6];
683 }
684
mlxsw_sp_vr_find_unused(struct mlxsw_sp * mlxsw_sp)685 static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
686 {
687 struct mlxsw_sp_vr *vr;
688 int i;
689
690 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
691 vr = &mlxsw_sp->router->vrs[i];
692 if (!mlxsw_sp_vr_is_used(vr))
693 return vr;
694 }
695 return NULL;
696 }
697
mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fib * fib,u8 tree_id)698 static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
699 const struct mlxsw_sp_fib *fib, u8 tree_id)
700 {
701 char raltb_pl[MLXSW_REG_RALTB_LEN];
702
703 mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
704 (enum mlxsw_reg_ralxx_protocol) fib->proto,
705 tree_id);
706 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
707 }
708
mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fib * fib)709 static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
710 const struct mlxsw_sp_fib *fib)
711 {
712 char raltb_pl[MLXSW_REG_RALTB_LEN];
713
714 /* Bind to tree 0 which is default */
715 mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
716 (enum mlxsw_reg_ralxx_protocol) fib->proto, 0);
717 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
718 }
719
mlxsw_sp_fix_tb_id(u32 tb_id)720 static u32 mlxsw_sp_fix_tb_id(u32 tb_id)
721 {
722 /* For our purpose, squash main, default and local tables into one */
723 if (tb_id == RT_TABLE_LOCAL || tb_id == RT_TABLE_DEFAULT)
724 tb_id = RT_TABLE_MAIN;
725 return tb_id;
726 }
727
mlxsw_sp_vr_find(struct mlxsw_sp * mlxsw_sp,u32 tb_id)728 static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
729 u32 tb_id)
730 {
731 struct mlxsw_sp_vr *vr;
732 int i;
733
734 tb_id = mlxsw_sp_fix_tb_id(tb_id);
735
736 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
737 vr = &mlxsw_sp->router->vrs[i];
738 if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id)
739 return vr;
740 }
741 return NULL;
742 }
743
mlxsw_sp_vr_fib(const struct mlxsw_sp_vr * vr,enum mlxsw_sp_l3proto proto)744 static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr,
745 enum mlxsw_sp_l3proto proto)
746 {
747 switch (proto) {
748 case MLXSW_SP_L3_PROTO_IPV4:
749 return vr->fib4;
750 case MLXSW_SP_L3_PROTO_IPV6:
751 return vr->fib6;
752 }
753 return NULL;
754 }
755
mlxsw_sp_vr_create(struct mlxsw_sp * mlxsw_sp,u32 tb_id,struct netlink_ext_ack * extack)756 static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
757 u32 tb_id,
758 struct netlink_ext_ack *extack)
759 {
760 struct mlxsw_sp_mr_table *mr4_table, *mr6_table;
761 struct mlxsw_sp_fib *fib4;
762 struct mlxsw_sp_fib *fib6;
763 struct mlxsw_sp_vr *vr;
764 int err;
765
766 vr = mlxsw_sp_vr_find_unused(mlxsw_sp);
767 if (!vr) {
768 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported virtual routers");
769 return ERR_PTR(-EBUSY);
770 }
771 fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
772 if (IS_ERR(fib4))
773 return ERR_CAST(fib4);
774 fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
775 if (IS_ERR(fib6)) {
776 err = PTR_ERR(fib6);
777 goto err_fib6_create;
778 }
779 mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
780 MLXSW_SP_L3_PROTO_IPV4);
781 if (IS_ERR(mr4_table)) {
782 err = PTR_ERR(mr4_table);
783 goto err_mr4_table_create;
784 }
785 mr6_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
786 MLXSW_SP_L3_PROTO_IPV6);
787 if (IS_ERR(mr6_table)) {
788 err = PTR_ERR(mr6_table);
789 goto err_mr6_table_create;
790 }
791
792 vr->fib4 = fib4;
793 vr->fib6 = fib6;
794 vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] = mr4_table;
795 vr->mr_table[MLXSW_SP_L3_PROTO_IPV6] = mr6_table;
796 vr->tb_id = tb_id;
797 return vr;
798
799 err_mr6_table_create:
800 mlxsw_sp_mr_table_destroy(mr4_table);
801 err_mr4_table_create:
802 mlxsw_sp_fib_destroy(mlxsw_sp, fib6);
803 err_fib6_create:
804 mlxsw_sp_fib_destroy(mlxsw_sp, fib4);
805 return ERR_PTR(err);
806 }
807
mlxsw_sp_vr_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr)808 static void mlxsw_sp_vr_destroy(struct mlxsw_sp *mlxsw_sp,
809 struct mlxsw_sp_vr *vr)
810 {
811 mlxsw_sp_mr_table_destroy(vr->mr_table[MLXSW_SP_L3_PROTO_IPV6]);
812 vr->mr_table[MLXSW_SP_L3_PROTO_IPV6] = NULL;
813 mlxsw_sp_mr_table_destroy(vr->mr_table[MLXSW_SP_L3_PROTO_IPV4]);
814 vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] = NULL;
815 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
816 vr->fib6 = NULL;
817 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
818 vr->fib4 = NULL;
819 }
820
mlxsw_sp_vr_get(struct mlxsw_sp * mlxsw_sp,u32 tb_id,struct netlink_ext_ack * extack)821 static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
822 struct netlink_ext_ack *extack)
823 {
824 struct mlxsw_sp_vr *vr;
825
826 tb_id = mlxsw_sp_fix_tb_id(tb_id);
827 vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
828 if (!vr)
829 vr = mlxsw_sp_vr_create(mlxsw_sp, tb_id, extack);
830 return vr;
831 }
832
mlxsw_sp_vr_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr)833 static void mlxsw_sp_vr_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr)
834 {
835 if (!vr->rif_count && list_empty(&vr->fib4->node_list) &&
836 list_empty(&vr->fib6->node_list) &&
837 mlxsw_sp_mr_table_empty(vr->mr_table[MLXSW_SP_L3_PROTO_IPV4]) &&
838 mlxsw_sp_mr_table_empty(vr->mr_table[MLXSW_SP_L3_PROTO_IPV6]))
839 mlxsw_sp_vr_destroy(mlxsw_sp, vr);
840 }
841
842 static bool
mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr * vr,enum mlxsw_sp_l3proto proto,u8 tree_id)843 mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr *vr,
844 enum mlxsw_sp_l3proto proto, u8 tree_id)
845 {
846 struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
847
848 if (!mlxsw_sp_vr_is_used(vr))
849 return false;
850 if (fib->lpm_tree->id == tree_id)
851 return true;
852 return false;
853 }
854
mlxsw_sp_vr_lpm_tree_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib * fib,struct mlxsw_sp_lpm_tree * new_tree)855 static int mlxsw_sp_vr_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
856 struct mlxsw_sp_fib *fib,
857 struct mlxsw_sp_lpm_tree *new_tree)
858 {
859 struct mlxsw_sp_lpm_tree *old_tree = fib->lpm_tree;
860 int err;
861
862 fib->lpm_tree = new_tree;
863 mlxsw_sp_lpm_tree_hold(new_tree);
864 err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, new_tree->id);
865 if (err)
866 goto err_tree_bind;
867 mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
868 return 0;
869
870 err_tree_bind:
871 mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree);
872 fib->lpm_tree = old_tree;
873 return err;
874 }
875
mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib * fib,struct mlxsw_sp_lpm_tree * new_tree)876 static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
877 struct mlxsw_sp_fib *fib,
878 struct mlxsw_sp_lpm_tree *new_tree)
879 {
880 enum mlxsw_sp_l3proto proto = fib->proto;
881 struct mlxsw_sp_lpm_tree *old_tree;
882 u8 old_id, new_id = new_tree->id;
883 struct mlxsw_sp_vr *vr;
884 int i, err;
885
886 old_tree = mlxsw_sp->router->lpm.proto_trees[proto];
887 old_id = old_tree->id;
888
889 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
890 vr = &mlxsw_sp->router->vrs[i];
891 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, old_id))
892 continue;
893 err = mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
894 mlxsw_sp_vr_fib(vr, proto),
895 new_tree);
896 if (err)
897 goto err_tree_replace;
898 }
899
900 memcpy(new_tree->prefix_ref_count, old_tree->prefix_ref_count,
901 sizeof(new_tree->prefix_ref_count));
902 mlxsw_sp->router->lpm.proto_trees[proto] = new_tree;
903 mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
904
905 return 0;
906
907 err_tree_replace:
908 for (i--; i >= 0; i--) {
909 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, new_id))
910 continue;
911 mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
912 mlxsw_sp_vr_fib(vr, proto),
913 old_tree);
914 }
915 return err;
916 }
917
mlxsw_sp_vrs_init(struct mlxsw_sp * mlxsw_sp)918 static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
919 {
920 struct mlxsw_sp_vr *vr;
921 u64 max_vrs;
922 int i;
923
924 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_VRS))
925 return -EIO;
926
927 max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
928 mlxsw_sp->router->vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr),
929 GFP_KERNEL);
930 if (!mlxsw_sp->router->vrs)
931 return -ENOMEM;
932
933 for (i = 0; i < max_vrs; i++) {
934 vr = &mlxsw_sp->router->vrs[i];
935 vr->id = i;
936 }
937
938 return 0;
939 }
940
941 static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp);
942
mlxsw_sp_vrs_fini(struct mlxsw_sp * mlxsw_sp)943 static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
944 {
945 /* At this stage we're guaranteed not to have new incoming
946 * FIB notifications and the work queue is free from FIBs
947 * sitting on top of mlxsw netdevs. However, we can still
948 * have other FIBs queued. Flush the queue before flushing
949 * the device's tables. No need for locks, as we're the only
950 * writer.
951 */
952 mlxsw_core_flush_owq();
953 mlxsw_sp_router_fib_flush(mlxsw_sp);
954 kfree(mlxsw_sp->router->vrs);
955 }
956
957 static struct net_device *
__mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device * ol_dev)958 __mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev)
959 {
960 struct ip_tunnel *tun = netdev_priv(ol_dev);
961 struct net *net = dev_net(ol_dev);
962
963 return __dev_get_by_index(net, tun->parms.link);
964 }
965
mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device * ol_dev)966 u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev)
967 {
968 struct net_device *d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
969
970 if (d)
971 return l3mdev_fib_table(d) ? : RT_TABLE_MAIN;
972 else
973 return RT_TABLE_MAIN;
974 }
975
976 static struct mlxsw_sp_rif *
977 mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
978 const struct mlxsw_sp_rif_params *params,
979 struct netlink_ext_ack *extack);
980
981 static struct mlxsw_sp_rif_ipip_lb *
mlxsw_sp_ipip_ol_ipip_lb_create(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_ipip_type ipipt,struct net_device * ol_dev,struct netlink_ext_ack * extack)982 mlxsw_sp_ipip_ol_ipip_lb_create(struct mlxsw_sp *mlxsw_sp,
983 enum mlxsw_sp_ipip_type ipipt,
984 struct net_device *ol_dev,
985 struct netlink_ext_ack *extack)
986 {
987 struct mlxsw_sp_rif_params_ipip_lb lb_params;
988 const struct mlxsw_sp_ipip_ops *ipip_ops;
989 struct mlxsw_sp_rif *rif;
990
991 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
992 lb_params = (struct mlxsw_sp_rif_params_ipip_lb) {
993 .common.dev = ol_dev,
994 .common.lag = false,
995 .lb_config = ipip_ops->ol_loopback_config(mlxsw_sp, ol_dev),
996 };
997
998 rif = mlxsw_sp_rif_create(mlxsw_sp, &lb_params.common, extack);
999 if (IS_ERR(rif))
1000 return ERR_CAST(rif);
1001 return container_of(rif, struct mlxsw_sp_rif_ipip_lb, common);
1002 }
1003
1004 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_ipip_type ipipt,struct net_device * ol_dev)1005 mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp *mlxsw_sp,
1006 enum mlxsw_sp_ipip_type ipipt,
1007 struct net_device *ol_dev)
1008 {
1009 const struct mlxsw_sp_ipip_ops *ipip_ops;
1010 struct mlxsw_sp_ipip_entry *ipip_entry;
1011 struct mlxsw_sp_ipip_entry *ret = NULL;
1012
1013 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
1014 ipip_entry = kzalloc(sizeof(*ipip_entry), GFP_KERNEL);
1015 if (!ipip_entry)
1016 return ERR_PTR(-ENOMEM);
1017
1018 ipip_entry->ol_lb = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp, ipipt,
1019 ol_dev, NULL);
1020 if (IS_ERR(ipip_entry->ol_lb)) {
1021 ret = ERR_CAST(ipip_entry->ol_lb);
1022 goto err_ol_ipip_lb_create;
1023 }
1024
1025 ipip_entry->ipipt = ipipt;
1026 ipip_entry->ol_dev = ol_dev;
1027
1028 switch (ipip_ops->ul_proto) {
1029 case MLXSW_SP_L3_PROTO_IPV4:
1030 ipip_entry->parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
1031 break;
1032 case MLXSW_SP_L3_PROTO_IPV6:
1033 WARN_ON(1);
1034 break;
1035 }
1036
1037 return ipip_entry;
1038
1039 err_ol_ipip_lb_create:
1040 kfree(ipip_entry);
1041 return ret;
1042 }
1043
1044 static void
mlxsw_sp_ipip_entry_dealloc(struct mlxsw_sp_ipip_entry * ipip_entry)1045 mlxsw_sp_ipip_entry_dealloc(struct mlxsw_sp_ipip_entry *ipip_entry)
1046 {
1047 mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
1048 kfree(ipip_entry);
1049 }
1050
1051 static bool
mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp * mlxsw_sp,const enum mlxsw_sp_l3proto ul_proto,union mlxsw_sp_l3addr saddr,u32 ul_tb_id,struct mlxsw_sp_ipip_entry * ipip_entry)1052 mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp *mlxsw_sp,
1053 const enum mlxsw_sp_l3proto ul_proto,
1054 union mlxsw_sp_l3addr saddr,
1055 u32 ul_tb_id,
1056 struct mlxsw_sp_ipip_entry *ipip_entry)
1057 {
1058 u32 tun_ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
1059 enum mlxsw_sp_ipip_type ipipt = ipip_entry->ipipt;
1060 union mlxsw_sp_l3addr tun_saddr;
1061
1062 if (mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto != ul_proto)
1063 return false;
1064
1065 tun_saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev);
1066 return tun_ul_tb_id == ul_tb_id &&
1067 mlxsw_sp_l3addr_eq(&tun_saddr, &saddr);
1068 }
1069
1070 static int
mlxsw_sp_fib_entry_decap_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,struct mlxsw_sp_ipip_entry * ipip_entry)1071 mlxsw_sp_fib_entry_decap_init(struct mlxsw_sp *mlxsw_sp,
1072 struct mlxsw_sp_fib_entry *fib_entry,
1073 struct mlxsw_sp_ipip_entry *ipip_entry)
1074 {
1075 u32 tunnel_index;
1076 int err;
1077
1078 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
1079 1, &tunnel_index);
1080 if (err)
1081 return err;
1082
1083 ipip_entry->decap_fib_entry = fib_entry;
1084 fib_entry->decap.ipip_entry = ipip_entry;
1085 fib_entry->decap.tunnel_index = tunnel_index;
1086 return 0;
1087 }
1088
mlxsw_sp_fib_entry_decap_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)1089 static void mlxsw_sp_fib_entry_decap_fini(struct mlxsw_sp *mlxsw_sp,
1090 struct mlxsw_sp_fib_entry *fib_entry)
1091 {
1092 /* Unlink this node from the IPIP entry that it's the decap entry of. */
1093 fib_entry->decap.ipip_entry->decap_fib_entry = NULL;
1094 fib_entry->decap.ipip_entry = NULL;
1095 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
1096 1, fib_entry->decap.tunnel_index);
1097 }
1098
1099 static struct mlxsw_sp_fib_node *
1100 mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
1101 size_t addr_len, unsigned char prefix_len);
1102 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
1103 struct mlxsw_sp_fib_entry *fib_entry);
1104
1105 static void
mlxsw_sp_ipip_entry_demote_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1106 mlxsw_sp_ipip_entry_demote_decap(struct mlxsw_sp *mlxsw_sp,
1107 struct mlxsw_sp_ipip_entry *ipip_entry)
1108 {
1109 struct mlxsw_sp_fib_entry *fib_entry = ipip_entry->decap_fib_entry;
1110
1111 mlxsw_sp_fib_entry_decap_fini(mlxsw_sp, fib_entry);
1112 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
1113
1114 mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
1115 }
1116
1117 static void
mlxsw_sp_ipip_entry_promote_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct mlxsw_sp_fib_entry * decap_fib_entry)1118 mlxsw_sp_ipip_entry_promote_decap(struct mlxsw_sp *mlxsw_sp,
1119 struct mlxsw_sp_ipip_entry *ipip_entry,
1120 struct mlxsw_sp_fib_entry *decap_fib_entry)
1121 {
1122 if (mlxsw_sp_fib_entry_decap_init(mlxsw_sp, decap_fib_entry,
1123 ipip_entry))
1124 return;
1125 decap_fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
1126
1127 if (mlxsw_sp_fib_entry_update(mlxsw_sp, decap_fib_entry))
1128 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1129 }
1130
1131 /* Given an IPIP entry, find the corresponding decap route. */
1132 static struct mlxsw_sp_fib_entry *
mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1133 mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp,
1134 struct mlxsw_sp_ipip_entry *ipip_entry)
1135 {
1136 static struct mlxsw_sp_fib_node *fib_node;
1137 const struct mlxsw_sp_ipip_ops *ipip_ops;
1138 struct mlxsw_sp_fib_entry *fib_entry;
1139 unsigned char saddr_prefix_len;
1140 union mlxsw_sp_l3addr saddr;
1141 struct mlxsw_sp_fib *ul_fib;
1142 struct mlxsw_sp_vr *ul_vr;
1143 const void *saddrp;
1144 size_t saddr_len;
1145 u32 ul_tb_id;
1146 u32 saddr4;
1147
1148 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
1149
1150 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
1151 ul_vr = mlxsw_sp_vr_find(mlxsw_sp, ul_tb_id);
1152 if (!ul_vr)
1153 return NULL;
1154
1155 ul_fib = mlxsw_sp_vr_fib(ul_vr, ipip_ops->ul_proto);
1156 saddr = mlxsw_sp_ipip_netdev_saddr(ipip_ops->ul_proto,
1157 ipip_entry->ol_dev);
1158
1159 switch (ipip_ops->ul_proto) {
1160 case MLXSW_SP_L3_PROTO_IPV4:
1161 saddr4 = be32_to_cpu(saddr.addr4);
1162 saddrp = &saddr4;
1163 saddr_len = 4;
1164 saddr_prefix_len = 32;
1165 break;
1166 case MLXSW_SP_L3_PROTO_IPV6:
1167 WARN_ON(1);
1168 return NULL;
1169 }
1170
1171 fib_node = mlxsw_sp_fib_node_lookup(ul_fib, saddrp, saddr_len,
1172 saddr_prefix_len);
1173 if (!fib_node || list_empty(&fib_node->entry_list))
1174 return NULL;
1175
1176 fib_entry = list_first_entry(&fib_node->entry_list,
1177 struct mlxsw_sp_fib_entry, list);
1178 if (fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP)
1179 return NULL;
1180
1181 return fib_entry;
1182 }
1183
1184 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_create(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_ipip_type ipipt,struct net_device * ol_dev)1185 mlxsw_sp_ipip_entry_create(struct mlxsw_sp *mlxsw_sp,
1186 enum mlxsw_sp_ipip_type ipipt,
1187 struct net_device *ol_dev)
1188 {
1189 struct mlxsw_sp_ipip_entry *ipip_entry;
1190
1191 ipip_entry = mlxsw_sp_ipip_entry_alloc(mlxsw_sp, ipipt, ol_dev);
1192 if (IS_ERR(ipip_entry))
1193 return ipip_entry;
1194
1195 list_add_tail(&ipip_entry->ipip_list_node,
1196 &mlxsw_sp->router->ipip_list);
1197
1198 return ipip_entry;
1199 }
1200
1201 static void
mlxsw_sp_ipip_entry_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1202 mlxsw_sp_ipip_entry_destroy(struct mlxsw_sp *mlxsw_sp,
1203 struct mlxsw_sp_ipip_entry *ipip_entry)
1204 {
1205 list_del(&ipip_entry->ipip_list_node);
1206 mlxsw_sp_ipip_entry_dealloc(ipip_entry);
1207 }
1208
1209 static bool
mlxsw_sp_ipip_entry_matches_decap(struct mlxsw_sp * mlxsw_sp,const struct net_device * ul_dev,enum mlxsw_sp_l3proto ul_proto,union mlxsw_sp_l3addr ul_dip,struct mlxsw_sp_ipip_entry * ipip_entry)1210 mlxsw_sp_ipip_entry_matches_decap(struct mlxsw_sp *mlxsw_sp,
1211 const struct net_device *ul_dev,
1212 enum mlxsw_sp_l3proto ul_proto,
1213 union mlxsw_sp_l3addr ul_dip,
1214 struct mlxsw_sp_ipip_entry *ipip_entry)
1215 {
1216 u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN;
1217 enum mlxsw_sp_ipip_type ipipt = ipip_entry->ipipt;
1218
1219 if (mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto != ul_proto)
1220 return false;
1221
1222 return mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp, ul_proto, ul_dip,
1223 ul_tb_id, ipip_entry);
1224 }
1225
1226 /* Given decap parameters, find the corresponding IPIP entry. */
1227 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_find_by_decap(struct mlxsw_sp * mlxsw_sp,const struct net_device * ul_dev,enum mlxsw_sp_l3proto ul_proto,union mlxsw_sp_l3addr ul_dip)1228 mlxsw_sp_ipip_entry_find_by_decap(struct mlxsw_sp *mlxsw_sp,
1229 const struct net_device *ul_dev,
1230 enum mlxsw_sp_l3proto ul_proto,
1231 union mlxsw_sp_l3addr ul_dip)
1232 {
1233 struct mlxsw_sp_ipip_entry *ipip_entry;
1234
1235 list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
1236 ipip_list_node)
1237 if (mlxsw_sp_ipip_entry_matches_decap(mlxsw_sp, ul_dev,
1238 ul_proto, ul_dip,
1239 ipip_entry))
1240 return ipip_entry;
1241
1242 return NULL;
1243 }
1244
mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev,enum mlxsw_sp_ipip_type * p_type)1245 static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp *mlxsw_sp,
1246 const struct net_device *dev,
1247 enum mlxsw_sp_ipip_type *p_type)
1248 {
1249 struct mlxsw_sp_router *router = mlxsw_sp->router;
1250 const struct mlxsw_sp_ipip_ops *ipip_ops;
1251 enum mlxsw_sp_ipip_type ipipt;
1252
1253 for (ipipt = 0; ipipt < MLXSW_SP_IPIP_TYPE_MAX; ++ipipt) {
1254 ipip_ops = router->ipip_ops_arr[ipipt];
1255 if (dev->type == ipip_ops->dev_type) {
1256 if (p_type)
1257 *p_type = ipipt;
1258 return true;
1259 }
1260 }
1261 return false;
1262 }
1263
mlxsw_sp_netdev_is_ipip_ol(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev)1264 bool mlxsw_sp_netdev_is_ipip_ol(const struct mlxsw_sp *mlxsw_sp,
1265 const struct net_device *dev)
1266 {
1267 return mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL);
1268 }
1269
1270 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_find_by_ol_dev(struct mlxsw_sp * mlxsw_sp,const struct net_device * ol_dev)1271 mlxsw_sp_ipip_entry_find_by_ol_dev(struct mlxsw_sp *mlxsw_sp,
1272 const struct net_device *ol_dev)
1273 {
1274 struct mlxsw_sp_ipip_entry *ipip_entry;
1275
1276 list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
1277 ipip_list_node)
1278 if (ipip_entry->ol_dev == ol_dev)
1279 return ipip_entry;
1280
1281 return NULL;
1282 }
1283
1284 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp * mlxsw_sp,const struct net_device * ul_dev,struct mlxsw_sp_ipip_entry * start)1285 mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp *mlxsw_sp,
1286 const struct net_device *ul_dev,
1287 struct mlxsw_sp_ipip_entry *start)
1288 {
1289 struct mlxsw_sp_ipip_entry *ipip_entry;
1290
1291 ipip_entry = list_prepare_entry(start, &mlxsw_sp->router->ipip_list,
1292 ipip_list_node);
1293 list_for_each_entry_continue(ipip_entry, &mlxsw_sp->router->ipip_list,
1294 ipip_list_node) {
1295 struct net_device *ipip_ul_dev =
1296 __mlxsw_sp_ipip_netdev_ul_dev_get(ipip_entry->ol_dev);
1297
1298 if (ipip_ul_dev == ul_dev)
1299 return ipip_entry;
1300 }
1301
1302 return NULL;
1303 }
1304
mlxsw_sp_netdev_is_ipip_ul(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev)1305 bool mlxsw_sp_netdev_is_ipip_ul(const struct mlxsw_sp *mlxsw_sp,
1306 const struct net_device *dev)
1307 {
1308 return mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL);
1309 }
1310
mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp * mlxsw_sp,const struct net_device * ol_dev,enum mlxsw_sp_ipip_type ipipt)1311 static bool mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp *mlxsw_sp,
1312 const struct net_device *ol_dev,
1313 enum mlxsw_sp_ipip_type ipipt)
1314 {
1315 const struct mlxsw_sp_ipip_ops *ops
1316 = mlxsw_sp->router->ipip_ops_arr[ipipt];
1317
1318 /* For deciding whether decap should be offloaded, we don't care about
1319 * overlay protocol, so ask whether either one is supported.
1320 */
1321 return ops->can_offload(mlxsw_sp, ol_dev, MLXSW_SP_L3_PROTO_IPV4) ||
1322 ops->can_offload(mlxsw_sp, ol_dev, MLXSW_SP_L3_PROTO_IPV6);
1323 }
1324
mlxsw_sp_netdevice_ipip_ol_reg_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1325 static int mlxsw_sp_netdevice_ipip_ol_reg_event(struct mlxsw_sp *mlxsw_sp,
1326 struct net_device *ol_dev)
1327 {
1328 struct mlxsw_sp_ipip_entry *ipip_entry;
1329 enum mlxsw_sp_l3proto ul_proto;
1330 enum mlxsw_sp_ipip_type ipipt;
1331 union mlxsw_sp_l3addr saddr;
1332 u32 ul_tb_id;
1333
1334 mlxsw_sp_netdev_ipip_type(mlxsw_sp, ol_dev, &ipipt);
1335 if (mlxsw_sp_netdevice_ipip_can_offload(mlxsw_sp, ol_dev, ipipt)) {
1336 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);
1337 ul_proto = mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto;
1338 saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ol_dev);
1339 if (!mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto,
1340 saddr, ul_tb_id,
1341 NULL)) {
1342 ipip_entry = mlxsw_sp_ipip_entry_create(mlxsw_sp, ipipt,
1343 ol_dev);
1344 if (IS_ERR(ipip_entry))
1345 return PTR_ERR(ipip_entry);
1346 }
1347 }
1348
1349 return 0;
1350 }
1351
mlxsw_sp_netdevice_ipip_ol_unreg_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1352 static void mlxsw_sp_netdevice_ipip_ol_unreg_event(struct mlxsw_sp *mlxsw_sp,
1353 struct net_device *ol_dev)
1354 {
1355 struct mlxsw_sp_ipip_entry *ipip_entry;
1356
1357 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1358 if (ipip_entry)
1359 mlxsw_sp_ipip_entry_destroy(mlxsw_sp, ipip_entry);
1360 }
1361
1362 static void
mlxsw_sp_ipip_entry_ol_up_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1363 mlxsw_sp_ipip_entry_ol_up_event(struct mlxsw_sp *mlxsw_sp,
1364 struct mlxsw_sp_ipip_entry *ipip_entry)
1365 {
1366 struct mlxsw_sp_fib_entry *decap_fib_entry;
1367
1368 decap_fib_entry = mlxsw_sp_ipip_entry_find_decap(mlxsw_sp, ipip_entry);
1369 if (decap_fib_entry)
1370 mlxsw_sp_ipip_entry_promote_decap(mlxsw_sp, ipip_entry,
1371 decap_fib_entry);
1372 }
1373
1374 static int
mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb * lb_rif,struct mlxsw_sp_vr * ul_vr,bool enable)1375 mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif,
1376 struct mlxsw_sp_vr *ul_vr, bool enable)
1377 {
1378 struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config;
1379 struct mlxsw_sp_rif *rif = &lb_rif->common;
1380 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
1381 char ritr_pl[MLXSW_REG_RITR_LEN];
1382 u32 saddr4;
1383
1384 switch (lb_cf.ul_protocol) {
1385 case MLXSW_SP_L3_PROTO_IPV4:
1386 saddr4 = be32_to_cpu(lb_cf.saddr.addr4);
1387 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
1388 rif->rif_index, rif->vr_id, rif->dev->mtu);
1389 mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt,
1390 MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET,
1391 ul_vr->id, saddr4, lb_cf.okey);
1392 break;
1393
1394 case MLXSW_SP_L3_PROTO_IPV6:
1395 return -EAFNOSUPPORT;
1396 }
1397
1398 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
1399 }
1400
mlxsw_sp_netdevice_ipip_ol_update_mtu(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1401 static int mlxsw_sp_netdevice_ipip_ol_update_mtu(struct mlxsw_sp *mlxsw_sp,
1402 struct net_device *ol_dev)
1403 {
1404 struct mlxsw_sp_ipip_entry *ipip_entry;
1405 struct mlxsw_sp_rif_ipip_lb *lb_rif;
1406 struct mlxsw_sp_vr *ul_vr;
1407 int err = 0;
1408
1409 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1410 if (ipip_entry) {
1411 lb_rif = ipip_entry->ol_lb;
1412 ul_vr = &mlxsw_sp->router->vrs[lb_rif->ul_vr_id];
1413 err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, true);
1414 if (err)
1415 goto out;
1416 lb_rif->common.mtu = ol_dev->mtu;
1417 }
1418
1419 out:
1420 return err;
1421 }
1422
mlxsw_sp_netdevice_ipip_ol_up_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1423 static void mlxsw_sp_netdevice_ipip_ol_up_event(struct mlxsw_sp *mlxsw_sp,
1424 struct net_device *ol_dev)
1425 {
1426 struct mlxsw_sp_ipip_entry *ipip_entry;
1427
1428 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1429 if (ipip_entry)
1430 mlxsw_sp_ipip_entry_ol_up_event(mlxsw_sp, ipip_entry);
1431 }
1432
1433 static void
mlxsw_sp_ipip_entry_ol_down_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1434 mlxsw_sp_ipip_entry_ol_down_event(struct mlxsw_sp *mlxsw_sp,
1435 struct mlxsw_sp_ipip_entry *ipip_entry)
1436 {
1437 if (ipip_entry->decap_fib_entry)
1438 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1439 }
1440
mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1441 static void mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp *mlxsw_sp,
1442 struct net_device *ol_dev)
1443 {
1444 struct mlxsw_sp_ipip_entry *ipip_entry;
1445
1446 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1447 if (ipip_entry)
1448 mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry);
1449 }
1450
1451 static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp,
1452 struct mlxsw_sp_rif *old_rif,
1453 struct mlxsw_sp_rif *new_rif);
1454 static int
mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,bool keep_encap,struct netlink_ext_ack * extack)1455 mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp,
1456 struct mlxsw_sp_ipip_entry *ipip_entry,
1457 bool keep_encap,
1458 struct netlink_ext_ack *extack)
1459 {
1460 struct mlxsw_sp_rif_ipip_lb *old_lb_rif = ipip_entry->ol_lb;
1461 struct mlxsw_sp_rif_ipip_lb *new_lb_rif;
1462
1463 new_lb_rif = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp,
1464 ipip_entry->ipipt,
1465 ipip_entry->ol_dev,
1466 extack);
1467 if (IS_ERR(new_lb_rif))
1468 return PTR_ERR(new_lb_rif);
1469 ipip_entry->ol_lb = new_lb_rif;
1470
1471 if (keep_encap)
1472 mlxsw_sp_nexthop_rif_migrate(mlxsw_sp, &old_lb_rif->common,
1473 &new_lb_rif->common);
1474
1475 mlxsw_sp_rif_destroy(&old_lb_rif->common);
1476
1477 return 0;
1478 }
1479
1480 static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
1481 struct mlxsw_sp_rif *rif);
1482
1483 /**
1484 * Update the offload related to an IPIP entry. This always updates decap, and
1485 * in addition to that it also:
1486 * @recreate_loopback: recreates the associated loopback RIF
1487 * @keep_encap: updates next hops that use the tunnel netdevice. This is only
1488 * relevant when recreate_loopback is true.
1489 * @update_nexthops: updates next hops, keeping the current loopback RIF. This
1490 * is only relevant when recreate_loopback is false.
1491 */
__mlxsw_sp_ipip_entry_update_tunnel(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,bool recreate_loopback,bool keep_encap,bool update_nexthops,struct netlink_ext_ack * extack)1492 int __mlxsw_sp_ipip_entry_update_tunnel(struct mlxsw_sp *mlxsw_sp,
1493 struct mlxsw_sp_ipip_entry *ipip_entry,
1494 bool recreate_loopback,
1495 bool keep_encap,
1496 bool update_nexthops,
1497 struct netlink_ext_ack *extack)
1498 {
1499 int err;
1500
1501 /* RIFs can't be edited, so to update loopback, we need to destroy and
1502 * recreate it. That creates a window of opportunity where RALUE and
1503 * RATR registers end up referencing a RIF that's already gone. RATRs
1504 * are handled in mlxsw_sp_ipip_entry_ol_lb_update(), and to take care
1505 * of RALUE, demote the decap route back.
1506 */
1507 if (ipip_entry->decap_fib_entry)
1508 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1509
1510 if (recreate_loopback) {
1511 err = mlxsw_sp_ipip_entry_ol_lb_update(mlxsw_sp, ipip_entry,
1512 keep_encap, extack);
1513 if (err)
1514 return err;
1515 } else if (update_nexthops) {
1516 mlxsw_sp_nexthop_rif_update(mlxsw_sp,
1517 &ipip_entry->ol_lb->common);
1518 }
1519
1520 if (ipip_entry->ol_dev->flags & IFF_UP)
1521 mlxsw_sp_ipip_entry_ol_up_event(mlxsw_sp, ipip_entry);
1522
1523 return 0;
1524 }
1525
mlxsw_sp_netdevice_ipip_ol_vrf_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev,struct netlink_ext_ack * extack)1526 static int mlxsw_sp_netdevice_ipip_ol_vrf_event(struct mlxsw_sp *mlxsw_sp,
1527 struct net_device *ol_dev,
1528 struct netlink_ext_ack *extack)
1529 {
1530 struct mlxsw_sp_ipip_entry *ipip_entry =
1531 mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1532
1533 if (!ipip_entry)
1534 return 0;
1535
1536 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1537 true, false, false, extack);
1538 }
1539
1540 static int
mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct net_device * ul_dev,struct netlink_ext_ack * extack)1541 mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp,
1542 struct mlxsw_sp_ipip_entry *ipip_entry,
1543 struct net_device *ul_dev,
1544 struct netlink_ext_ack *extack)
1545 {
1546 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1547 true, true, false, extack);
1548 }
1549
1550 static int
mlxsw_sp_netdevice_ipip_ul_up_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct net_device * ul_dev)1551 mlxsw_sp_netdevice_ipip_ul_up_event(struct mlxsw_sp *mlxsw_sp,
1552 struct mlxsw_sp_ipip_entry *ipip_entry,
1553 struct net_device *ul_dev)
1554 {
1555 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1556 false, false, true, NULL);
1557 }
1558
1559 static int
mlxsw_sp_netdevice_ipip_ul_down_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct net_device * ul_dev)1560 mlxsw_sp_netdevice_ipip_ul_down_event(struct mlxsw_sp *mlxsw_sp,
1561 struct mlxsw_sp_ipip_entry *ipip_entry,
1562 struct net_device *ul_dev)
1563 {
1564 /* A down underlay device causes encapsulated packets to not be
1565 * forwarded, but decap still works. So refresh next hops without
1566 * touching anything else.
1567 */
1568 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1569 false, false, true, NULL);
1570 }
1571
1572 static int
mlxsw_sp_netdevice_ipip_ol_change_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev,struct netlink_ext_ack * extack)1573 mlxsw_sp_netdevice_ipip_ol_change_event(struct mlxsw_sp *mlxsw_sp,
1574 struct net_device *ol_dev,
1575 struct netlink_ext_ack *extack)
1576 {
1577 const struct mlxsw_sp_ipip_ops *ipip_ops;
1578 struct mlxsw_sp_ipip_entry *ipip_entry;
1579 int err;
1580
1581 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1582 if (!ipip_entry)
1583 /* A change might make a tunnel eligible for offloading, but
1584 * that is currently not implemented. What falls to slow path
1585 * stays there.
1586 */
1587 return 0;
1588
1589 /* A change might make a tunnel not eligible for offloading. */
1590 if (!mlxsw_sp_netdevice_ipip_can_offload(mlxsw_sp, ol_dev,
1591 ipip_entry->ipipt)) {
1592 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1593 return 0;
1594 }
1595
1596 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
1597 err = ipip_ops->ol_netdev_change(mlxsw_sp, ipip_entry, extack);
1598 return err;
1599 }
1600
mlxsw_sp_ipip_entry_demote_tunnel(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1601 void mlxsw_sp_ipip_entry_demote_tunnel(struct mlxsw_sp *mlxsw_sp,
1602 struct mlxsw_sp_ipip_entry *ipip_entry)
1603 {
1604 struct net_device *ol_dev = ipip_entry->ol_dev;
1605
1606 if (ol_dev->flags & IFF_UP)
1607 mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry);
1608 mlxsw_sp_ipip_entry_destroy(mlxsw_sp, ipip_entry);
1609 }
1610
1611 /* The configuration where several tunnels have the same local address in the
1612 * same underlay table needs special treatment in the HW. That is currently not
1613 * implemented in the driver. This function finds and demotes the first tunnel
1614 * with a given source address, except the one passed in in the argument
1615 * `except'.
1616 */
1617 bool
mlxsw_sp_ipip_demote_tunnel_by_saddr(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_l3proto ul_proto,union mlxsw_sp_l3addr saddr,u32 ul_tb_id,const struct mlxsw_sp_ipip_entry * except)1618 mlxsw_sp_ipip_demote_tunnel_by_saddr(struct mlxsw_sp *mlxsw_sp,
1619 enum mlxsw_sp_l3proto ul_proto,
1620 union mlxsw_sp_l3addr saddr,
1621 u32 ul_tb_id,
1622 const struct mlxsw_sp_ipip_entry *except)
1623 {
1624 struct mlxsw_sp_ipip_entry *ipip_entry, *tmp;
1625
1626 list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list,
1627 ipip_list_node) {
1628 if (ipip_entry != except &&
1629 mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp, ul_proto, saddr,
1630 ul_tb_id, ipip_entry)) {
1631 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1632 return true;
1633 }
1634 }
1635
1636 return false;
1637 }
1638
mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(struct mlxsw_sp * mlxsw_sp,struct net_device * ul_dev)1639 static void mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(struct mlxsw_sp *mlxsw_sp,
1640 struct net_device *ul_dev)
1641 {
1642 struct mlxsw_sp_ipip_entry *ipip_entry, *tmp;
1643
1644 list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list,
1645 ipip_list_node) {
1646 struct net_device *ipip_ul_dev =
1647 __mlxsw_sp_ipip_netdev_ul_dev_get(ipip_entry->ol_dev);
1648
1649 if (ipip_ul_dev == ul_dev)
1650 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1651 }
1652 }
1653
mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev,unsigned long event,struct netdev_notifier_info * info)1654 int mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp *mlxsw_sp,
1655 struct net_device *ol_dev,
1656 unsigned long event,
1657 struct netdev_notifier_info *info)
1658 {
1659 struct netdev_notifier_changeupper_info *chup;
1660 struct netlink_ext_ack *extack;
1661
1662 switch (event) {
1663 case NETDEV_REGISTER:
1664 return mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev);
1665 case NETDEV_UNREGISTER:
1666 mlxsw_sp_netdevice_ipip_ol_unreg_event(mlxsw_sp, ol_dev);
1667 return 0;
1668 case NETDEV_UP:
1669 mlxsw_sp_netdevice_ipip_ol_up_event(mlxsw_sp, ol_dev);
1670 return 0;
1671 case NETDEV_DOWN:
1672 mlxsw_sp_netdevice_ipip_ol_down_event(mlxsw_sp, ol_dev);
1673 return 0;
1674 case NETDEV_CHANGEUPPER:
1675 chup = container_of(info, typeof(*chup), info);
1676 extack = info->extack;
1677 if (netif_is_l3_master(chup->upper_dev))
1678 return mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp,
1679 ol_dev,
1680 extack);
1681 return 0;
1682 case NETDEV_CHANGE:
1683 extack = info->extack;
1684 return mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp,
1685 ol_dev, extack);
1686 case NETDEV_CHANGEMTU:
1687 return mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev);
1688 }
1689 return 0;
1690 }
1691
1692 static int
__mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct net_device * ul_dev,unsigned long event,struct netdev_notifier_info * info)1693 __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
1694 struct mlxsw_sp_ipip_entry *ipip_entry,
1695 struct net_device *ul_dev,
1696 unsigned long event,
1697 struct netdev_notifier_info *info)
1698 {
1699 struct netdev_notifier_changeupper_info *chup;
1700 struct netlink_ext_ack *extack;
1701
1702 switch (event) {
1703 case NETDEV_CHANGEUPPER:
1704 chup = container_of(info, typeof(*chup), info);
1705 extack = info->extack;
1706 if (netif_is_l3_master(chup->upper_dev))
1707 return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp,
1708 ipip_entry,
1709 ul_dev,
1710 extack);
1711 break;
1712
1713 case NETDEV_UP:
1714 return mlxsw_sp_netdevice_ipip_ul_up_event(mlxsw_sp, ipip_entry,
1715 ul_dev);
1716 case NETDEV_DOWN:
1717 return mlxsw_sp_netdevice_ipip_ul_down_event(mlxsw_sp,
1718 ipip_entry,
1719 ul_dev);
1720 }
1721 return 0;
1722 }
1723
1724 int
mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ul_dev,unsigned long event,struct netdev_notifier_info * info)1725 mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
1726 struct net_device *ul_dev,
1727 unsigned long event,
1728 struct netdev_notifier_info *info)
1729 {
1730 struct mlxsw_sp_ipip_entry *ipip_entry = NULL;
1731 int err;
1732
1733 while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp,
1734 ul_dev,
1735 ipip_entry))) {
1736 err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry,
1737 ul_dev, event, info);
1738 if (err) {
1739 mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp,
1740 ul_dev);
1741 return err;
1742 }
1743 }
1744
1745 return 0;
1746 }
1747
1748 struct mlxsw_sp_neigh_key {
1749 struct neighbour *n;
1750 };
1751
1752 struct mlxsw_sp_neigh_entry {
1753 struct list_head rif_list_node;
1754 struct rhash_head ht_node;
1755 struct mlxsw_sp_neigh_key key;
1756 u16 rif;
1757 bool connected;
1758 unsigned char ha[ETH_ALEN];
1759 struct list_head nexthop_list; /* list of nexthops using
1760 * this neigh entry
1761 */
1762 struct list_head nexthop_neighs_list_node;
1763 unsigned int counter_index;
1764 bool counter_valid;
1765 };
1766
1767 static const struct rhashtable_params mlxsw_sp_neigh_ht_params = {
1768 .key_offset = offsetof(struct mlxsw_sp_neigh_entry, key),
1769 .head_offset = offsetof(struct mlxsw_sp_neigh_entry, ht_node),
1770 .key_len = sizeof(struct mlxsw_sp_neigh_key),
1771 };
1772
1773 struct mlxsw_sp_neigh_entry *
mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif * rif,struct mlxsw_sp_neigh_entry * neigh_entry)1774 mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif *rif,
1775 struct mlxsw_sp_neigh_entry *neigh_entry)
1776 {
1777 if (!neigh_entry) {
1778 if (list_empty(&rif->neigh_list))
1779 return NULL;
1780 else
1781 return list_first_entry(&rif->neigh_list,
1782 typeof(*neigh_entry),
1783 rif_list_node);
1784 }
1785 if (list_is_last(&neigh_entry->rif_list_node, &rif->neigh_list))
1786 return NULL;
1787 return list_next_entry(neigh_entry, rif_list_node);
1788 }
1789
mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry * neigh_entry)1790 int mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry *neigh_entry)
1791 {
1792 return neigh_entry->key.n->tbl->family;
1793 }
1794
1795 unsigned char *
mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry * neigh_entry)1796 mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry *neigh_entry)
1797 {
1798 return neigh_entry->ha;
1799 }
1800
mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry * neigh_entry)1801 u32 mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry *neigh_entry)
1802 {
1803 struct neighbour *n;
1804
1805 n = neigh_entry->key.n;
1806 return ntohl(*((__be32 *) n->primary_key));
1807 }
1808
1809 struct in6_addr *
mlxsw_sp_neigh6_entry_dip(struct mlxsw_sp_neigh_entry * neigh_entry)1810 mlxsw_sp_neigh6_entry_dip(struct mlxsw_sp_neigh_entry *neigh_entry)
1811 {
1812 struct neighbour *n;
1813
1814 n = neigh_entry->key.n;
1815 return (struct in6_addr *) &n->primary_key;
1816 }
1817
mlxsw_sp_neigh_counter_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,u64 * p_counter)1818 int mlxsw_sp_neigh_counter_get(struct mlxsw_sp *mlxsw_sp,
1819 struct mlxsw_sp_neigh_entry *neigh_entry,
1820 u64 *p_counter)
1821 {
1822 if (!neigh_entry->counter_valid)
1823 return -EINVAL;
1824
1825 return mlxsw_sp_flow_counter_get(mlxsw_sp, neigh_entry->counter_index,
1826 p_counter, NULL);
1827 }
1828
1829 static struct mlxsw_sp_neigh_entry *
mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp * mlxsw_sp,struct neighbour * n,u16 rif)1830 mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp *mlxsw_sp, struct neighbour *n,
1831 u16 rif)
1832 {
1833 struct mlxsw_sp_neigh_entry *neigh_entry;
1834
1835 neigh_entry = kzalloc(sizeof(*neigh_entry), GFP_KERNEL);
1836 if (!neigh_entry)
1837 return NULL;
1838
1839 neigh_entry->key.n = n;
1840 neigh_entry->rif = rif;
1841 INIT_LIST_HEAD(&neigh_entry->nexthop_list);
1842
1843 return neigh_entry;
1844 }
1845
mlxsw_sp_neigh_entry_free(struct mlxsw_sp_neigh_entry * neigh_entry)1846 static void mlxsw_sp_neigh_entry_free(struct mlxsw_sp_neigh_entry *neigh_entry)
1847 {
1848 kfree(neigh_entry);
1849 }
1850
1851 static int
mlxsw_sp_neigh_entry_insert(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)1852 mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp,
1853 struct mlxsw_sp_neigh_entry *neigh_entry)
1854 {
1855 return rhashtable_insert_fast(&mlxsw_sp->router->neigh_ht,
1856 &neigh_entry->ht_node,
1857 mlxsw_sp_neigh_ht_params);
1858 }
1859
1860 static void
mlxsw_sp_neigh_entry_remove(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)1861 mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
1862 struct mlxsw_sp_neigh_entry *neigh_entry)
1863 {
1864 rhashtable_remove_fast(&mlxsw_sp->router->neigh_ht,
1865 &neigh_entry->ht_node,
1866 mlxsw_sp_neigh_ht_params);
1867 }
1868
1869 static bool
mlxsw_sp_neigh_counter_should_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)1870 mlxsw_sp_neigh_counter_should_alloc(struct mlxsw_sp *mlxsw_sp,
1871 struct mlxsw_sp_neigh_entry *neigh_entry)
1872 {
1873 struct devlink *devlink;
1874 const char *table_name;
1875
1876 switch (mlxsw_sp_neigh_entry_type(neigh_entry)) {
1877 case AF_INET:
1878 table_name = MLXSW_SP_DPIPE_TABLE_NAME_HOST4;
1879 break;
1880 case AF_INET6:
1881 table_name = MLXSW_SP_DPIPE_TABLE_NAME_HOST6;
1882 break;
1883 default:
1884 WARN_ON(1);
1885 return false;
1886 }
1887
1888 devlink = priv_to_devlink(mlxsw_sp->core);
1889 return devlink_dpipe_table_counter_enabled(devlink, table_name);
1890 }
1891
1892 static void
mlxsw_sp_neigh_counter_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)1893 mlxsw_sp_neigh_counter_alloc(struct mlxsw_sp *mlxsw_sp,
1894 struct mlxsw_sp_neigh_entry *neigh_entry)
1895 {
1896 if (!mlxsw_sp_neigh_counter_should_alloc(mlxsw_sp, neigh_entry))
1897 return;
1898
1899 if (mlxsw_sp_flow_counter_alloc(mlxsw_sp, &neigh_entry->counter_index))
1900 return;
1901
1902 neigh_entry->counter_valid = true;
1903 }
1904
1905 static void
mlxsw_sp_neigh_counter_free(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)1906 mlxsw_sp_neigh_counter_free(struct mlxsw_sp *mlxsw_sp,
1907 struct mlxsw_sp_neigh_entry *neigh_entry)
1908 {
1909 if (!neigh_entry->counter_valid)
1910 return;
1911 mlxsw_sp_flow_counter_free(mlxsw_sp,
1912 neigh_entry->counter_index);
1913 neigh_entry->counter_valid = false;
1914 }
1915
1916 static struct mlxsw_sp_neigh_entry *
mlxsw_sp_neigh_entry_create(struct mlxsw_sp * mlxsw_sp,struct neighbour * n)1917 mlxsw_sp_neigh_entry_create(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
1918 {
1919 struct mlxsw_sp_neigh_entry *neigh_entry;
1920 struct mlxsw_sp_rif *rif;
1921 int err;
1922
1923 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev);
1924 if (!rif)
1925 return ERR_PTR(-EINVAL);
1926
1927 neigh_entry = mlxsw_sp_neigh_entry_alloc(mlxsw_sp, n, rif->rif_index);
1928 if (!neigh_entry)
1929 return ERR_PTR(-ENOMEM);
1930
1931 err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
1932 if (err)
1933 goto err_neigh_entry_insert;
1934
1935 mlxsw_sp_neigh_counter_alloc(mlxsw_sp, neigh_entry);
1936 list_add(&neigh_entry->rif_list_node, &rif->neigh_list);
1937
1938 return neigh_entry;
1939
1940 err_neigh_entry_insert:
1941 mlxsw_sp_neigh_entry_free(neigh_entry);
1942 return ERR_PTR(err);
1943 }
1944
1945 static void
mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)1946 mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp *mlxsw_sp,
1947 struct mlxsw_sp_neigh_entry *neigh_entry)
1948 {
1949 list_del(&neigh_entry->rif_list_node);
1950 mlxsw_sp_neigh_counter_free(mlxsw_sp, neigh_entry);
1951 mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
1952 mlxsw_sp_neigh_entry_free(neigh_entry);
1953 }
1954
1955 static struct mlxsw_sp_neigh_entry *
mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp * mlxsw_sp,struct neighbour * n)1956 mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
1957 {
1958 struct mlxsw_sp_neigh_key key;
1959
1960 key.n = n;
1961 return rhashtable_lookup_fast(&mlxsw_sp->router->neigh_ht,
1962 &key, mlxsw_sp_neigh_ht_params);
1963 }
1964
1965 static void
mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp * mlxsw_sp)1966 mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp)
1967 {
1968 unsigned long interval;
1969
1970 #if IS_ENABLED(CONFIG_IPV6)
1971 interval = min_t(unsigned long,
1972 NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME),
1973 NEIGH_VAR(&nd_tbl.parms, DELAY_PROBE_TIME));
1974 #else
1975 interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
1976 #endif
1977 mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval);
1978 }
1979
mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int ent_index)1980 static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
1981 char *rauhtd_pl,
1982 int ent_index)
1983 {
1984 struct net_device *dev;
1985 struct neighbour *n;
1986 __be32 dipn;
1987 u32 dip;
1988 u16 rif;
1989
1990 mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
1991
1992 if (!mlxsw_sp->router->rifs[rif]) {
1993 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
1994 return;
1995 }
1996
1997 dipn = htonl(dip);
1998 dev = mlxsw_sp->router->rifs[rif]->dev;
1999 n = neigh_lookup(&arp_tbl, &dipn, dev);
2000 if (!n)
2001 return;
2002
2003 netdev_dbg(dev, "Updating neighbour with IP=%pI4h\n", &dip);
2004 neigh_event_send(n, NULL);
2005 neigh_release(n);
2006 }
2007
2008 #if IS_ENABLED(CONFIG_IPV6)
mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2009 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2010 char *rauhtd_pl,
2011 int rec_index)
2012 {
2013 struct net_device *dev;
2014 struct neighbour *n;
2015 struct in6_addr dip;
2016 u16 rif;
2017
2018 mlxsw_reg_rauhtd_ent_ipv6_unpack(rauhtd_pl, rec_index, &rif,
2019 (char *) &dip);
2020
2021 if (!mlxsw_sp->router->rifs[rif]) {
2022 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
2023 return;
2024 }
2025
2026 dev = mlxsw_sp->router->rifs[rif]->dev;
2027 n = neigh_lookup(&nd_tbl, &dip, dev);
2028 if (!n)
2029 return;
2030
2031 netdev_dbg(dev, "Updating neighbour with IP=%pI6c\n", &dip);
2032 neigh_event_send(n, NULL);
2033 neigh_release(n);
2034 }
2035 #else
mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2036 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2037 char *rauhtd_pl,
2038 int rec_index)
2039 {
2040 }
2041 #endif
2042
mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2043 static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp *mlxsw_sp,
2044 char *rauhtd_pl,
2045 int rec_index)
2046 {
2047 u8 num_entries;
2048 int i;
2049
2050 num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
2051 rec_index);
2052 /* Hardware starts counting at 0, so add 1. */
2053 num_entries++;
2054
2055 /* Each record consists of several neighbour entries. */
2056 for (i = 0; i < num_entries; i++) {
2057 int ent_index;
2058
2059 ent_index = rec_index * MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC + i;
2060 mlxsw_sp_router_neigh_ent_ipv4_process(mlxsw_sp, rauhtd_pl,
2061 ent_index);
2062 }
2063
2064 }
2065
mlxsw_sp_router_neigh_rec_ipv6_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2066 static void mlxsw_sp_router_neigh_rec_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2067 char *rauhtd_pl,
2068 int rec_index)
2069 {
2070 /* One record contains one entry. */
2071 mlxsw_sp_router_neigh_ent_ipv6_process(mlxsw_sp, rauhtd_pl,
2072 rec_index);
2073 }
2074
mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2075 static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp *mlxsw_sp,
2076 char *rauhtd_pl, int rec_index)
2077 {
2078 switch (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, rec_index)) {
2079 case MLXSW_REG_RAUHTD_TYPE_IPV4:
2080 mlxsw_sp_router_neigh_rec_ipv4_process(mlxsw_sp, rauhtd_pl,
2081 rec_index);
2082 break;
2083 case MLXSW_REG_RAUHTD_TYPE_IPV6:
2084 mlxsw_sp_router_neigh_rec_ipv6_process(mlxsw_sp, rauhtd_pl,
2085 rec_index);
2086 break;
2087 }
2088 }
2089
mlxsw_sp_router_rauhtd_is_full(char * rauhtd_pl)2090 static bool mlxsw_sp_router_rauhtd_is_full(char *rauhtd_pl)
2091 {
2092 u8 num_rec, last_rec_index, num_entries;
2093
2094 num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
2095 last_rec_index = num_rec - 1;
2096
2097 if (num_rec < MLXSW_REG_RAUHTD_REC_MAX_NUM)
2098 return false;
2099 if (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, last_rec_index) ==
2100 MLXSW_REG_RAUHTD_TYPE_IPV6)
2101 return true;
2102
2103 num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
2104 last_rec_index);
2105 if (++num_entries == MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC)
2106 return true;
2107 return false;
2108 }
2109
2110 static int
__mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,enum mlxsw_reg_rauhtd_type type)2111 __mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp,
2112 char *rauhtd_pl,
2113 enum mlxsw_reg_rauhtd_type type)
2114 {
2115 int i, num_rec;
2116 int err;
2117
2118 /* Make sure the neighbour's netdev isn't removed in the
2119 * process.
2120 */
2121 rtnl_lock();
2122 do {
2123 mlxsw_reg_rauhtd_pack(rauhtd_pl, type);
2124 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(rauhtd),
2125 rauhtd_pl);
2126 if (err) {
2127 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to dump neighbour table\n");
2128 break;
2129 }
2130 num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
2131 for (i = 0; i < num_rec; i++)
2132 mlxsw_sp_router_neigh_rec_process(mlxsw_sp, rauhtd_pl,
2133 i);
2134 } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl));
2135 rtnl_unlock();
2136
2137 return err;
2138 }
2139
mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp * mlxsw_sp)2140 static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
2141 {
2142 enum mlxsw_reg_rauhtd_type type;
2143 char *rauhtd_pl;
2144 int err;
2145
2146 rauhtd_pl = kmalloc(MLXSW_REG_RAUHTD_LEN, GFP_KERNEL);
2147 if (!rauhtd_pl)
2148 return -ENOMEM;
2149
2150 type = MLXSW_REG_RAUHTD_TYPE_IPV4;
2151 err = __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp, rauhtd_pl, type);
2152 if (err)
2153 goto out;
2154
2155 type = MLXSW_REG_RAUHTD_TYPE_IPV6;
2156 err = __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp, rauhtd_pl, type);
2157 out:
2158 kfree(rauhtd_pl);
2159 return err;
2160 }
2161
mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp * mlxsw_sp)2162 static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
2163 {
2164 struct mlxsw_sp_neigh_entry *neigh_entry;
2165
2166 /* Take RTNL mutex here to prevent lists from changes */
2167 rtnl_lock();
2168 list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list,
2169 nexthop_neighs_list_node)
2170 /* If this neigh have nexthops, make the kernel think this neigh
2171 * is active regardless of the traffic.
2172 */
2173 neigh_event_send(neigh_entry->key.n, NULL);
2174 rtnl_unlock();
2175 }
2176
2177 static void
mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp * mlxsw_sp)2178 mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp)
2179 {
2180 unsigned long interval = mlxsw_sp->router->neighs_update.interval;
2181
2182 mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw,
2183 msecs_to_jiffies(interval));
2184 }
2185
mlxsw_sp_router_neighs_update_work(struct work_struct * work)2186 static void mlxsw_sp_router_neighs_update_work(struct work_struct *work)
2187 {
2188 struct mlxsw_sp_router *router;
2189 int err;
2190
2191 router = container_of(work, struct mlxsw_sp_router,
2192 neighs_update.dw.work);
2193 err = mlxsw_sp_router_neighs_update_rauhtd(router->mlxsw_sp);
2194 if (err)
2195 dev_err(router->mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
2196
2197 mlxsw_sp_router_neighs_update_nh(router->mlxsw_sp);
2198
2199 mlxsw_sp_router_neighs_update_work_schedule(router->mlxsw_sp);
2200 }
2201
mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct * work)2202 static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
2203 {
2204 struct mlxsw_sp_neigh_entry *neigh_entry;
2205 struct mlxsw_sp_router *router;
2206
2207 router = container_of(work, struct mlxsw_sp_router,
2208 nexthop_probe_dw.work);
2209 /* Iterate over nexthop neighbours, find those who are unresolved and
2210 * send arp on them. This solves the chicken-egg problem when
2211 * the nexthop wouldn't get offloaded until the neighbor is resolved
2212 * but it wouldn't get resolved ever in case traffic is flowing in HW
2213 * using different nexthop.
2214 *
2215 * Take RTNL mutex here to prevent lists from changes.
2216 */
2217 rtnl_lock();
2218 list_for_each_entry(neigh_entry, &router->nexthop_neighs_list,
2219 nexthop_neighs_list_node)
2220 if (!neigh_entry->connected)
2221 neigh_event_send(neigh_entry->key.n, NULL);
2222 rtnl_unlock();
2223
2224 mlxsw_core_schedule_dw(&router->nexthop_probe_dw,
2225 MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL);
2226 }
2227
2228 static void
2229 mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
2230 struct mlxsw_sp_neigh_entry *neigh_entry,
2231 bool removing, bool dead);
2232
mlxsw_sp_rauht_op(bool adding)2233 static enum mlxsw_reg_rauht_op mlxsw_sp_rauht_op(bool adding)
2234 {
2235 return adding ? MLXSW_REG_RAUHT_OP_WRITE_ADD :
2236 MLXSW_REG_RAUHT_OP_WRITE_DELETE;
2237 }
2238
2239 static void
mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,enum mlxsw_reg_rauht_op op)2240 mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp,
2241 struct mlxsw_sp_neigh_entry *neigh_entry,
2242 enum mlxsw_reg_rauht_op op)
2243 {
2244 struct neighbour *n = neigh_entry->key.n;
2245 u32 dip = ntohl(*((__be32 *) n->primary_key));
2246 char rauht_pl[MLXSW_REG_RAUHT_LEN];
2247
2248 mlxsw_reg_rauht_pack4(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
2249 dip);
2250 if (neigh_entry->counter_valid)
2251 mlxsw_reg_rauht_pack_counter(rauht_pl,
2252 neigh_entry->counter_index);
2253 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
2254 }
2255
2256 static void
mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,enum mlxsw_reg_rauht_op op)2257 mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp,
2258 struct mlxsw_sp_neigh_entry *neigh_entry,
2259 enum mlxsw_reg_rauht_op op)
2260 {
2261 struct neighbour *n = neigh_entry->key.n;
2262 char rauht_pl[MLXSW_REG_RAUHT_LEN];
2263 const char *dip = n->primary_key;
2264
2265 mlxsw_reg_rauht_pack6(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
2266 dip);
2267 if (neigh_entry->counter_valid)
2268 mlxsw_reg_rauht_pack_counter(rauht_pl,
2269 neigh_entry->counter_index);
2270 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
2271 }
2272
mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry * neigh_entry)2273 bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry *neigh_entry)
2274 {
2275 struct neighbour *n = neigh_entry->key.n;
2276
2277 /* Packets with a link-local destination address are trapped
2278 * after LPM lookup and never reach the neighbour table, so
2279 * there is no need to program such neighbours to the device.
2280 */
2281 if (ipv6_addr_type((struct in6_addr *) &n->primary_key) &
2282 IPV6_ADDR_LINKLOCAL)
2283 return true;
2284 return false;
2285 }
2286
2287 static void
mlxsw_sp_neigh_entry_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,bool adding)2288 mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp,
2289 struct mlxsw_sp_neigh_entry *neigh_entry,
2290 bool adding)
2291 {
2292 if (!adding && !neigh_entry->connected)
2293 return;
2294 neigh_entry->connected = adding;
2295 if (neigh_entry->key.n->tbl->family == AF_INET) {
2296 mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry,
2297 mlxsw_sp_rauht_op(adding));
2298 } else if (neigh_entry->key.n->tbl->family == AF_INET6) {
2299 if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
2300 return;
2301 mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry,
2302 mlxsw_sp_rauht_op(adding));
2303 } else {
2304 WARN_ON_ONCE(1);
2305 }
2306 }
2307
2308 void
mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,bool adding)2309 mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp *mlxsw_sp,
2310 struct mlxsw_sp_neigh_entry *neigh_entry,
2311 bool adding)
2312 {
2313 if (adding)
2314 mlxsw_sp_neigh_counter_alloc(mlxsw_sp, neigh_entry);
2315 else
2316 mlxsw_sp_neigh_counter_free(mlxsw_sp, neigh_entry);
2317 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, true);
2318 }
2319
2320 struct mlxsw_sp_netevent_work {
2321 struct work_struct work;
2322 struct mlxsw_sp *mlxsw_sp;
2323 struct neighbour *n;
2324 };
2325
mlxsw_sp_router_neigh_event_work(struct work_struct * work)2326 static void mlxsw_sp_router_neigh_event_work(struct work_struct *work)
2327 {
2328 struct mlxsw_sp_netevent_work *net_work =
2329 container_of(work, struct mlxsw_sp_netevent_work, work);
2330 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
2331 struct mlxsw_sp_neigh_entry *neigh_entry;
2332 struct neighbour *n = net_work->n;
2333 unsigned char ha[ETH_ALEN];
2334 bool entry_connected;
2335 u8 nud_state, dead;
2336
2337 /* If these parameters are changed after we release the lock,
2338 * then we are guaranteed to receive another event letting us
2339 * know about it.
2340 */
2341 read_lock_bh(&n->lock);
2342 memcpy(ha, n->ha, ETH_ALEN);
2343 nud_state = n->nud_state;
2344 dead = n->dead;
2345 read_unlock_bh(&n->lock);
2346
2347 rtnl_lock();
2348 mlxsw_sp_span_respin(mlxsw_sp);
2349
2350 entry_connected = nud_state & NUD_VALID && !dead;
2351 neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
2352 if (!entry_connected && !neigh_entry)
2353 goto out;
2354 if (!neigh_entry) {
2355 neigh_entry = mlxsw_sp_neigh_entry_create(mlxsw_sp, n);
2356 if (IS_ERR(neigh_entry))
2357 goto out;
2358 }
2359
2360 memcpy(neigh_entry->ha, ha, ETH_ALEN);
2361 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, entry_connected);
2362 mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected,
2363 dead);
2364
2365 if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list))
2366 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
2367
2368 out:
2369 rtnl_unlock();
2370 neigh_release(n);
2371 kfree(net_work);
2372 }
2373
2374 static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp);
2375
mlxsw_sp_router_mp_hash_event_work(struct work_struct * work)2376 static void mlxsw_sp_router_mp_hash_event_work(struct work_struct *work)
2377 {
2378 struct mlxsw_sp_netevent_work *net_work =
2379 container_of(work, struct mlxsw_sp_netevent_work, work);
2380 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
2381
2382 mlxsw_sp_mp_hash_init(mlxsw_sp);
2383 kfree(net_work);
2384 }
2385
2386 static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
2387
mlxsw_sp_router_update_priority_work(struct work_struct * work)2388 static void mlxsw_sp_router_update_priority_work(struct work_struct *work)
2389 {
2390 struct mlxsw_sp_netevent_work *net_work =
2391 container_of(work, struct mlxsw_sp_netevent_work, work);
2392 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
2393
2394 __mlxsw_sp_router_init(mlxsw_sp);
2395 kfree(net_work);
2396 }
2397
mlxsw_sp_router_schedule_work(struct net * net,struct notifier_block * nb,void (* cb)(struct work_struct *))2398 static int mlxsw_sp_router_schedule_work(struct net *net,
2399 struct notifier_block *nb,
2400 void (*cb)(struct work_struct *))
2401 {
2402 struct mlxsw_sp_netevent_work *net_work;
2403 struct mlxsw_sp_router *router;
2404
2405 if (!net_eq(net, &init_net))
2406 return NOTIFY_DONE;
2407
2408 net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
2409 if (!net_work)
2410 return NOTIFY_BAD;
2411
2412 router = container_of(nb, struct mlxsw_sp_router, netevent_nb);
2413 INIT_WORK(&net_work->work, cb);
2414 net_work->mlxsw_sp = router->mlxsw_sp;
2415 mlxsw_core_schedule_work(&net_work->work);
2416 return NOTIFY_DONE;
2417 }
2418
mlxsw_sp_router_netevent_event(struct notifier_block * nb,unsigned long event,void * ptr)2419 static int mlxsw_sp_router_netevent_event(struct notifier_block *nb,
2420 unsigned long event, void *ptr)
2421 {
2422 struct mlxsw_sp_netevent_work *net_work;
2423 struct mlxsw_sp_port *mlxsw_sp_port;
2424 struct mlxsw_sp *mlxsw_sp;
2425 unsigned long interval;
2426 struct neigh_parms *p;
2427 struct neighbour *n;
2428
2429 switch (event) {
2430 case NETEVENT_DELAY_PROBE_TIME_UPDATE:
2431 p = ptr;
2432
2433 /* We don't care about changes in the default table. */
2434 if (!p->dev || (p->tbl->family != AF_INET &&
2435 p->tbl->family != AF_INET6))
2436 return NOTIFY_DONE;
2437
2438 /* We are in atomic context and can't take RTNL mutex,
2439 * so use RCU variant to walk the device chain.
2440 */
2441 mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(p->dev);
2442 if (!mlxsw_sp_port)
2443 return NOTIFY_DONE;
2444
2445 mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2446 interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME));
2447 mlxsw_sp->router->neighs_update.interval = interval;
2448
2449 mlxsw_sp_port_dev_put(mlxsw_sp_port);
2450 break;
2451 case NETEVENT_NEIGH_UPDATE:
2452 n = ptr;
2453
2454 if (n->tbl->family != AF_INET && n->tbl->family != AF_INET6)
2455 return NOTIFY_DONE;
2456
2457 mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(n->dev);
2458 if (!mlxsw_sp_port)
2459 return NOTIFY_DONE;
2460
2461 net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
2462 if (!net_work) {
2463 mlxsw_sp_port_dev_put(mlxsw_sp_port);
2464 return NOTIFY_BAD;
2465 }
2466
2467 INIT_WORK(&net_work->work, mlxsw_sp_router_neigh_event_work);
2468 net_work->mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2469 net_work->n = n;
2470
2471 /* Take a reference to ensure the neighbour won't be
2472 * destructed until we drop the reference in delayed
2473 * work.
2474 */
2475 neigh_clone(n);
2476 mlxsw_core_schedule_work(&net_work->work);
2477 mlxsw_sp_port_dev_put(mlxsw_sp_port);
2478 break;
2479 case NETEVENT_IPV4_MPATH_HASH_UPDATE:
2480 case NETEVENT_IPV6_MPATH_HASH_UPDATE:
2481 return mlxsw_sp_router_schedule_work(ptr, nb,
2482 mlxsw_sp_router_mp_hash_event_work);
2483
2484 case NETEVENT_IPV4_FWD_UPDATE_PRIORITY_UPDATE:
2485 return mlxsw_sp_router_schedule_work(ptr, nb,
2486 mlxsw_sp_router_update_priority_work);
2487 }
2488
2489 return NOTIFY_DONE;
2490 }
2491
mlxsw_sp_neigh_init(struct mlxsw_sp * mlxsw_sp)2492 static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
2493 {
2494 int err;
2495
2496 err = rhashtable_init(&mlxsw_sp->router->neigh_ht,
2497 &mlxsw_sp_neigh_ht_params);
2498 if (err)
2499 return err;
2500
2501 /* Initialize the polling interval according to the default
2502 * table.
2503 */
2504 mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp);
2505
2506 /* Create the delayed works for the activity_update */
2507 INIT_DELAYED_WORK(&mlxsw_sp->router->neighs_update.dw,
2508 mlxsw_sp_router_neighs_update_work);
2509 INIT_DELAYED_WORK(&mlxsw_sp->router->nexthop_probe_dw,
2510 mlxsw_sp_router_probe_unresolved_nexthops);
2511 mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, 0);
2512 mlxsw_core_schedule_dw(&mlxsw_sp->router->nexthop_probe_dw, 0);
2513 return 0;
2514 }
2515
mlxsw_sp_neigh_fini(struct mlxsw_sp * mlxsw_sp)2516 static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
2517 {
2518 cancel_delayed_work_sync(&mlxsw_sp->router->neighs_update.dw);
2519 cancel_delayed_work_sync(&mlxsw_sp->router->nexthop_probe_dw);
2520 rhashtable_destroy(&mlxsw_sp->router->neigh_ht);
2521 }
2522
mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)2523 static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
2524 struct mlxsw_sp_rif *rif)
2525 {
2526 struct mlxsw_sp_neigh_entry *neigh_entry, *tmp;
2527
2528 list_for_each_entry_safe(neigh_entry, tmp, &rif->neigh_list,
2529 rif_list_node) {
2530 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, false);
2531 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
2532 }
2533 }
2534
2535 enum mlxsw_sp_nexthop_type {
2536 MLXSW_SP_NEXTHOP_TYPE_ETH,
2537 MLXSW_SP_NEXTHOP_TYPE_IPIP,
2538 };
2539
2540 struct mlxsw_sp_nexthop_key {
2541 struct fib_nh *fib_nh;
2542 };
2543
2544 struct mlxsw_sp_nexthop {
2545 struct list_head neigh_list_node; /* member of neigh entry list */
2546 struct list_head rif_list_node;
2547 struct list_head router_list_node;
2548 struct mlxsw_sp_nexthop_group *nh_grp; /* pointer back to the group
2549 * this belongs to
2550 */
2551 struct rhash_head ht_node;
2552 struct mlxsw_sp_nexthop_key key;
2553 unsigned char gw_addr[sizeof(struct in6_addr)];
2554 int ifindex;
2555 int nh_weight;
2556 int norm_nh_weight;
2557 int num_adj_entries;
2558 struct mlxsw_sp_rif *rif;
2559 u8 should_offload:1, /* set indicates this neigh is connected and
2560 * should be put to KVD linear area of this group.
2561 */
2562 offloaded:1, /* set in case the neigh is actually put into
2563 * KVD linear area of this group.
2564 */
2565 update:1; /* set indicates that MAC of this neigh should be
2566 * updated in HW
2567 */
2568 enum mlxsw_sp_nexthop_type type;
2569 union {
2570 struct mlxsw_sp_neigh_entry *neigh_entry;
2571 struct mlxsw_sp_ipip_entry *ipip_entry;
2572 };
2573 unsigned int counter_index;
2574 bool counter_valid;
2575 };
2576
2577 struct mlxsw_sp_nexthop_group {
2578 void *priv;
2579 struct rhash_head ht_node;
2580 struct list_head fib_list; /* list of fib entries that use this group */
2581 struct neigh_table *neigh_tbl;
2582 u8 adj_index_valid:1,
2583 gateway:1; /* routes using the group use a gateway */
2584 u32 adj_index;
2585 u16 ecmp_size;
2586 u16 count;
2587 int sum_norm_weight;
2588 struct mlxsw_sp_nexthop nexthops[0];
2589 #define nh_rif nexthops[0].rif
2590 };
2591
mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)2592 void mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp *mlxsw_sp,
2593 struct mlxsw_sp_nexthop *nh)
2594 {
2595 struct devlink *devlink;
2596
2597 devlink = priv_to_devlink(mlxsw_sp->core);
2598 if (!devlink_dpipe_table_counter_enabled(devlink,
2599 MLXSW_SP_DPIPE_TABLE_NAME_ADJ))
2600 return;
2601
2602 if (mlxsw_sp_flow_counter_alloc(mlxsw_sp, &nh->counter_index))
2603 return;
2604
2605 nh->counter_valid = true;
2606 }
2607
mlxsw_sp_nexthop_counter_free(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)2608 void mlxsw_sp_nexthop_counter_free(struct mlxsw_sp *mlxsw_sp,
2609 struct mlxsw_sp_nexthop *nh)
2610 {
2611 if (!nh->counter_valid)
2612 return;
2613 mlxsw_sp_flow_counter_free(mlxsw_sp, nh->counter_index);
2614 nh->counter_valid = false;
2615 }
2616
mlxsw_sp_nexthop_counter_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh,u64 * p_counter)2617 int mlxsw_sp_nexthop_counter_get(struct mlxsw_sp *mlxsw_sp,
2618 struct mlxsw_sp_nexthop *nh, u64 *p_counter)
2619 {
2620 if (!nh->counter_valid)
2621 return -EINVAL;
2622
2623 return mlxsw_sp_flow_counter_get(mlxsw_sp, nh->counter_index,
2624 p_counter, NULL);
2625 }
2626
mlxsw_sp_nexthop_next(struct mlxsw_sp_router * router,struct mlxsw_sp_nexthop * nh)2627 struct mlxsw_sp_nexthop *mlxsw_sp_nexthop_next(struct mlxsw_sp_router *router,
2628 struct mlxsw_sp_nexthop *nh)
2629 {
2630 if (!nh) {
2631 if (list_empty(&router->nexthop_list))
2632 return NULL;
2633 else
2634 return list_first_entry(&router->nexthop_list,
2635 typeof(*nh), router_list_node);
2636 }
2637 if (list_is_last(&nh->router_list_node, &router->nexthop_list))
2638 return NULL;
2639 return list_next_entry(nh, router_list_node);
2640 }
2641
mlxsw_sp_nexthop_offload(struct mlxsw_sp_nexthop * nh)2642 bool mlxsw_sp_nexthop_offload(struct mlxsw_sp_nexthop *nh)
2643 {
2644 return nh->offloaded;
2645 }
2646
mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop * nh)2647 unsigned char *mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop *nh)
2648 {
2649 if (!nh->offloaded)
2650 return NULL;
2651 return nh->neigh_entry->ha;
2652 }
2653
mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop * nh,u32 * p_adj_index,u32 * p_adj_size,u32 * p_adj_hash_index)2654 int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index,
2655 u32 *p_adj_size, u32 *p_adj_hash_index)
2656 {
2657 struct mlxsw_sp_nexthop_group *nh_grp = nh->nh_grp;
2658 u32 adj_hash_index = 0;
2659 int i;
2660
2661 if (!nh->offloaded || !nh_grp->adj_index_valid)
2662 return -EINVAL;
2663
2664 *p_adj_index = nh_grp->adj_index;
2665 *p_adj_size = nh_grp->ecmp_size;
2666
2667 for (i = 0; i < nh_grp->count; i++) {
2668 struct mlxsw_sp_nexthop *nh_iter = &nh_grp->nexthops[i];
2669
2670 if (nh_iter == nh)
2671 break;
2672 if (nh_iter->offloaded)
2673 adj_hash_index += nh_iter->num_adj_entries;
2674 }
2675
2676 *p_adj_hash_index = adj_hash_index;
2677 return 0;
2678 }
2679
mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop * nh)2680 struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh)
2681 {
2682 return nh->rif;
2683 }
2684
mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop * nh)2685 bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh)
2686 {
2687 struct mlxsw_sp_nexthop_group *nh_grp = nh->nh_grp;
2688 int i;
2689
2690 for (i = 0; i < nh_grp->count; i++) {
2691 struct mlxsw_sp_nexthop *nh_iter = &nh_grp->nexthops[i];
2692
2693 if (nh_iter->type == MLXSW_SP_NEXTHOP_TYPE_IPIP)
2694 return true;
2695 }
2696 return false;
2697 }
2698
2699 static struct fib_info *
mlxsw_sp_nexthop4_group_fi(const struct mlxsw_sp_nexthop_group * nh_grp)2700 mlxsw_sp_nexthop4_group_fi(const struct mlxsw_sp_nexthop_group *nh_grp)
2701 {
2702 return nh_grp->priv;
2703 }
2704
2705 struct mlxsw_sp_nexthop_group_cmp_arg {
2706 enum mlxsw_sp_l3proto proto;
2707 union {
2708 struct fib_info *fi;
2709 struct mlxsw_sp_fib6_entry *fib6_entry;
2710 };
2711 };
2712
2713 static bool
mlxsw_sp_nexthop6_group_has_nexthop(const struct mlxsw_sp_nexthop_group * nh_grp,const struct in6_addr * gw,int ifindex,int weight)2714 mlxsw_sp_nexthop6_group_has_nexthop(const struct mlxsw_sp_nexthop_group *nh_grp,
2715 const struct in6_addr *gw, int ifindex,
2716 int weight)
2717 {
2718 int i;
2719
2720 for (i = 0; i < nh_grp->count; i++) {
2721 const struct mlxsw_sp_nexthop *nh;
2722
2723 nh = &nh_grp->nexthops[i];
2724 if (nh->ifindex == ifindex && nh->nh_weight == weight &&
2725 ipv6_addr_equal(gw, (struct in6_addr *) nh->gw_addr))
2726 return true;
2727 }
2728
2729 return false;
2730 }
2731
2732 static bool
mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group * nh_grp,const struct mlxsw_sp_fib6_entry * fib6_entry)2733 mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group *nh_grp,
2734 const struct mlxsw_sp_fib6_entry *fib6_entry)
2735 {
2736 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
2737
2738 if (nh_grp->count != fib6_entry->nrt6)
2739 return false;
2740
2741 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
2742 struct in6_addr *gw;
2743 int ifindex, weight;
2744
2745 ifindex = mlxsw_sp_rt6->rt->fib6_nh.nh_dev->ifindex;
2746 weight = mlxsw_sp_rt6->rt->fib6_nh.nh_weight;
2747 gw = &mlxsw_sp_rt6->rt->fib6_nh.nh_gw;
2748 if (!mlxsw_sp_nexthop6_group_has_nexthop(nh_grp, gw, ifindex,
2749 weight))
2750 return false;
2751 }
2752
2753 return true;
2754 }
2755
2756 static int
mlxsw_sp_nexthop_group_cmp(struct rhashtable_compare_arg * arg,const void * ptr)2757 mlxsw_sp_nexthop_group_cmp(struct rhashtable_compare_arg *arg, const void *ptr)
2758 {
2759 const struct mlxsw_sp_nexthop_group_cmp_arg *cmp_arg = arg->key;
2760 const struct mlxsw_sp_nexthop_group *nh_grp = ptr;
2761
2762 switch (cmp_arg->proto) {
2763 case MLXSW_SP_L3_PROTO_IPV4:
2764 return cmp_arg->fi != mlxsw_sp_nexthop4_group_fi(nh_grp);
2765 case MLXSW_SP_L3_PROTO_IPV6:
2766 return !mlxsw_sp_nexthop6_group_cmp(nh_grp,
2767 cmp_arg->fib6_entry);
2768 default:
2769 WARN_ON(1);
2770 return 1;
2771 }
2772 }
2773
2774 static int
mlxsw_sp_nexthop_group_type(const struct mlxsw_sp_nexthop_group * nh_grp)2775 mlxsw_sp_nexthop_group_type(const struct mlxsw_sp_nexthop_group *nh_grp)
2776 {
2777 return nh_grp->neigh_tbl->family;
2778 }
2779
mlxsw_sp_nexthop_group_hash_obj(const void * data,u32 len,u32 seed)2780 static u32 mlxsw_sp_nexthop_group_hash_obj(const void *data, u32 len, u32 seed)
2781 {
2782 const struct mlxsw_sp_nexthop_group *nh_grp = data;
2783 const struct mlxsw_sp_nexthop *nh;
2784 struct fib_info *fi;
2785 unsigned int val;
2786 int i;
2787
2788 switch (mlxsw_sp_nexthop_group_type(nh_grp)) {
2789 case AF_INET:
2790 fi = mlxsw_sp_nexthop4_group_fi(nh_grp);
2791 return jhash(&fi, sizeof(fi), seed);
2792 case AF_INET6:
2793 val = nh_grp->count;
2794 for (i = 0; i < nh_grp->count; i++) {
2795 nh = &nh_grp->nexthops[i];
2796 val ^= nh->ifindex;
2797 }
2798 return jhash(&val, sizeof(val), seed);
2799 default:
2800 WARN_ON(1);
2801 return 0;
2802 }
2803 }
2804
2805 static u32
mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry * fib6_entry,u32 seed)2806 mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry *fib6_entry, u32 seed)
2807 {
2808 unsigned int val = fib6_entry->nrt6;
2809 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
2810 struct net_device *dev;
2811
2812 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
2813 dev = mlxsw_sp_rt6->rt->fib6_nh.nh_dev;
2814 val ^= dev->ifindex;
2815 }
2816
2817 return jhash(&val, sizeof(val), seed);
2818 }
2819
2820 static u32
mlxsw_sp_nexthop_group_hash(const void * data,u32 len,u32 seed)2821 mlxsw_sp_nexthop_group_hash(const void *data, u32 len, u32 seed)
2822 {
2823 const struct mlxsw_sp_nexthop_group_cmp_arg *cmp_arg = data;
2824
2825 switch (cmp_arg->proto) {
2826 case MLXSW_SP_L3_PROTO_IPV4:
2827 return jhash(&cmp_arg->fi, sizeof(cmp_arg->fi), seed);
2828 case MLXSW_SP_L3_PROTO_IPV6:
2829 return mlxsw_sp_nexthop6_group_hash(cmp_arg->fib6_entry, seed);
2830 default:
2831 WARN_ON(1);
2832 return 0;
2833 }
2834 }
2835
2836 static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params = {
2837 .head_offset = offsetof(struct mlxsw_sp_nexthop_group, ht_node),
2838 .hashfn = mlxsw_sp_nexthop_group_hash,
2839 .obj_hashfn = mlxsw_sp_nexthop_group_hash_obj,
2840 .obj_cmpfn = mlxsw_sp_nexthop_group_cmp,
2841 };
2842
mlxsw_sp_nexthop_group_insert(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)2843 static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp,
2844 struct mlxsw_sp_nexthop_group *nh_grp)
2845 {
2846 if (mlxsw_sp_nexthop_group_type(nh_grp) == AF_INET6 &&
2847 !nh_grp->gateway)
2848 return 0;
2849
2850 return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_group_ht,
2851 &nh_grp->ht_node,
2852 mlxsw_sp_nexthop_group_ht_params);
2853 }
2854
mlxsw_sp_nexthop_group_remove(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)2855 static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp *mlxsw_sp,
2856 struct mlxsw_sp_nexthop_group *nh_grp)
2857 {
2858 if (mlxsw_sp_nexthop_group_type(nh_grp) == AF_INET6 &&
2859 !nh_grp->gateway)
2860 return;
2861
2862 rhashtable_remove_fast(&mlxsw_sp->router->nexthop_group_ht,
2863 &nh_grp->ht_node,
2864 mlxsw_sp_nexthop_group_ht_params);
2865 }
2866
2867 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop4_group_lookup(struct mlxsw_sp * mlxsw_sp,struct fib_info * fi)2868 mlxsw_sp_nexthop4_group_lookup(struct mlxsw_sp *mlxsw_sp,
2869 struct fib_info *fi)
2870 {
2871 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg;
2872
2873 cmp_arg.proto = MLXSW_SP_L3_PROTO_IPV4;
2874 cmp_arg.fi = fi;
2875 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht,
2876 &cmp_arg,
2877 mlxsw_sp_nexthop_group_ht_params);
2878 }
2879
2880 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop6_group_lookup(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)2881 mlxsw_sp_nexthop6_group_lookup(struct mlxsw_sp *mlxsw_sp,
2882 struct mlxsw_sp_fib6_entry *fib6_entry)
2883 {
2884 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg;
2885
2886 cmp_arg.proto = MLXSW_SP_L3_PROTO_IPV6;
2887 cmp_arg.fib6_entry = fib6_entry;
2888 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht,
2889 &cmp_arg,
2890 mlxsw_sp_nexthop_group_ht_params);
2891 }
2892
2893 static const struct rhashtable_params mlxsw_sp_nexthop_ht_params = {
2894 .key_offset = offsetof(struct mlxsw_sp_nexthop, key),
2895 .head_offset = offsetof(struct mlxsw_sp_nexthop, ht_node),
2896 .key_len = sizeof(struct mlxsw_sp_nexthop_key),
2897 };
2898
mlxsw_sp_nexthop_insert(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)2899 static int mlxsw_sp_nexthop_insert(struct mlxsw_sp *mlxsw_sp,
2900 struct mlxsw_sp_nexthop *nh)
2901 {
2902 return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_ht,
2903 &nh->ht_node, mlxsw_sp_nexthop_ht_params);
2904 }
2905
mlxsw_sp_nexthop_remove(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)2906 static void mlxsw_sp_nexthop_remove(struct mlxsw_sp *mlxsw_sp,
2907 struct mlxsw_sp_nexthop *nh)
2908 {
2909 rhashtable_remove_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node,
2910 mlxsw_sp_nexthop_ht_params);
2911 }
2912
2913 static struct mlxsw_sp_nexthop *
mlxsw_sp_nexthop_lookup(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_key key)2914 mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp,
2915 struct mlxsw_sp_nexthop_key key)
2916 {
2917 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_ht, &key,
2918 mlxsw_sp_nexthop_ht_params);
2919 }
2920
mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fib * fib,u32 adj_index,u16 ecmp_size,u32 new_adj_index,u16 new_ecmp_size)2921 static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp *mlxsw_sp,
2922 const struct mlxsw_sp_fib *fib,
2923 u32 adj_index, u16 ecmp_size,
2924 u32 new_adj_index,
2925 u16 new_ecmp_size)
2926 {
2927 char raleu_pl[MLXSW_REG_RALEU_LEN];
2928
2929 mlxsw_reg_raleu_pack(raleu_pl,
2930 (enum mlxsw_reg_ralxx_protocol) fib->proto,
2931 fib->vr->id, adj_index, ecmp_size, new_adj_index,
2932 new_ecmp_size);
2933 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raleu), raleu_pl);
2934 }
2935
mlxsw_sp_adj_index_mass_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,u32 old_adj_index,u16 old_ecmp_size)2936 static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp,
2937 struct mlxsw_sp_nexthop_group *nh_grp,
2938 u32 old_adj_index, u16 old_ecmp_size)
2939 {
2940 struct mlxsw_sp_fib_entry *fib_entry;
2941 struct mlxsw_sp_fib *fib = NULL;
2942 int err;
2943
2944 list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
2945 if (fib == fib_entry->fib_node->fib)
2946 continue;
2947 fib = fib_entry->fib_node->fib;
2948 err = mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp, fib,
2949 old_adj_index,
2950 old_ecmp_size,
2951 nh_grp->adj_index,
2952 nh_grp->ecmp_size);
2953 if (err)
2954 return err;
2955 }
2956 return 0;
2957 }
2958
__mlxsw_sp_nexthop_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh)2959 static int __mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
2960 struct mlxsw_sp_nexthop *nh)
2961 {
2962 struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
2963 char ratr_pl[MLXSW_REG_RATR_LEN];
2964
2965 mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY,
2966 true, MLXSW_REG_RATR_TYPE_ETHERNET,
2967 adj_index, neigh_entry->rif);
2968 mlxsw_reg_ratr_eth_entry_pack(ratr_pl, neigh_entry->ha);
2969 if (nh->counter_valid)
2970 mlxsw_reg_ratr_counter_pack(ratr_pl, nh->counter_index, true);
2971 else
2972 mlxsw_reg_ratr_counter_pack(ratr_pl, 0, false);
2973
2974 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
2975 }
2976
mlxsw_sp_nexthop_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh)2977 int mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
2978 struct mlxsw_sp_nexthop *nh)
2979 {
2980 int i;
2981
2982 for (i = 0; i < nh->num_adj_entries; i++) {
2983 int err;
2984
2985 err = __mlxsw_sp_nexthop_update(mlxsw_sp, adj_index + i, nh);
2986 if (err)
2987 return err;
2988 }
2989
2990 return 0;
2991 }
2992
__mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh)2993 static int __mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp *mlxsw_sp,
2994 u32 adj_index,
2995 struct mlxsw_sp_nexthop *nh)
2996 {
2997 const struct mlxsw_sp_ipip_ops *ipip_ops;
2998
2999 ipip_ops = mlxsw_sp->router->ipip_ops_arr[nh->ipip_entry->ipipt];
3000 return ipip_ops->nexthop_update(mlxsw_sp, adj_index, nh->ipip_entry);
3001 }
3002
mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh)3003 static int mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp *mlxsw_sp,
3004 u32 adj_index,
3005 struct mlxsw_sp_nexthop *nh)
3006 {
3007 int i;
3008
3009 for (i = 0; i < nh->num_adj_entries; i++) {
3010 int err;
3011
3012 err = __mlxsw_sp_nexthop_ipip_update(mlxsw_sp, adj_index + i,
3013 nh);
3014 if (err)
3015 return err;
3016 }
3017
3018 return 0;
3019 }
3020
3021 static int
mlxsw_sp_nexthop_group_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,bool reallocate)3022 mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
3023 struct mlxsw_sp_nexthop_group *nh_grp,
3024 bool reallocate)
3025 {
3026 u32 adj_index = nh_grp->adj_index; /* base */
3027 struct mlxsw_sp_nexthop *nh;
3028 int i;
3029 int err;
3030
3031 for (i = 0; i < nh_grp->count; i++) {
3032 nh = &nh_grp->nexthops[i];
3033
3034 if (!nh->should_offload) {
3035 nh->offloaded = 0;
3036 continue;
3037 }
3038
3039 if (nh->update || reallocate) {
3040 switch (nh->type) {
3041 case MLXSW_SP_NEXTHOP_TYPE_ETH:
3042 err = mlxsw_sp_nexthop_update
3043 (mlxsw_sp, adj_index, nh);
3044 break;
3045 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
3046 err = mlxsw_sp_nexthop_ipip_update
3047 (mlxsw_sp, adj_index, nh);
3048 break;
3049 }
3050 if (err)
3051 return err;
3052 nh->update = 0;
3053 nh->offloaded = 1;
3054 }
3055 adj_index += nh->num_adj_entries;
3056 }
3057 return 0;
3058 }
3059
3060 static bool
3061 mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node,
3062 const struct mlxsw_sp_fib_entry *fib_entry);
3063
3064 static int
mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)3065 mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp,
3066 struct mlxsw_sp_nexthop_group *nh_grp)
3067 {
3068 struct mlxsw_sp_fib_entry *fib_entry;
3069 int err;
3070
3071 list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
3072 if (!mlxsw_sp_fib_node_entry_is_first(fib_entry->fib_node,
3073 fib_entry))
3074 continue;
3075 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
3076 if (err)
3077 return err;
3078 }
3079 return 0;
3080 }
3081
3082 static void
3083 mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry *fib_entry,
3084 enum mlxsw_reg_ralue_op op, int err);
3085
3086 static void
mlxsw_sp_nexthop_fib_entries_refresh(struct mlxsw_sp_nexthop_group * nh_grp)3087 mlxsw_sp_nexthop_fib_entries_refresh(struct mlxsw_sp_nexthop_group *nh_grp)
3088 {
3089 enum mlxsw_reg_ralue_op op = MLXSW_REG_RALUE_OP_WRITE_WRITE;
3090 struct mlxsw_sp_fib_entry *fib_entry;
3091
3092 list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
3093 if (!mlxsw_sp_fib_node_entry_is_first(fib_entry->fib_node,
3094 fib_entry))
3095 continue;
3096 mlxsw_sp_fib_entry_offload_refresh(fib_entry, op, 0);
3097 }
3098 }
3099
mlxsw_sp_adj_grp_size_round_up(u16 * p_adj_grp_size)3100 static void mlxsw_sp_adj_grp_size_round_up(u16 *p_adj_grp_size)
3101 {
3102 /* Valid sizes for an adjacency group are:
3103 * 1-64, 512, 1024, 2048 and 4096.
3104 */
3105 if (*p_adj_grp_size <= 64)
3106 return;
3107 else if (*p_adj_grp_size <= 512)
3108 *p_adj_grp_size = 512;
3109 else if (*p_adj_grp_size <= 1024)
3110 *p_adj_grp_size = 1024;
3111 else if (*p_adj_grp_size <= 2048)
3112 *p_adj_grp_size = 2048;
3113 else
3114 *p_adj_grp_size = 4096;
3115 }
3116
mlxsw_sp_adj_grp_size_round_down(u16 * p_adj_grp_size,unsigned int alloc_size)3117 static void mlxsw_sp_adj_grp_size_round_down(u16 *p_adj_grp_size,
3118 unsigned int alloc_size)
3119 {
3120 if (alloc_size >= 4096)
3121 *p_adj_grp_size = 4096;
3122 else if (alloc_size >= 2048)
3123 *p_adj_grp_size = 2048;
3124 else if (alloc_size >= 1024)
3125 *p_adj_grp_size = 1024;
3126 else if (alloc_size >= 512)
3127 *p_adj_grp_size = 512;
3128 }
3129
mlxsw_sp_fix_adj_grp_size(struct mlxsw_sp * mlxsw_sp,u16 * p_adj_grp_size)3130 static int mlxsw_sp_fix_adj_grp_size(struct mlxsw_sp *mlxsw_sp,
3131 u16 *p_adj_grp_size)
3132 {
3133 unsigned int alloc_size;
3134 int err;
3135
3136 /* Round up the requested group size to the next size supported
3137 * by the device and make sure the request can be satisfied.
3138 */
3139 mlxsw_sp_adj_grp_size_round_up(p_adj_grp_size);
3140 err = mlxsw_sp_kvdl_alloc_count_query(mlxsw_sp,
3141 MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
3142 *p_adj_grp_size, &alloc_size);
3143 if (err)
3144 return err;
3145 /* It is possible the allocation results in more allocated
3146 * entries than requested. Try to use as much of them as
3147 * possible.
3148 */
3149 mlxsw_sp_adj_grp_size_round_down(p_adj_grp_size, alloc_size);
3150
3151 return 0;
3152 }
3153
3154 static void
mlxsw_sp_nexthop_group_normalize(struct mlxsw_sp_nexthop_group * nh_grp)3155 mlxsw_sp_nexthop_group_normalize(struct mlxsw_sp_nexthop_group *nh_grp)
3156 {
3157 int i, g = 0, sum_norm_weight = 0;
3158 struct mlxsw_sp_nexthop *nh;
3159
3160 for (i = 0; i < nh_grp->count; i++) {
3161 nh = &nh_grp->nexthops[i];
3162
3163 if (!nh->should_offload)
3164 continue;
3165 if (g > 0)
3166 g = gcd(nh->nh_weight, g);
3167 else
3168 g = nh->nh_weight;
3169 }
3170
3171 for (i = 0; i < nh_grp->count; i++) {
3172 nh = &nh_grp->nexthops[i];
3173
3174 if (!nh->should_offload)
3175 continue;
3176 nh->norm_nh_weight = nh->nh_weight / g;
3177 sum_norm_weight += nh->norm_nh_weight;
3178 }
3179
3180 nh_grp->sum_norm_weight = sum_norm_weight;
3181 }
3182
3183 static void
mlxsw_sp_nexthop_group_rebalance(struct mlxsw_sp_nexthop_group * nh_grp)3184 mlxsw_sp_nexthop_group_rebalance(struct mlxsw_sp_nexthop_group *nh_grp)
3185 {
3186 int total = nh_grp->sum_norm_weight;
3187 u16 ecmp_size = nh_grp->ecmp_size;
3188 int i, weight = 0, lower_bound = 0;
3189
3190 for (i = 0; i < nh_grp->count; i++) {
3191 struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
3192 int upper_bound;
3193
3194 if (!nh->should_offload)
3195 continue;
3196 weight += nh->norm_nh_weight;
3197 upper_bound = DIV_ROUND_CLOSEST(ecmp_size * weight, total);
3198 nh->num_adj_entries = upper_bound - lower_bound;
3199 lower_bound = upper_bound;
3200 }
3201 }
3202
3203 static void
mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)3204 mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
3205 struct mlxsw_sp_nexthop_group *nh_grp)
3206 {
3207 u16 ecmp_size, old_ecmp_size;
3208 struct mlxsw_sp_nexthop *nh;
3209 bool offload_change = false;
3210 u32 adj_index;
3211 bool old_adj_index_valid;
3212 u32 old_adj_index;
3213 int i;
3214 int err;
3215
3216 if (!nh_grp->gateway) {
3217 mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
3218 return;
3219 }
3220
3221 for (i = 0; i < nh_grp->count; i++) {
3222 nh = &nh_grp->nexthops[i];
3223
3224 if (nh->should_offload != nh->offloaded) {
3225 offload_change = true;
3226 if (nh->should_offload)
3227 nh->update = 1;
3228 }
3229 }
3230 if (!offload_change) {
3231 /* Nothing was added or removed, so no need to reallocate. Just
3232 * update MAC on existing adjacency indexes.
3233 */
3234 err = mlxsw_sp_nexthop_group_update(mlxsw_sp, nh_grp, false);
3235 if (err) {
3236 dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
3237 goto set_trap;
3238 }
3239 return;
3240 }
3241 mlxsw_sp_nexthop_group_normalize(nh_grp);
3242 if (!nh_grp->sum_norm_weight)
3243 /* No neigh of this group is connected so we just set
3244 * the trap and let everthing flow through kernel.
3245 */
3246 goto set_trap;
3247
3248 ecmp_size = nh_grp->sum_norm_weight;
3249 err = mlxsw_sp_fix_adj_grp_size(mlxsw_sp, &ecmp_size);
3250 if (err)
3251 /* No valid allocation size available. */
3252 goto set_trap;
3253
3254 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
3255 ecmp_size, &adj_index);
3256 if (err) {
3257 /* We ran out of KVD linear space, just set the
3258 * trap and let everything flow through kernel.
3259 */
3260 dev_warn(mlxsw_sp->bus_info->dev, "Failed to allocate KVD linear area for nexthop group.\n");
3261 goto set_trap;
3262 }
3263 old_adj_index_valid = nh_grp->adj_index_valid;
3264 old_adj_index = nh_grp->adj_index;
3265 old_ecmp_size = nh_grp->ecmp_size;
3266 nh_grp->adj_index_valid = 1;
3267 nh_grp->adj_index = adj_index;
3268 nh_grp->ecmp_size = ecmp_size;
3269 mlxsw_sp_nexthop_group_rebalance(nh_grp);
3270 err = mlxsw_sp_nexthop_group_update(mlxsw_sp, nh_grp, true);
3271 if (err) {
3272 dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
3273 goto set_trap;
3274 }
3275
3276 if (!old_adj_index_valid) {
3277 /* The trap was set for fib entries, so we have to call
3278 * fib entry update to unset it and use adjacency index.
3279 */
3280 err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
3281 if (err) {
3282 dev_warn(mlxsw_sp->bus_info->dev, "Failed to add adjacency index to fib entries.\n");
3283 goto set_trap;
3284 }
3285 return;
3286 }
3287
3288 err = mlxsw_sp_adj_index_mass_update(mlxsw_sp, nh_grp,
3289 old_adj_index, old_ecmp_size);
3290 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
3291 old_ecmp_size, old_adj_index);
3292 if (err) {
3293 dev_warn(mlxsw_sp->bus_info->dev, "Failed to mass-update adjacency index for nexthop group.\n");
3294 goto set_trap;
3295 }
3296
3297 /* Offload state within the group changed, so update the flags. */
3298 mlxsw_sp_nexthop_fib_entries_refresh(nh_grp);
3299
3300 return;
3301
3302 set_trap:
3303 old_adj_index_valid = nh_grp->adj_index_valid;
3304 nh_grp->adj_index_valid = 0;
3305 for (i = 0; i < nh_grp->count; i++) {
3306 nh = &nh_grp->nexthops[i];
3307 nh->offloaded = 0;
3308 }
3309 err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
3310 if (err)
3311 dev_warn(mlxsw_sp->bus_info->dev, "Failed to set traps for fib entries.\n");
3312 if (old_adj_index_valid)
3313 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
3314 nh_grp->ecmp_size, nh_grp->adj_index);
3315 }
3316
__mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop * nh,bool removing)3317 static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
3318 bool removing)
3319 {
3320 if (!removing)
3321 nh->should_offload = 1;
3322 else
3323 nh->should_offload = 0;
3324 nh->update = 1;
3325 }
3326
3327 static int
mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)3328 mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp,
3329 struct mlxsw_sp_neigh_entry *neigh_entry)
3330 {
3331 struct neighbour *n, *old_n = neigh_entry->key.n;
3332 struct mlxsw_sp_nexthop *nh;
3333 bool entry_connected;
3334 u8 nud_state, dead;
3335 int err;
3336
3337 nh = list_first_entry(&neigh_entry->nexthop_list,
3338 struct mlxsw_sp_nexthop, neigh_list_node);
3339
3340 n = neigh_lookup(nh->nh_grp->neigh_tbl, &nh->gw_addr, nh->rif->dev);
3341 if (!n) {
3342 n = neigh_create(nh->nh_grp->neigh_tbl, &nh->gw_addr,
3343 nh->rif->dev);
3344 if (IS_ERR(n))
3345 return PTR_ERR(n);
3346 neigh_event_send(n, NULL);
3347 }
3348
3349 mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
3350 neigh_entry->key.n = n;
3351 err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
3352 if (err)
3353 goto err_neigh_entry_insert;
3354
3355 read_lock_bh(&n->lock);
3356 nud_state = n->nud_state;
3357 dead = n->dead;
3358 read_unlock_bh(&n->lock);
3359 entry_connected = nud_state & NUD_VALID && !dead;
3360
3361 list_for_each_entry(nh, &neigh_entry->nexthop_list,
3362 neigh_list_node) {
3363 neigh_release(old_n);
3364 neigh_clone(n);
3365 __mlxsw_sp_nexthop_neigh_update(nh, !entry_connected);
3366 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3367 }
3368
3369 neigh_release(n);
3370
3371 return 0;
3372
3373 err_neigh_entry_insert:
3374 neigh_entry->key.n = old_n;
3375 mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
3376 neigh_release(n);
3377 return err;
3378 }
3379
3380 static void
mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,bool removing,bool dead)3381 mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
3382 struct mlxsw_sp_neigh_entry *neigh_entry,
3383 bool removing, bool dead)
3384 {
3385 struct mlxsw_sp_nexthop *nh;
3386
3387 if (list_empty(&neigh_entry->nexthop_list))
3388 return;
3389
3390 if (dead) {
3391 int err;
3392
3393 err = mlxsw_sp_nexthop_dead_neigh_replace(mlxsw_sp,
3394 neigh_entry);
3395 if (err)
3396 dev_err(mlxsw_sp->bus_info->dev, "Failed to replace dead neigh\n");
3397 return;
3398 }
3399
3400 list_for_each_entry(nh, &neigh_entry->nexthop_list,
3401 neigh_list_node) {
3402 __mlxsw_sp_nexthop_neigh_update(nh, removing);
3403 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3404 }
3405 }
3406
mlxsw_sp_nexthop_rif_init(struct mlxsw_sp_nexthop * nh,struct mlxsw_sp_rif * rif)3407 static void mlxsw_sp_nexthop_rif_init(struct mlxsw_sp_nexthop *nh,
3408 struct mlxsw_sp_rif *rif)
3409 {
3410 if (nh->rif)
3411 return;
3412
3413 nh->rif = rif;
3414 list_add(&nh->rif_list_node, &rif->nexthop_list);
3415 }
3416
mlxsw_sp_nexthop_rif_fini(struct mlxsw_sp_nexthop * nh)3417 static void mlxsw_sp_nexthop_rif_fini(struct mlxsw_sp_nexthop *nh)
3418 {
3419 if (!nh->rif)
3420 return;
3421
3422 list_del(&nh->rif_list_node);
3423 nh->rif = NULL;
3424 }
3425
mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3426 static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
3427 struct mlxsw_sp_nexthop *nh)
3428 {
3429 struct mlxsw_sp_neigh_entry *neigh_entry;
3430 struct neighbour *n;
3431 u8 nud_state, dead;
3432 int err;
3433
3434 if (!nh->nh_grp->gateway || nh->neigh_entry)
3435 return 0;
3436
3437 /* Take a reference of neigh here ensuring that neigh would
3438 * not be destructed before the nexthop entry is finished.
3439 * The reference is taken either in neigh_lookup() or
3440 * in neigh_create() in case n is not found.
3441 */
3442 n = neigh_lookup(nh->nh_grp->neigh_tbl, &nh->gw_addr, nh->rif->dev);
3443 if (!n) {
3444 n = neigh_create(nh->nh_grp->neigh_tbl, &nh->gw_addr,
3445 nh->rif->dev);
3446 if (IS_ERR(n))
3447 return PTR_ERR(n);
3448 neigh_event_send(n, NULL);
3449 }
3450 neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
3451 if (!neigh_entry) {
3452 neigh_entry = mlxsw_sp_neigh_entry_create(mlxsw_sp, n);
3453 if (IS_ERR(neigh_entry)) {
3454 err = -EINVAL;
3455 goto err_neigh_entry_create;
3456 }
3457 }
3458
3459 /* If that is the first nexthop connected to that neigh, add to
3460 * nexthop_neighs_list
3461 */
3462 if (list_empty(&neigh_entry->nexthop_list))
3463 list_add_tail(&neigh_entry->nexthop_neighs_list_node,
3464 &mlxsw_sp->router->nexthop_neighs_list);
3465
3466 nh->neigh_entry = neigh_entry;
3467 list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list);
3468 read_lock_bh(&n->lock);
3469 nud_state = n->nud_state;
3470 dead = n->dead;
3471 read_unlock_bh(&n->lock);
3472 __mlxsw_sp_nexthop_neigh_update(nh, !(nud_state & NUD_VALID && !dead));
3473
3474 return 0;
3475
3476 err_neigh_entry_create:
3477 neigh_release(n);
3478 return err;
3479 }
3480
mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3481 static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp *mlxsw_sp,
3482 struct mlxsw_sp_nexthop *nh)
3483 {
3484 struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
3485 struct neighbour *n;
3486
3487 if (!neigh_entry)
3488 return;
3489 n = neigh_entry->key.n;
3490
3491 __mlxsw_sp_nexthop_neigh_update(nh, true);
3492 list_del(&nh->neigh_list_node);
3493 nh->neigh_entry = NULL;
3494
3495 /* If that is the last nexthop connected to that neigh, remove from
3496 * nexthop_neighs_list
3497 */
3498 if (list_empty(&neigh_entry->nexthop_list))
3499 list_del(&neigh_entry->nexthop_neighs_list_node);
3500
3501 if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list))
3502 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
3503
3504 neigh_release(n);
3505 }
3506
mlxsw_sp_ipip_netdev_ul_up(struct net_device * ol_dev)3507 static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev)
3508 {
3509 struct net_device *ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
3510
3511 return ul_dev ? (ul_dev->flags & IFF_UP) : true;
3512 }
3513
mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh,struct mlxsw_sp_ipip_entry * ipip_entry)3514 static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp,
3515 struct mlxsw_sp_nexthop *nh,
3516 struct mlxsw_sp_ipip_entry *ipip_entry)
3517 {
3518 bool removing;
3519
3520 if (!nh->nh_grp->gateway || nh->ipip_entry)
3521 return;
3522
3523 nh->ipip_entry = ipip_entry;
3524 removing = !mlxsw_sp_ipip_netdev_ul_up(ipip_entry->ol_dev);
3525 __mlxsw_sp_nexthop_neigh_update(nh, removing);
3526 mlxsw_sp_nexthop_rif_init(nh, &ipip_entry->ol_lb->common);
3527 }
3528
mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3529 static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp *mlxsw_sp,
3530 struct mlxsw_sp_nexthop *nh)
3531 {
3532 struct mlxsw_sp_ipip_entry *ipip_entry = nh->ipip_entry;
3533
3534 if (!ipip_entry)
3535 return;
3536
3537 __mlxsw_sp_nexthop_neigh_update(nh, true);
3538 nh->ipip_entry = NULL;
3539 }
3540
mlxsw_sp_nexthop4_ipip_type(const struct mlxsw_sp * mlxsw_sp,const struct fib_nh * fib_nh,enum mlxsw_sp_ipip_type * p_ipipt)3541 static bool mlxsw_sp_nexthop4_ipip_type(const struct mlxsw_sp *mlxsw_sp,
3542 const struct fib_nh *fib_nh,
3543 enum mlxsw_sp_ipip_type *p_ipipt)
3544 {
3545 struct net_device *dev = fib_nh->nh_dev;
3546
3547 return dev &&
3548 fib_nh->nh_parent->fib_type == RTN_UNICAST &&
3549 mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, p_ipipt);
3550 }
3551
mlxsw_sp_nexthop_type_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3552 static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp,
3553 struct mlxsw_sp_nexthop *nh)
3554 {
3555 switch (nh->type) {
3556 case MLXSW_SP_NEXTHOP_TYPE_ETH:
3557 mlxsw_sp_nexthop_neigh_fini(mlxsw_sp, nh);
3558 mlxsw_sp_nexthop_rif_fini(nh);
3559 break;
3560 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
3561 mlxsw_sp_nexthop_rif_fini(nh);
3562 mlxsw_sp_nexthop_ipip_fini(mlxsw_sp, nh);
3563 break;
3564 }
3565 }
3566
mlxsw_sp_nexthop4_type_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh,struct fib_nh * fib_nh)3567 static int mlxsw_sp_nexthop4_type_init(struct mlxsw_sp *mlxsw_sp,
3568 struct mlxsw_sp_nexthop *nh,
3569 struct fib_nh *fib_nh)
3570 {
3571 const struct mlxsw_sp_ipip_ops *ipip_ops;
3572 struct net_device *dev = fib_nh->nh_dev;
3573 struct mlxsw_sp_ipip_entry *ipip_entry;
3574 struct mlxsw_sp_rif *rif;
3575 int err;
3576
3577 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev);
3578 if (ipip_entry) {
3579 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
3580 if (ipip_ops->can_offload(mlxsw_sp, dev,
3581 MLXSW_SP_L3_PROTO_IPV4)) {
3582 nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
3583 mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, ipip_entry);
3584 return 0;
3585 }
3586 }
3587
3588 nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
3589 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
3590 if (!rif)
3591 return 0;
3592
3593 mlxsw_sp_nexthop_rif_init(nh, rif);
3594 err = mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
3595 if (err)
3596 goto err_neigh_init;
3597
3598 return 0;
3599
3600 err_neigh_init:
3601 mlxsw_sp_nexthop_rif_fini(nh);
3602 return err;
3603 }
3604
mlxsw_sp_nexthop4_type_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3605 static void mlxsw_sp_nexthop4_type_fini(struct mlxsw_sp *mlxsw_sp,
3606 struct mlxsw_sp_nexthop *nh)
3607 {
3608 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
3609 }
3610
mlxsw_sp_nexthop4_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_nexthop * nh,struct fib_nh * fib_nh)3611 static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
3612 struct mlxsw_sp_nexthop_group *nh_grp,
3613 struct mlxsw_sp_nexthop *nh,
3614 struct fib_nh *fib_nh)
3615 {
3616 struct net_device *dev = fib_nh->nh_dev;
3617 struct in_device *in_dev;
3618 int err;
3619
3620 nh->nh_grp = nh_grp;
3621 nh->key.fib_nh = fib_nh;
3622 #ifdef CONFIG_IP_ROUTE_MULTIPATH
3623 nh->nh_weight = fib_nh->nh_weight;
3624 #else
3625 nh->nh_weight = 1;
3626 #endif
3627 memcpy(&nh->gw_addr, &fib_nh->nh_gw, sizeof(fib_nh->nh_gw));
3628 err = mlxsw_sp_nexthop_insert(mlxsw_sp, nh);
3629 if (err)
3630 return err;
3631
3632 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
3633 list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
3634
3635 if (!dev)
3636 return 0;
3637
3638 in_dev = __in_dev_get_rtnl(dev);
3639 if (in_dev && IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
3640 fib_nh->nh_flags & RTNH_F_LINKDOWN)
3641 return 0;
3642
3643 err = mlxsw_sp_nexthop4_type_init(mlxsw_sp, nh, fib_nh);
3644 if (err)
3645 goto err_nexthop_neigh_init;
3646
3647 return 0;
3648
3649 err_nexthop_neigh_init:
3650 mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
3651 return err;
3652 }
3653
mlxsw_sp_nexthop4_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3654 static void mlxsw_sp_nexthop4_fini(struct mlxsw_sp *mlxsw_sp,
3655 struct mlxsw_sp_nexthop *nh)
3656 {
3657 mlxsw_sp_nexthop4_type_fini(mlxsw_sp, nh);
3658 list_del(&nh->router_list_node);
3659 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
3660 mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
3661 }
3662
mlxsw_sp_nexthop4_event(struct mlxsw_sp * mlxsw_sp,unsigned long event,struct fib_nh * fib_nh)3663 static void mlxsw_sp_nexthop4_event(struct mlxsw_sp *mlxsw_sp,
3664 unsigned long event, struct fib_nh *fib_nh)
3665 {
3666 struct mlxsw_sp_nexthop_key key;
3667 struct mlxsw_sp_nexthop *nh;
3668
3669 if (mlxsw_sp->router->aborted)
3670 return;
3671
3672 key.fib_nh = fib_nh;
3673 nh = mlxsw_sp_nexthop_lookup(mlxsw_sp, key);
3674 if (WARN_ON_ONCE(!nh))
3675 return;
3676
3677 switch (event) {
3678 case FIB_EVENT_NH_ADD:
3679 mlxsw_sp_nexthop4_type_init(mlxsw_sp, nh, fib_nh);
3680 break;
3681 case FIB_EVENT_NH_DEL:
3682 mlxsw_sp_nexthop4_type_fini(mlxsw_sp, nh);
3683 break;
3684 }
3685
3686 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3687 }
3688
mlxsw_sp_nexthop_rif_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)3689 static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
3690 struct mlxsw_sp_rif *rif)
3691 {
3692 struct mlxsw_sp_nexthop *nh;
3693 bool removing;
3694
3695 list_for_each_entry(nh, &rif->nexthop_list, rif_list_node) {
3696 switch (nh->type) {
3697 case MLXSW_SP_NEXTHOP_TYPE_ETH:
3698 removing = false;
3699 break;
3700 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
3701 removing = !mlxsw_sp_ipip_netdev_ul_up(rif->dev);
3702 break;
3703 default:
3704 WARN_ON(1);
3705 continue;
3706 }
3707
3708 __mlxsw_sp_nexthop_neigh_update(nh, removing);
3709 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3710 }
3711 }
3712
mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * old_rif,struct mlxsw_sp_rif * new_rif)3713 static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp,
3714 struct mlxsw_sp_rif *old_rif,
3715 struct mlxsw_sp_rif *new_rif)
3716 {
3717 struct mlxsw_sp_nexthop *nh;
3718
3719 list_splice_init(&old_rif->nexthop_list, &new_rif->nexthop_list);
3720 list_for_each_entry(nh, &new_rif->nexthop_list, rif_list_node)
3721 nh->rif = new_rif;
3722 mlxsw_sp_nexthop_rif_update(mlxsw_sp, new_rif);
3723 }
3724
mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)3725 static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
3726 struct mlxsw_sp_rif *rif)
3727 {
3728 struct mlxsw_sp_nexthop *nh, *tmp;
3729
3730 list_for_each_entry_safe(nh, tmp, &rif->nexthop_list, rif_list_node) {
3731 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
3732 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3733 }
3734 }
3735
mlxsw_sp_fi_is_gateway(const struct mlxsw_sp * mlxsw_sp,const struct fib_info * fi)3736 static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
3737 const struct fib_info *fi)
3738 {
3739 return fi->fib_nh->nh_scope == RT_SCOPE_LINK ||
3740 mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, fi->fib_nh, NULL);
3741 }
3742
3743 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop4_group_create(struct mlxsw_sp * mlxsw_sp,struct fib_info * fi)3744 mlxsw_sp_nexthop4_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
3745 {
3746 struct mlxsw_sp_nexthop_group *nh_grp;
3747 struct mlxsw_sp_nexthop *nh;
3748 struct fib_nh *fib_nh;
3749 size_t alloc_size;
3750 int i;
3751 int err;
3752
3753 alloc_size = sizeof(*nh_grp) +
3754 fi->fib_nhs * sizeof(struct mlxsw_sp_nexthop);
3755 nh_grp = kzalloc(alloc_size, GFP_KERNEL);
3756 if (!nh_grp)
3757 return ERR_PTR(-ENOMEM);
3758 nh_grp->priv = fi;
3759 INIT_LIST_HEAD(&nh_grp->fib_list);
3760 nh_grp->neigh_tbl = &arp_tbl;
3761
3762 nh_grp->gateway = mlxsw_sp_fi_is_gateway(mlxsw_sp, fi);
3763 nh_grp->count = fi->fib_nhs;
3764 fib_info_hold(fi);
3765 for (i = 0; i < nh_grp->count; i++) {
3766 nh = &nh_grp->nexthops[i];
3767 fib_nh = &fi->fib_nh[i];
3768 err = mlxsw_sp_nexthop4_init(mlxsw_sp, nh_grp, nh, fib_nh);
3769 if (err)
3770 goto err_nexthop4_init;
3771 }
3772 err = mlxsw_sp_nexthop_group_insert(mlxsw_sp, nh_grp);
3773 if (err)
3774 goto err_nexthop_group_insert;
3775 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
3776 return nh_grp;
3777
3778 err_nexthop_group_insert:
3779 err_nexthop4_init:
3780 for (i--; i >= 0; i--) {
3781 nh = &nh_grp->nexthops[i];
3782 mlxsw_sp_nexthop4_fini(mlxsw_sp, nh);
3783 }
3784 fib_info_put(fi);
3785 kfree(nh_grp);
3786 return ERR_PTR(err);
3787 }
3788
3789 static void
mlxsw_sp_nexthop4_group_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)3790 mlxsw_sp_nexthop4_group_destroy(struct mlxsw_sp *mlxsw_sp,
3791 struct mlxsw_sp_nexthop_group *nh_grp)
3792 {
3793 struct mlxsw_sp_nexthop *nh;
3794 int i;
3795
3796 mlxsw_sp_nexthop_group_remove(mlxsw_sp, nh_grp);
3797 for (i = 0; i < nh_grp->count; i++) {
3798 nh = &nh_grp->nexthops[i];
3799 mlxsw_sp_nexthop4_fini(mlxsw_sp, nh);
3800 }
3801 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
3802 WARN_ON_ONCE(nh_grp->adj_index_valid);
3803 fib_info_put(mlxsw_sp_nexthop4_group_fi(nh_grp));
3804 kfree(nh_grp);
3805 }
3806
mlxsw_sp_nexthop4_group_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,struct fib_info * fi)3807 static int mlxsw_sp_nexthop4_group_get(struct mlxsw_sp *mlxsw_sp,
3808 struct mlxsw_sp_fib_entry *fib_entry,
3809 struct fib_info *fi)
3810 {
3811 struct mlxsw_sp_nexthop_group *nh_grp;
3812
3813 nh_grp = mlxsw_sp_nexthop4_group_lookup(mlxsw_sp, fi);
3814 if (!nh_grp) {
3815 nh_grp = mlxsw_sp_nexthop4_group_create(mlxsw_sp, fi);
3816 if (IS_ERR(nh_grp))
3817 return PTR_ERR(nh_grp);
3818 }
3819 list_add_tail(&fib_entry->nexthop_group_node, &nh_grp->fib_list);
3820 fib_entry->nh_group = nh_grp;
3821 return 0;
3822 }
3823
mlxsw_sp_nexthop4_group_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)3824 static void mlxsw_sp_nexthop4_group_put(struct mlxsw_sp *mlxsw_sp,
3825 struct mlxsw_sp_fib_entry *fib_entry)
3826 {
3827 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
3828
3829 list_del(&fib_entry->nexthop_group_node);
3830 if (!list_empty(&nh_grp->fib_list))
3831 return;
3832 mlxsw_sp_nexthop4_group_destroy(mlxsw_sp, nh_grp);
3833 }
3834
3835 static bool
mlxsw_sp_fib4_entry_should_offload(const struct mlxsw_sp_fib_entry * fib_entry)3836 mlxsw_sp_fib4_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
3837 {
3838 struct mlxsw_sp_fib4_entry *fib4_entry;
3839
3840 fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
3841 common);
3842 return !fib4_entry->tos;
3843 }
3844
3845 static bool
mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry * fib_entry)3846 mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
3847 {
3848 struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
3849
3850 switch (fib_entry->fib_node->fib->proto) {
3851 case MLXSW_SP_L3_PROTO_IPV4:
3852 if (!mlxsw_sp_fib4_entry_should_offload(fib_entry))
3853 return false;
3854 break;
3855 case MLXSW_SP_L3_PROTO_IPV6:
3856 break;
3857 }
3858
3859 switch (fib_entry->type) {
3860 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
3861 return !!nh_group->adj_index_valid;
3862 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
3863 return !!nh_group->nh_rif;
3864 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
3865 return true;
3866 default:
3867 return false;
3868 }
3869 }
3870
3871 static struct mlxsw_sp_nexthop *
mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group * nh_grp,const struct mlxsw_sp_rt6 * mlxsw_sp_rt6)3872 mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
3873 const struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
3874 {
3875 int i;
3876
3877 for (i = 0; i < nh_grp->count; i++) {
3878 struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
3879 struct fib6_info *rt = mlxsw_sp_rt6->rt;
3880
3881 if (nh->rif && nh->rif->dev == rt->fib6_nh.nh_dev &&
3882 ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr,
3883 &rt->fib6_nh.nh_gw))
3884 return nh;
3885 continue;
3886 }
3887
3888 return NULL;
3889 }
3890
3891 static void
mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry * fib_entry)3892 mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
3893 {
3894 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
3895 int i;
3896
3897 if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ||
3898 fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP) {
3899 nh_grp->nexthops->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD;
3900 return;
3901 }
3902
3903 for (i = 0; i < nh_grp->count; i++) {
3904 struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
3905
3906 if (nh->offloaded)
3907 nh->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD;
3908 else
3909 nh->key.fib_nh->nh_flags &= ~RTNH_F_OFFLOAD;
3910 }
3911 }
3912
3913 static void
mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry * fib_entry)3914 mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
3915 {
3916 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
3917 int i;
3918
3919 if (!list_is_singular(&nh_grp->fib_list))
3920 return;
3921
3922 for (i = 0; i < nh_grp->count; i++) {
3923 struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
3924
3925 nh->key.fib_nh->nh_flags &= ~RTNH_F_OFFLOAD;
3926 }
3927 }
3928
3929 static void
mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry * fib_entry)3930 mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
3931 {
3932 struct mlxsw_sp_fib6_entry *fib6_entry;
3933 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
3934
3935 fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
3936 common);
3937
3938 if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL) {
3939 list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
3940 list)->rt->fib6_nh.nh_flags |= RTNH_F_OFFLOAD;
3941 return;
3942 }
3943
3944 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
3945 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
3946 struct mlxsw_sp_nexthop *nh;
3947
3948 nh = mlxsw_sp_rt6_nexthop(nh_grp, mlxsw_sp_rt6);
3949 if (nh && nh->offloaded)
3950 mlxsw_sp_rt6->rt->fib6_nh.nh_flags |= RTNH_F_OFFLOAD;
3951 else
3952 mlxsw_sp_rt6->rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD;
3953 }
3954 }
3955
3956 static void
mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry * fib_entry)3957 mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
3958 {
3959 struct mlxsw_sp_fib6_entry *fib6_entry;
3960 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
3961
3962 fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
3963 common);
3964 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
3965 struct fib6_info *rt = mlxsw_sp_rt6->rt;
3966
3967 rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD;
3968 }
3969 }
3970
mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry * fib_entry)3971 static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
3972 {
3973 switch (fib_entry->fib_node->fib->proto) {
3974 case MLXSW_SP_L3_PROTO_IPV4:
3975 mlxsw_sp_fib4_entry_offload_set(fib_entry);
3976 break;
3977 case MLXSW_SP_L3_PROTO_IPV6:
3978 mlxsw_sp_fib6_entry_offload_set(fib_entry);
3979 break;
3980 }
3981 }
3982
3983 static void
mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry * fib_entry)3984 mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
3985 {
3986 switch (fib_entry->fib_node->fib->proto) {
3987 case MLXSW_SP_L3_PROTO_IPV4:
3988 mlxsw_sp_fib4_entry_offload_unset(fib_entry);
3989 break;
3990 case MLXSW_SP_L3_PROTO_IPV6:
3991 mlxsw_sp_fib6_entry_offload_unset(fib_entry);
3992 break;
3993 }
3994 }
3995
3996 static void
mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op,int err)3997 mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry *fib_entry,
3998 enum mlxsw_reg_ralue_op op, int err)
3999 {
4000 switch (op) {
4001 case MLXSW_REG_RALUE_OP_WRITE_DELETE:
4002 return mlxsw_sp_fib_entry_offload_unset(fib_entry);
4003 case MLXSW_REG_RALUE_OP_WRITE_WRITE:
4004 if (err)
4005 return;
4006 if (mlxsw_sp_fib_entry_should_offload(fib_entry))
4007 mlxsw_sp_fib_entry_offload_set(fib_entry);
4008 else
4009 mlxsw_sp_fib_entry_offload_unset(fib_entry);
4010 return;
4011 default:
4012 return;
4013 }
4014 }
4015
4016 static void
mlxsw_sp_fib_entry_ralue_pack(char * ralue_pl,const struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)4017 mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl,
4018 const struct mlxsw_sp_fib_entry *fib_entry,
4019 enum mlxsw_reg_ralue_op op)
4020 {
4021 struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
4022 enum mlxsw_reg_ralxx_protocol proto;
4023 u32 *p_dip;
4024
4025 proto = (enum mlxsw_reg_ralxx_protocol) fib->proto;
4026
4027 switch (fib->proto) {
4028 case MLXSW_SP_L3_PROTO_IPV4:
4029 p_dip = (u32 *) fib_entry->fib_node->key.addr;
4030 mlxsw_reg_ralue_pack4(ralue_pl, proto, op, fib->vr->id,
4031 fib_entry->fib_node->key.prefix_len,
4032 *p_dip);
4033 break;
4034 case MLXSW_SP_L3_PROTO_IPV6:
4035 mlxsw_reg_ralue_pack6(ralue_pl, proto, op, fib->vr->id,
4036 fib_entry->fib_node->key.prefix_len,
4037 fib_entry->fib_node->key.addr);
4038 break;
4039 }
4040 }
4041
mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)4042 static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
4043 struct mlxsw_sp_fib_entry *fib_entry,
4044 enum mlxsw_reg_ralue_op op)
4045 {
4046 char ralue_pl[MLXSW_REG_RALUE_LEN];
4047 enum mlxsw_reg_ralue_trap_action trap_action;
4048 u16 trap_id = 0;
4049 u32 adjacency_index = 0;
4050 u16 ecmp_size = 0;
4051
4052 /* In case the nexthop group adjacency index is valid, use it
4053 * with provided ECMP size. Otherwise, setup trap and pass
4054 * traffic to kernel.
4055 */
4056 if (mlxsw_sp_fib_entry_should_offload(fib_entry)) {
4057 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
4058 adjacency_index = fib_entry->nh_group->adj_index;
4059 ecmp_size = fib_entry->nh_group->ecmp_size;
4060 } else {
4061 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
4062 trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
4063 }
4064
4065 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
4066 mlxsw_reg_ralue_act_remote_pack(ralue_pl, trap_action, trap_id,
4067 adjacency_index, ecmp_size);
4068 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4069 }
4070
mlxsw_sp_fib_entry_op_local(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)4071 static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp,
4072 struct mlxsw_sp_fib_entry *fib_entry,
4073 enum mlxsw_reg_ralue_op op)
4074 {
4075 struct mlxsw_sp_rif *rif = fib_entry->nh_group->nh_rif;
4076 enum mlxsw_reg_ralue_trap_action trap_action;
4077 char ralue_pl[MLXSW_REG_RALUE_LEN];
4078 u16 trap_id = 0;
4079 u16 rif_index = 0;
4080
4081 if (mlxsw_sp_fib_entry_should_offload(fib_entry)) {
4082 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
4083 rif_index = rif->rif_index;
4084 } else {
4085 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
4086 trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
4087 }
4088
4089 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
4090 mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id,
4091 rif_index);
4092 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4093 }
4094
mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)4095 static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp,
4096 struct mlxsw_sp_fib_entry *fib_entry,
4097 enum mlxsw_reg_ralue_op op)
4098 {
4099 char ralue_pl[MLXSW_REG_RALUE_LEN];
4100
4101 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
4102 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
4103 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4104 }
4105
4106 static int
mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)4107 mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
4108 struct mlxsw_sp_fib_entry *fib_entry,
4109 enum mlxsw_reg_ralue_op op)
4110 {
4111 struct mlxsw_sp_ipip_entry *ipip_entry = fib_entry->decap.ipip_entry;
4112 const struct mlxsw_sp_ipip_ops *ipip_ops;
4113
4114 if (WARN_ON(!ipip_entry))
4115 return -EINVAL;
4116
4117 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
4118 return ipip_ops->fib_entry_op(mlxsw_sp, ipip_entry, op,
4119 fib_entry->decap.tunnel_index);
4120 }
4121
__mlxsw_sp_fib_entry_op(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)4122 static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
4123 struct mlxsw_sp_fib_entry *fib_entry,
4124 enum mlxsw_reg_ralue_op op)
4125 {
4126 switch (fib_entry->type) {
4127 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
4128 return mlxsw_sp_fib_entry_op_remote(mlxsw_sp, fib_entry, op);
4129 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
4130 return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op);
4131 case MLXSW_SP_FIB_ENTRY_TYPE_TRAP:
4132 return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op);
4133 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
4134 return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp,
4135 fib_entry, op);
4136 }
4137 return -EINVAL;
4138 }
4139
mlxsw_sp_fib_entry_op(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)4140 static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
4141 struct mlxsw_sp_fib_entry *fib_entry,
4142 enum mlxsw_reg_ralue_op op)
4143 {
4144 int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op);
4145
4146 mlxsw_sp_fib_entry_offload_refresh(fib_entry, op, err);
4147
4148 return err;
4149 }
4150
mlxsw_sp_fib_entry_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)4151 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
4152 struct mlxsw_sp_fib_entry *fib_entry)
4153 {
4154 return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
4155 MLXSW_REG_RALUE_OP_WRITE_WRITE);
4156 }
4157
mlxsw_sp_fib_entry_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)4158 static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
4159 struct mlxsw_sp_fib_entry *fib_entry)
4160 {
4161 return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
4162 MLXSW_REG_RALUE_OP_WRITE_DELETE);
4163 }
4164
4165 static int
mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp * mlxsw_sp,const struct fib_entry_notifier_info * fen_info,struct mlxsw_sp_fib_entry * fib_entry)4166 mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
4167 const struct fib_entry_notifier_info *fen_info,
4168 struct mlxsw_sp_fib_entry *fib_entry)
4169 {
4170 union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) };
4171 struct net_device *dev = fen_info->fi->fib_dev;
4172 struct mlxsw_sp_ipip_entry *ipip_entry;
4173 struct fib_info *fi = fen_info->fi;
4174
4175 switch (fen_info->type) {
4176 case RTN_LOCAL:
4177 ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, dev,
4178 MLXSW_SP_L3_PROTO_IPV4, dip);
4179 if (ipip_entry && ipip_entry->ol_dev->flags & IFF_UP) {
4180 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
4181 return mlxsw_sp_fib_entry_decap_init(mlxsw_sp,
4182 fib_entry,
4183 ipip_entry);
4184 }
4185 /* fall through */
4186 case RTN_BROADCAST:
4187 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
4188 return 0;
4189 case RTN_UNREACHABLE: /* fall through */
4190 case RTN_BLACKHOLE: /* fall through */
4191 case RTN_PROHIBIT:
4192 /* Packets hitting these routes need to be trapped, but
4193 * can do so with a lower priority than packets directed
4194 * at the host, so use action type local instead of trap.
4195 */
4196 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
4197 return 0;
4198 case RTN_UNICAST:
4199 if (mlxsw_sp_fi_is_gateway(mlxsw_sp, fi))
4200 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
4201 else
4202 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
4203 return 0;
4204 default:
4205 return -EINVAL;
4206 }
4207 }
4208
4209 static struct mlxsw_sp_fib4_entry *
mlxsw_sp_fib4_entry_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node,const struct fib_entry_notifier_info * fen_info)4210 mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
4211 struct mlxsw_sp_fib_node *fib_node,
4212 const struct fib_entry_notifier_info *fen_info)
4213 {
4214 struct mlxsw_sp_fib4_entry *fib4_entry;
4215 struct mlxsw_sp_fib_entry *fib_entry;
4216 int err;
4217
4218 fib4_entry = kzalloc(sizeof(*fib4_entry), GFP_KERNEL);
4219 if (!fib4_entry)
4220 return ERR_PTR(-ENOMEM);
4221 fib_entry = &fib4_entry->common;
4222
4223 err = mlxsw_sp_fib4_entry_type_set(mlxsw_sp, fen_info, fib_entry);
4224 if (err)
4225 goto err_fib4_entry_type_set;
4226
4227 err = mlxsw_sp_nexthop4_group_get(mlxsw_sp, fib_entry, fen_info->fi);
4228 if (err)
4229 goto err_nexthop4_group_get;
4230
4231 fib4_entry->prio = fen_info->fi->fib_priority;
4232 fib4_entry->tb_id = fen_info->tb_id;
4233 fib4_entry->type = fen_info->type;
4234 fib4_entry->tos = fen_info->tos;
4235
4236 fib_entry->fib_node = fib_node;
4237
4238 return fib4_entry;
4239
4240 err_nexthop4_group_get:
4241 err_fib4_entry_type_set:
4242 kfree(fib4_entry);
4243 return ERR_PTR(err);
4244 }
4245
mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib4_entry * fib4_entry)4246 static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp,
4247 struct mlxsw_sp_fib4_entry *fib4_entry)
4248 {
4249 mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
4250 kfree(fib4_entry);
4251 }
4252
4253 static struct mlxsw_sp_fib4_entry *
mlxsw_sp_fib4_entry_lookup(struct mlxsw_sp * mlxsw_sp,const struct fib_entry_notifier_info * fen_info)4254 mlxsw_sp_fib4_entry_lookup(struct mlxsw_sp *mlxsw_sp,
4255 const struct fib_entry_notifier_info *fen_info)
4256 {
4257 struct mlxsw_sp_fib4_entry *fib4_entry;
4258 struct mlxsw_sp_fib_node *fib_node;
4259 struct mlxsw_sp_fib *fib;
4260 struct mlxsw_sp_vr *vr;
4261
4262 vr = mlxsw_sp_vr_find(mlxsw_sp, fen_info->tb_id);
4263 if (!vr)
4264 return NULL;
4265 fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV4);
4266
4267 fib_node = mlxsw_sp_fib_node_lookup(fib, &fen_info->dst,
4268 sizeof(fen_info->dst),
4269 fen_info->dst_len);
4270 if (!fib_node)
4271 return NULL;
4272
4273 list_for_each_entry(fib4_entry, &fib_node->entry_list, common.list) {
4274 if (fib4_entry->tb_id == fen_info->tb_id &&
4275 fib4_entry->tos == fen_info->tos &&
4276 fib4_entry->type == fen_info->type &&
4277 mlxsw_sp_nexthop4_group_fi(fib4_entry->common.nh_group) ==
4278 fen_info->fi) {
4279 return fib4_entry;
4280 }
4281 }
4282
4283 return NULL;
4284 }
4285
4286 static const struct rhashtable_params mlxsw_sp_fib_ht_params = {
4287 .key_offset = offsetof(struct mlxsw_sp_fib_node, key),
4288 .head_offset = offsetof(struct mlxsw_sp_fib_node, ht_node),
4289 .key_len = sizeof(struct mlxsw_sp_fib_key),
4290 .automatic_shrinking = true,
4291 };
4292
mlxsw_sp_fib_node_insert(struct mlxsw_sp_fib * fib,struct mlxsw_sp_fib_node * fib_node)4293 static int mlxsw_sp_fib_node_insert(struct mlxsw_sp_fib *fib,
4294 struct mlxsw_sp_fib_node *fib_node)
4295 {
4296 return rhashtable_insert_fast(&fib->ht, &fib_node->ht_node,
4297 mlxsw_sp_fib_ht_params);
4298 }
4299
mlxsw_sp_fib_node_remove(struct mlxsw_sp_fib * fib,struct mlxsw_sp_fib_node * fib_node)4300 static void mlxsw_sp_fib_node_remove(struct mlxsw_sp_fib *fib,
4301 struct mlxsw_sp_fib_node *fib_node)
4302 {
4303 rhashtable_remove_fast(&fib->ht, &fib_node->ht_node,
4304 mlxsw_sp_fib_ht_params);
4305 }
4306
4307 static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib * fib,const void * addr,size_t addr_len,unsigned char prefix_len)4308 mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
4309 size_t addr_len, unsigned char prefix_len)
4310 {
4311 struct mlxsw_sp_fib_key key;
4312
4313 memset(&key, 0, sizeof(key));
4314 memcpy(key.addr, addr, addr_len);
4315 key.prefix_len = prefix_len;
4316 return rhashtable_lookup_fast(&fib->ht, &key, mlxsw_sp_fib_ht_params);
4317 }
4318
4319 static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_create(struct mlxsw_sp_fib * fib,const void * addr,size_t addr_len,unsigned char prefix_len)4320 mlxsw_sp_fib_node_create(struct mlxsw_sp_fib *fib, const void *addr,
4321 size_t addr_len, unsigned char prefix_len)
4322 {
4323 struct mlxsw_sp_fib_node *fib_node;
4324
4325 fib_node = kzalloc(sizeof(*fib_node), GFP_KERNEL);
4326 if (!fib_node)
4327 return NULL;
4328
4329 INIT_LIST_HEAD(&fib_node->entry_list);
4330 list_add(&fib_node->list, &fib->node_list);
4331 memcpy(fib_node->key.addr, addr, addr_len);
4332 fib_node->key.prefix_len = prefix_len;
4333
4334 return fib_node;
4335 }
4336
mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node * fib_node)4337 static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node *fib_node)
4338 {
4339 list_del(&fib_node->list);
4340 WARN_ON(!list_empty(&fib_node->entry_list));
4341 kfree(fib_node);
4342 }
4343
4344 static bool
mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node * fib_node,const struct mlxsw_sp_fib_entry * fib_entry)4345 mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node *fib_node,
4346 const struct mlxsw_sp_fib_entry *fib_entry)
4347 {
4348 return list_first_entry(&fib_node->entry_list,
4349 struct mlxsw_sp_fib_entry, list) == fib_entry;
4350 }
4351
mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)4352 static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp,
4353 struct mlxsw_sp_fib_node *fib_node)
4354 {
4355 struct mlxsw_sp_prefix_usage req_prefix_usage;
4356 struct mlxsw_sp_fib *fib = fib_node->fib;
4357 struct mlxsw_sp_lpm_tree *lpm_tree;
4358 int err;
4359
4360 lpm_tree = mlxsw_sp->router->lpm.proto_trees[fib->proto];
4361 if (lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
4362 goto out;
4363
4364 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
4365 mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
4366 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
4367 fib->proto);
4368 if (IS_ERR(lpm_tree))
4369 return PTR_ERR(lpm_tree);
4370
4371 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
4372 if (err)
4373 goto err_lpm_tree_replace;
4374
4375 out:
4376 lpm_tree->prefix_ref_count[fib_node->key.prefix_len]++;
4377 return 0;
4378
4379 err_lpm_tree_replace:
4380 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
4381 return err;
4382 }
4383
mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)4384 static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp *mlxsw_sp,
4385 struct mlxsw_sp_fib_node *fib_node)
4386 {
4387 struct mlxsw_sp_lpm_tree *lpm_tree = fib_node->fib->lpm_tree;
4388 struct mlxsw_sp_prefix_usage req_prefix_usage;
4389 struct mlxsw_sp_fib *fib = fib_node->fib;
4390 int err;
4391
4392 if (--lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
4393 return;
4394 /* Try to construct a new LPM tree from the current prefix usage
4395 * minus the unused one. If we fail, continue using the old one.
4396 */
4397 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
4398 mlxsw_sp_prefix_usage_clear(&req_prefix_usage,
4399 fib_node->key.prefix_len);
4400 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
4401 fib->proto);
4402 if (IS_ERR(lpm_tree))
4403 return;
4404
4405 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
4406 if (err)
4407 goto err_lpm_tree_replace;
4408
4409 return;
4410
4411 err_lpm_tree_replace:
4412 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
4413 }
4414
mlxsw_sp_fib_node_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node,struct mlxsw_sp_fib * fib)4415 static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
4416 struct mlxsw_sp_fib_node *fib_node,
4417 struct mlxsw_sp_fib *fib)
4418 {
4419 int err;
4420
4421 err = mlxsw_sp_fib_node_insert(fib, fib_node);
4422 if (err)
4423 return err;
4424 fib_node->fib = fib;
4425
4426 err = mlxsw_sp_fib_lpm_tree_link(mlxsw_sp, fib_node);
4427 if (err)
4428 goto err_fib_lpm_tree_link;
4429
4430 return 0;
4431
4432 err_fib_lpm_tree_link:
4433 fib_node->fib = NULL;
4434 mlxsw_sp_fib_node_remove(fib, fib_node);
4435 return err;
4436 }
4437
mlxsw_sp_fib_node_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)4438 static void mlxsw_sp_fib_node_fini(struct mlxsw_sp *mlxsw_sp,
4439 struct mlxsw_sp_fib_node *fib_node)
4440 {
4441 struct mlxsw_sp_fib *fib = fib_node->fib;
4442
4443 mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp, fib_node);
4444 fib_node->fib = NULL;
4445 mlxsw_sp_fib_node_remove(fib, fib_node);
4446 }
4447
4448 static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_get(struct mlxsw_sp * mlxsw_sp,u32 tb_id,const void * addr,size_t addr_len,unsigned char prefix_len,enum mlxsw_sp_l3proto proto)4449 mlxsw_sp_fib_node_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, const void *addr,
4450 size_t addr_len, unsigned char prefix_len,
4451 enum mlxsw_sp_l3proto proto)
4452 {
4453 struct mlxsw_sp_fib_node *fib_node;
4454 struct mlxsw_sp_fib *fib;
4455 struct mlxsw_sp_vr *vr;
4456 int err;
4457
4458 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id, NULL);
4459 if (IS_ERR(vr))
4460 return ERR_CAST(vr);
4461 fib = mlxsw_sp_vr_fib(vr, proto);
4462
4463 fib_node = mlxsw_sp_fib_node_lookup(fib, addr, addr_len, prefix_len);
4464 if (fib_node)
4465 return fib_node;
4466
4467 fib_node = mlxsw_sp_fib_node_create(fib, addr, addr_len, prefix_len);
4468 if (!fib_node) {
4469 err = -ENOMEM;
4470 goto err_fib_node_create;
4471 }
4472
4473 err = mlxsw_sp_fib_node_init(mlxsw_sp, fib_node, fib);
4474 if (err)
4475 goto err_fib_node_init;
4476
4477 return fib_node;
4478
4479 err_fib_node_init:
4480 mlxsw_sp_fib_node_destroy(fib_node);
4481 err_fib_node_create:
4482 mlxsw_sp_vr_put(mlxsw_sp, vr);
4483 return ERR_PTR(err);
4484 }
4485
mlxsw_sp_fib_node_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)4486 static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp,
4487 struct mlxsw_sp_fib_node *fib_node)
4488 {
4489 struct mlxsw_sp_vr *vr = fib_node->fib->vr;
4490
4491 if (!list_empty(&fib_node->entry_list))
4492 return;
4493 mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node);
4494 mlxsw_sp_fib_node_destroy(fib_node);
4495 mlxsw_sp_vr_put(mlxsw_sp, vr);
4496 }
4497
4498 static struct mlxsw_sp_fib4_entry *
mlxsw_sp_fib4_node_entry_find(const struct mlxsw_sp_fib_node * fib_node,const struct mlxsw_sp_fib4_entry * new4_entry)4499 mlxsw_sp_fib4_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
4500 const struct mlxsw_sp_fib4_entry *new4_entry)
4501 {
4502 struct mlxsw_sp_fib4_entry *fib4_entry;
4503
4504 list_for_each_entry(fib4_entry, &fib_node->entry_list, common.list) {
4505 if (fib4_entry->tb_id > new4_entry->tb_id)
4506 continue;
4507 if (fib4_entry->tb_id != new4_entry->tb_id)
4508 break;
4509 if (fib4_entry->tos > new4_entry->tos)
4510 continue;
4511 if (fib4_entry->prio >= new4_entry->prio ||
4512 fib4_entry->tos < new4_entry->tos)
4513 return fib4_entry;
4514 }
4515
4516 return NULL;
4517 }
4518
4519 static int
mlxsw_sp_fib4_node_list_append(struct mlxsw_sp_fib4_entry * fib4_entry,struct mlxsw_sp_fib4_entry * new4_entry)4520 mlxsw_sp_fib4_node_list_append(struct mlxsw_sp_fib4_entry *fib4_entry,
4521 struct mlxsw_sp_fib4_entry *new4_entry)
4522 {
4523 struct mlxsw_sp_fib_node *fib_node;
4524
4525 if (WARN_ON(!fib4_entry))
4526 return -EINVAL;
4527
4528 fib_node = fib4_entry->common.fib_node;
4529 list_for_each_entry_from(fib4_entry, &fib_node->entry_list,
4530 common.list) {
4531 if (fib4_entry->tb_id != new4_entry->tb_id ||
4532 fib4_entry->tos != new4_entry->tos ||
4533 fib4_entry->prio != new4_entry->prio)
4534 break;
4535 }
4536
4537 list_add_tail(&new4_entry->common.list, &fib4_entry->common.list);
4538 return 0;
4539 }
4540
4541 static int
mlxsw_sp_fib4_node_list_insert(struct mlxsw_sp_fib4_entry * new4_entry,bool replace,bool append)4542 mlxsw_sp_fib4_node_list_insert(struct mlxsw_sp_fib4_entry *new4_entry,
4543 bool replace, bool append)
4544 {
4545 struct mlxsw_sp_fib_node *fib_node = new4_entry->common.fib_node;
4546 struct mlxsw_sp_fib4_entry *fib4_entry;
4547
4548 fib4_entry = mlxsw_sp_fib4_node_entry_find(fib_node, new4_entry);
4549
4550 if (append)
4551 return mlxsw_sp_fib4_node_list_append(fib4_entry, new4_entry);
4552 if (replace && WARN_ON(!fib4_entry))
4553 return -EINVAL;
4554
4555 /* Insert new entry before replaced one, so that we can later
4556 * remove the second.
4557 */
4558 if (fib4_entry) {
4559 list_add_tail(&new4_entry->common.list,
4560 &fib4_entry->common.list);
4561 } else {
4562 struct mlxsw_sp_fib4_entry *last;
4563
4564 list_for_each_entry(last, &fib_node->entry_list, common.list) {
4565 if (new4_entry->tb_id > last->tb_id)
4566 break;
4567 fib4_entry = last;
4568 }
4569
4570 if (fib4_entry)
4571 list_add(&new4_entry->common.list,
4572 &fib4_entry->common.list);
4573 else
4574 list_add(&new4_entry->common.list,
4575 &fib_node->entry_list);
4576 }
4577
4578 return 0;
4579 }
4580
4581 static void
mlxsw_sp_fib4_node_list_remove(struct mlxsw_sp_fib4_entry * fib4_entry)4582 mlxsw_sp_fib4_node_list_remove(struct mlxsw_sp_fib4_entry *fib4_entry)
4583 {
4584 list_del(&fib4_entry->common.list);
4585 }
4586
mlxsw_sp_fib_node_entry_add(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)4587 static int mlxsw_sp_fib_node_entry_add(struct mlxsw_sp *mlxsw_sp,
4588 struct mlxsw_sp_fib_entry *fib_entry)
4589 {
4590 struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
4591
4592 if (!mlxsw_sp_fib_node_entry_is_first(fib_node, fib_entry))
4593 return 0;
4594
4595 /* To prevent packet loss, overwrite the previously offloaded
4596 * entry.
4597 */
4598 if (!list_is_singular(&fib_node->entry_list)) {
4599 enum mlxsw_reg_ralue_op op = MLXSW_REG_RALUE_OP_WRITE_DELETE;
4600 struct mlxsw_sp_fib_entry *n = list_next_entry(fib_entry, list);
4601
4602 mlxsw_sp_fib_entry_offload_refresh(n, op, 0);
4603 }
4604
4605 return mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
4606 }
4607
mlxsw_sp_fib_node_entry_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)4608 static void mlxsw_sp_fib_node_entry_del(struct mlxsw_sp *mlxsw_sp,
4609 struct mlxsw_sp_fib_entry *fib_entry)
4610 {
4611 struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
4612
4613 if (!mlxsw_sp_fib_node_entry_is_first(fib_node, fib_entry))
4614 return;
4615
4616 /* Promote the next entry by overwriting the deleted entry */
4617 if (!list_is_singular(&fib_node->entry_list)) {
4618 struct mlxsw_sp_fib_entry *n = list_next_entry(fib_entry, list);
4619 enum mlxsw_reg_ralue_op op = MLXSW_REG_RALUE_OP_WRITE_DELETE;
4620
4621 mlxsw_sp_fib_entry_update(mlxsw_sp, n);
4622 mlxsw_sp_fib_entry_offload_refresh(fib_entry, op, 0);
4623 return;
4624 }
4625
4626 mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
4627 }
4628
mlxsw_sp_fib4_node_entry_link(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib4_entry * fib4_entry,bool replace,bool append)4629 static int mlxsw_sp_fib4_node_entry_link(struct mlxsw_sp *mlxsw_sp,
4630 struct mlxsw_sp_fib4_entry *fib4_entry,
4631 bool replace, bool append)
4632 {
4633 int err;
4634
4635 err = mlxsw_sp_fib4_node_list_insert(fib4_entry, replace, append);
4636 if (err)
4637 return err;
4638
4639 err = mlxsw_sp_fib_node_entry_add(mlxsw_sp, &fib4_entry->common);
4640 if (err)
4641 goto err_fib_node_entry_add;
4642
4643 return 0;
4644
4645 err_fib_node_entry_add:
4646 mlxsw_sp_fib4_node_list_remove(fib4_entry);
4647 return err;
4648 }
4649
4650 static void
mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib4_entry * fib4_entry)4651 mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
4652 struct mlxsw_sp_fib4_entry *fib4_entry)
4653 {
4654 mlxsw_sp_fib_node_entry_del(mlxsw_sp, &fib4_entry->common);
4655 mlxsw_sp_fib4_node_list_remove(fib4_entry);
4656
4657 if (fib4_entry->common.type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP)
4658 mlxsw_sp_fib_entry_decap_fini(mlxsw_sp, &fib4_entry->common);
4659 }
4660
mlxsw_sp_fib4_entry_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib4_entry * fib4_entry,bool replace)4661 static void mlxsw_sp_fib4_entry_replace(struct mlxsw_sp *mlxsw_sp,
4662 struct mlxsw_sp_fib4_entry *fib4_entry,
4663 bool replace)
4664 {
4665 struct mlxsw_sp_fib_node *fib_node = fib4_entry->common.fib_node;
4666 struct mlxsw_sp_fib4_entry *replaced;
4667
4668 if (!replace)
4669 return;
4670
4671 /* We inserted the new entry before replaced one */
4672 replaced = list_next_entry(fib4_entry, common.list);
4673
4674 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp, replaced);
4675 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, replaced);
4676 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
4677 }
4678
4679 static int
mlxsw_sp_router_fib4_add(struct mlxsw_sp * mlxsw_sp,const struct fib_entry_notifier_info * fen_info,bool replace,bool append)4680 mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp,
4681 const struct fib_entry_notifier_info *fen_info,
4682 bool replace, bool append)
4683 {
4684 struct mlxsw_sp_fib4_entry *fib4_entry;
4685 struct mlxsw_sp_fib_node *fib_node;
4686 int err;
4687
4688 if (mlxsw_sp->router->aborted)
4689 return 0;
4690
4691 fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, fen_info->tb_id,
4692 &fen_info->dst, sizeof(fen_info->dst),
4693 fen_info->dst_len,
4694 MLXSW_SP_L3_PROTO_IPV4);
4695 if (IS_ERR(fib_node)) {
4696 dev_warn(mlxsw_sp->bus_info->dev, "Failed to get FIB node\n");
4697 return PTR_ERR(fib_node);
4698 }
4699
4700 fib4_entry = mlxsw_sp_fib4_entry_create(mlxsw_sp, fib_node, fen_info);
4701 if (IS_ERR(fib4_entry)) {
4702 dev_warn(mlxsw_sp->bus_info->dev, "Failed to create FIB entry\n");
4703 err = PTR_ERR(fib4_entry);
4704 goto err_fib4_entry_create;
4705 }
4706
4707 err = mlxsw_sp_fib4_node_entry_link(mlxsw_sp, fib4_entry, replace,
4708 append);
4709 if (err) {
4710 dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n");
4711 goto err_fib4_node_entry_link;
4712 }
4713
4714 mlxsw_sp_fib4_entry_replace(mlxsw_sp, fib4_entry, replace);
4715
4716 return 0;
4717
4718 err_fib4_node_entry_link:
4719 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
4720 err_fib4_entry_create:
4721 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
4722 return err;
4723 }
4724
mlxsw_sp_router_fib4_del(struct mlxsw_sp * mlxsw_sp,struct fib_entry_notifier_info * fen_info)4725 static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
4726 struct fib_entry_notifier_info *fen_info)
4727 {
4728 struct mlxsw_sp_fib4_entry *fib4_entry;
4729 struct mlxsw_sp_fib_node *fib_node;
4730
4731 if (mlxsw_sp->router->aborted)
4732 return;
4733
4734 fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
4735 if (WARN_ON(!fib4_entry))
4736 return;
4737 fib_node = fib4_entry->common.fib_node;
4738
4739 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp, fib4_entry);
4740 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
4741 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
4742 }
4743
mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info * rt)4744 static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt)
4745 {
4746 /* Packets with link-local destination IP arriving to the router
4747 * are trapped to the CPU, so no need to program specific routes
4748 * for them.
4749 */
4750 if (ipv6_addr_type(&rt->fib6_dst.addr) & IPV6_ADDR_LINKLOCAL)
4751 return true;
4752
4753 /* Multicast routes aren't supported, so ignore them. Neighbour
4754 * Discovery packets are specifically trapped.
4755 */
4756 if (ipv6_addr_type(&rt->fib6_dst.addr) & IPV6_ADDR_MULTICAST)
4757 return true;
4758
4759 /* Cloned routes are irrelevant in the forwarding path. */
4760 if (rt->fib6_flags & RTF_CACHE)
4761 return true;
4762
4763 return false;
4764 }
4765
mlxsw_sp_rt6_create(struct fib6_info * rt)4766 static struct mlxsw_sp_rt6 *mlxsw_sp_rt6_create(struct fib6_info *rt)
4767 {
4768 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
4769
4770 mlxsw_sp_rt6 = kzalloc(sizeof(*mlxsw_sp_rt6), GFP_KERNEL);
4771 if (!mlxsw_sp_rt6)
4772 return ERR_PTR(-ENOMEM);
4773
4774 /* In case of route replace, replaced route is deleted with
4775 * no notification. Take reference to prevent accessing freed
4776 * memory.
4777 */
4778 mlxsw_sp_rt6->rt = rt;
4779 fib6_info_hold(rt);
4780
4781 return mlxsw_sp_rt6;
4782 }
4783
4784 #if IS_ENABLED(CONFIG_IPV6)
mlxsw_sp_rt6_release(struct fib6_info * rt)4785 static void mlxsw_sp_rt6_release(struct fib6_info *rt)
4786 {
4787 fib6_info_release(rt);
4788 }
4789 #else
mlxsw_sp_rt6_release(struct fib6_info * rt)4790 static void mlxsw_sp_rt6_release(struct fib6_info *rt)
4791 {
4792 }
4793 #endif
4794
mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 * mlxsw_sp_rt6)4795 static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
4796 {
4797 mlxsw_sp_rt6_release(mlxsw_sp_rt6->rt);
4798 kfree(mlxsw_sp_rt6);
4799 }
4800
mlxsw_sp_fib6_rt_can_mp(const struct fib6_info * rt)4801 static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt)
4802 {
4803 /* RTF_CACHE routes are ignored */
4804 return (rt->fib6_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY;
4805 }
4806
4807 static struct fib6_info *
mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry * fib6_entry)4808 mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
4809 {
4810 return list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
4811 list)->rt;
4812 }
4813
4814 static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node * fib_node,const struct fib6_info * nrt,bool replace)4815 mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,
4816 const struct fib6_info *nrt, bool replace)
4817 {
4818 struct mlxsw_sp_fib6_entry *fib6_entry;
4819
4820 if (!mlxsw_sp_fib6_rt_can_mp(nrt) || replace)
4821 return NULL;
4822
4823 list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
4824 struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
4825
4826 /* RT6_TABLE_LOCAL and RT6_TABLE_MAIN share the same
4827 * virtual router.
4828 */
4829 if (rt->fib6_table->tb6_id > nrt->fib6_table->tb6_id)
4830 continue;
4831 if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id)
4832 break;
4833 if (rt->fib6_metric < nrt->fib6_metric)
4834 continue;
4835 if (rt->fib6_metric == nrt->fib6_metric &&
4836 mlxsw_sp_fib6_rt_can_mp(rt))
4837 return fib6_entry;
4838 if (rt->fib6_metric > nrt->fib6_metric)
4839 break;
4840 }
4841
4842 return NULL;
4843 }
4844
4845 static struct mlxsw_sp_rt6 *
mlxsw_sp_fib6_entry_rt_find(const struct mlxsw_sp_fib6_entry * fib6_entry,const struct fib6_info * rt)4846 mlxsw_sp_fib6_entry_rt_find(const struct mlxsw_sp_fib6_entry *fib6_entry,
4847 const struct fib6_info *rt)
4848 {
4849 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
4850
4851 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
4852 if (mlxsw_sp_rt6->rt == rt)
4853 return mlxsw_sp_rt6;
4854 }
4855
4856 return NULL;
4857 }
4858
mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp * mlxsw_sp,const struct fib6_info * rt,enum mlxsw_sp_ipip_type * ret)4859 static bool mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp *mlxsw_sp,
4860 const struct fib6_info *rt,
4861 enum mlxsw_sp_ipip_type *ret)
4862 {
4863 return rt->fib6_nh.nh_dev &&
4864 mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh.nh_dev, ret);
4865 }
4866
mlxsw_sp_nexthop6_type_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_nexthop * nh,const struct fib6_info * rt)4867 static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
4868 struct mlxsw_sp_nexthop_group *nh_grp,
4869 struct mlxsw_sp_nexthop *nh,
4870 const struct fib6_info *rt)
4871 {
4872 const struct mlxsw_sp_ipip_ops *ipip_ops;
4873 struct mlxsw_sp_ipip_entry *ipip_entry;
4874 struct net_device *dev = rt->fib6_nh.nh_dev;
4875 struct mlxsw_sp_rif *rif;
4876 int err;
4877
4878 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev);
4879 if (ipip_entry) {
4880 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
4881 if (ipip_ops->can_offload(mlxsw_sp, dev,
4882 MLXSW_SP_L3_PROTO_IPV6)) {
4883 nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
4884 mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, ipip_entry);
4885 return 0;
4886 }
4887 }
4888
4889 nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
4890 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
4891 if (!rif)
4892 return 0;
4893 mlxsw_sp_nexthop_rif_init(nh, rif);
4894
4895 err = mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
4896 if (err)
4897 goto err_nexthop_neigh_init;
4898
4899 return 0;
4900
4901 err_nexthop_neigh_init:
4902 mlxsw_sp_nexthop_rif_fini(nh);
4903 return err;
4904 }
4905
mlxsw_sp_nexthop6_type_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4906 static void mlxsw_sp_nexthop6_type_fini(struct mlxsw_sp *mlxsw_sp,
4907 struct mlxsw_sp_nexthop *nh)
4908 {
4909 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
4910 }
4911
mlxsw_sp_nexthop6_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_nexthop * nh,const struct fib6_info * rt)4912 static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
4913 struct mlxsw_sp_nexthop_group *nh_grp,
4914 struct mlxsw_sp_nexthop *nh,
4915 const struct fib6_info *rt)
4916 {
4917 struct net_device *dev = rt->fib6_nh.nh_dev;
4918
4919 nh->nh_grp = nh_grp;
4920 nh->nh_weight = rt->fib6_nh.nh_weight;
4921 memcpy(&nh->gw_addr, &rt->fib6_nh.nh_gw, sizeof(nh->gw_addr));
4922 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
4923
4924 list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
4925
4926 if (!dev)
4927 return 0;
4928 nh->ifindex = dev->ifindex;
4929
4930 return mlxsw_sp_nexthop6_type_init(mlxsw_sp, nh_grp, nh, rt);
4931 }
4932
mlxsw_sp_nexthop6_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4933 static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
4934 struct mlxsw_sp_nexthop *nh)
4935 {
4936 mlxsw_sp_nexthop6_type_fini(mlxsw_sp, nh);
4937 list_del(&nh->router_list_node);
4938 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
4939 }
4940
mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp * mlxsw_sp,const struct fib6_info * rt)4941 static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
4942 const struct fib6_info *rt)
4943 {
4944 return rt->fib6_flags & RTF_GATEWAY ||
4945 mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
4946 }
4947
4948 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop6_group_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)4949 mlxsw_sp_nexthop6_group_create(struct mlxsw_sp *mlxsw_sp,
4950 struct mlxsw_sp_fib6_entry *fib6_entry)
4951 {
4952 struct mlxsw_sp_nexthop_group *nh_grp;
4953 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
4954 struct mlxsw_sp_nexthop *nh;
4955 size_t alloc_size;
4956 int i = 0;
4957 int err;
4958
4959 alloc_size = sizeof(*nh_grp) +
4960 fib6_entry->nrt6 * sizeof(struct mlxsw_sp_nexthop);
4961 nh_grp = kzalloc(alloc_size, GFP_KERNEL);
4962 if (!nh_grp)
4963 return ERR_PTR(-ENOMEM);
4964 INIT_LIST_HEAD(&nh_grp->fib_list);
4965 #if IS_ENABLED(CONFIG_IPV6)
4966 nh_grp->neigh_tbl = &nd_tbl;
4967 #endif
4968 mlxsw_sp_rt6 = list_first_entry(&fib6_entry->rt6_list,
4969 struct mlxsw_sp_rt6, list);
4970 nh_grp->gateway = mlxsw_sp_rt6_is_gateway(mlxsw_sp, mlxsw_sp_rt6->rt);
4971 nh_grp->count = fib6_entry->nrt6;
4972 for (i = 0; i < nh_grp->count; i++) {
4973 struct fib6_info *rt = mlxsw_sp_rt6->rt;
4974
4975 nh = &nh_grp->nexthops[i];
4976 err = mlxsw_sp_nexthop6_init(mlxsw_sp, nh_grp, nh, rt);
4977 if (err)
4978 goto err_nexthop6_init;
4979 mlxsw_sp_rt6 = list_next_entry(mlxsw_sp_rt6, list);
4980 }
4981
4982 err = mlxsw_sp_nexthop_group_insert(mlxsw_sp, nh_grp);
4983 if (err)
4984 goto err_nexthop_group_insert;
4985
4986 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
4987 return nh_grp;
4988
4989 err_nexthop_group_insert:
4990 err_nexthop6_init:
4991 for (i--; i >= 0; i--) {
4992 nh = &nh_grp->nexthops[i];
4993 mlxsw_sp_nexthop6_fini(mlxsw_sp, nh);
4994 }
4995 kfree(nh_grp);
4996 return ERR_PTR(err);
4997 }
4998
4999 static void
mlxsw_sp_nexthop6_group_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)5000 mlxsw_sp_nexthop6_group_destroy(struct mlxsw_sp *mlxsw_sp,
5001 struct mlxsw_sp_nexthop_group *nh_grp)
5002 {
5003 struct mlxsw_sp_nexthop *nh;
5004 int i = nh_grp->count;
5005
5006 mlxsw_sp_nexthop_group_remove(mlxsw_sp, nh_grp);
5007 for (i--; i >= 0; i--) {
5008 nh = &nh_grp->nexthops[i];
5009 mlxsw_sp_nexthop6_fini(mlxsw_sp, nh);
5010 }
5011 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
5012 WARN_ON(nh_grp->adj_index_valid);
5013 kfree(nh_grp);
5014 }
5015
mlxsw_sp_nexthop6_group_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)5016 static int mlxsw_sp_nexthop6_group_get(struct mlxsw_sp *mlxsw_sp,
5017 struct mlxsw_sp_fib6_entry *fib6_entry)
5018 {
5019 struct mlxsw_sp_nexthop_group *nh_grp;
5020
5021 nh_grp = mlxsw_sp_nexthop6_group_lookup(mlxsw_sp, fib6_entry);
5022 if (!nh_grp) {
5023 nh_grp = mlxsw_sp_nexthop6_group_create(mlxsw_sp, fib6_entry);
5024 if (IS_ERR(nh_grp))
5025 return PTR_ERR(nh_grp);
5026 }
5027
5028 list_add_tail(&fib6_entry->common.nexthop_group_node,
5029 &nh_grp->fib_list);
5030 fib6_entry->common.nh_group = nh_grp;
5031
5032 return 0;
5033 }
5034
mlxsw_sp_nexthop6_group_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)5035 static void mlxsw_sp_nexthop6_group_put(struct mlxsw_sp *mlxsw_sp,
5036 struct mlxsw_sp_fib_entry *fib_entry)
5037 {
5038 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
5039
5040 list_del(&fib_entry->nexthop_group_node);
5041 if (!list_empty(&nh_grp->fib_list))
5042 return;
5043 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, nh_grp);
5044 }
5045
5046 static int
mlxsw_sp_nexthop6_group_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)5047 mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
5048 struct mlxsw_sp_fib6_entry *fib6_entry)
5049 {
5050 struct mlxsw_sp_nexthop_group *old_nh_grp = fib6_entry->common.nh_group;
5051 int err;
5052
5053 fib6_entry->common.nh_group = NULL;
5054 list_del(&fib6_entry->common.nexthop_group_node);
5055
5056 err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
5057 if (err)
5058 goto err_nexthop6_group_get;
5059
5060 /* In case this entry is offloaded, then the adjacency index
5061 * currently associated with it in the device's table is that
5062 * of the old group. Start using the new one instead.
5063 */
5064 err = mlxsw_sp_fib_node_entry_add(mlxsw_sp, &fib6_entry->common);
5065 if (err)
5066 goto err_fib_node_entry_add;
5067
5068 if (list_empty(&old_nh_grp->fib_list))
5069 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, old_nh_grp);
5070
5071 return 0;
5072
5073 err_fib_node_entry_add:
5074 mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
5075 err_nexthop6_group_get:
5076 list_add_tail(&fib6_entry->common.nexthop_group_node,
5077 &old_nh_grp->fib_list);
5078 fib6_entry->common.nh_group = old_nh_grp;
5079 return err;
5080 }
5081
5082 static int
mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry,struct fib6_info * rt)5083 mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
5084 struct mlxsw_sp_fib6_entry *fib6_entry,
5085 struct fib6_info *rt)
5086 {
5087 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
5088 int err;
5089
5090 mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt);
5091 if (IS_ERR(mlxsw_sp_rt6))
5092 return PTR_ERR(mlxsw_sp_rt6);
5093
5094 list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
5095 fib6_entry->nrt6++;
5096
5097 err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
5098 if (err)
5099 goto err_nexthop6_group_update;
5100
5101 return 0;
5102
5103 err_nexthop6_group_update:
5104 fib6_entry->nrt6--;
5105 list_del(&mlxsw_sp_rt6->list);
5106 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5107 return err;
5108 }
5109
5110 static void
mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry,struct fib6_info * rt)5111 mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
5112 struct mlxsw_sp_fib6_entry *fib6_entry,
5113 struct fib6_info *rt)
5114 {
5115 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
5116
5117 mlxsw_sp_rt6 = mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt);
5118 if (WARN_ON(!mlxsw_sp_rt6))
5119 return;
5120
5121 fib6_entry->nrt6--;
5122 list_del(&mlxsw_sp_rt6->list);
5123 mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
5124 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5125 }
5126
mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,const struct fib6_info * rt)5127 static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
5128 struct mlxsw_sp_fib_entry *fib_entry,
5129 const struct fib6_info *rt)
5130 {
5131 /* Packets hitting RTF_REJECT routes need to be discarded by the
5132 * stack. We can rely on their destination device not having a
5133 * RIF (it's the loopback device) and can thus use action type
5134 * local, which will cause them to be trapped with a lower
5135 * priority than packets that need to be locally received.
5136 */
5137 if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
5138 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
5139 else if (rt->fib6_flags & RTF_REJECT)
5140 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
5141 else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt))
5142 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
5143 else
5144 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
5145 }
5146
5147 static void
mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry * fib6_entry)5148 mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry *fib6_entry)
5149 {
5150 struct mlxsw_sp_rt6 *mlxsw_sp_rt6, *tmp;
5151
5152 list_for_each_entry_safe(mlxsw_sp_rt6, tmp, &fib6_entry->rt6_list,
5153 list) {
5154 fib6_entry->nrt6--;
5155 list_del(&mlxsw_sp_rt6->list);
5156 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5157 }
5158 }
5159
5160 static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_entry_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node,struct fib6_info * rt)5161 mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
5162 struct mlxsw_sp_fib_node *fib_node,
5163 struct fib6_info *rt)
5164 {
5165 struct mlxsw_sp_fib6_entry *fib6_entry;
5166 struct mlxsw_sp_fib_entry *fib_entry;
5167 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
5168 int err;
5169
5170 fib6_entry = kzalloc(sizeof(*fib6_entry), GFP_KERNEL);
5171 if (!fib6_entry)
5172 return ERR_PTR(-ENOMEM);
5173 fib_entry = &fib6_entry->common;
5174
5175 mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt);
5176 if (IS_ERR(mlxsw_sp_rt6)) {
5177 err = PTR_ERR(mlxsw_sp_rt6);
5178 goto err_rt6_create;
5179 }
5180
5181 mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, mlxsw_sp_rt6->rt);
5182
5183 INIT_LIST_HEAD(&fib6_entry->rt6_list);
5184 list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
5185 fib6_entry->nrt6 = 1;
5186 err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
5187 if (err)
5188 goto err_nexthop6_group_get;
5189
5190 fib_entry->fib_node = fib_node;
5191
5192 return fib6_entry;
5193
5194 err_nexthop6_group_get:
5195 list_del(&mlxsw_sp_rt6->list);
5196 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5197 err_rt6_create:
5198 kfree(fib6_entry);
5199 return ERR_PTR(err);
5200 }
5201
mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)5202 static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
5203 struct mlxsw_sp_fib6_entry *fib6_entry)
5204 {
5205 mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
5206 mlxsw_sp_fib6_entry_rt_destroy_all(fib6_entry);
5207 WARN_ON(fib6_entry->nrt6);
5208 kfree(fib6_entry);
5209 }
5210
5211 static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node * fib_node,const struct fib6_info * nrt,bool replace)5212 mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
5213 const struct fib6_info *nrt, bool replace)
5214 {
5215 struct mlxsw_sp_fib6_entry *fib6_entry, *fallback = NULL;
5216
5217 list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
5218 struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
5219
5220 if (rt->fib6_table->tb6_id > nrt->fib6_table->tb6_id)
5221 continue;
5222 if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id)
5223 break;
5224 if (replace && rt->fib6_metric == nrt->fib6_metric) {
5225 if (mlxsw_sp_fib6_rt_can_mp(rt) ==
5226 mlxsw_sp_fib6_rt_can_mp(nrt))
5227 return fib6_entry;
5228 if (mlxsw_sp_fib6_rt_can_mp(nrt))
5229 fallback = fallback ?: fib6_entry;
5230 }
5231 if (rt->fib6_metric > nrt->fib6_metric)
5232 return fallback ?: fib6_entry;
5233 }
5234
5235 return fallback;
5236 }
5237
5238 static int
mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry * new6_entry,bool replace)5239 mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry,
5240 bool replace)
5241 {
5242 struct mlxsw_sp_fib_node *fib_node = new6_entry->common.fib_node;
5243 struct fib6_info *nrt = mlxsw_sp_fib6_entry_rt(new6_entry);
5244 struct mlxsw_sp_fib6_entry *fib6_entry;
5245
5246 fib6_entry = mlxsw_sp_fib6_node_entry_find(fib_node, nrt, replace);
5247
5248 if (replace && WARN_ON(!fib6_entry))
5249 return -EINVAL;
5250
5251 if (fib6_entry) {
5252 list_add_tail(&new6_entry->common.list,
5253 &fib6_entry->common.list);
5254 } else {
5255 struct mlxsw_sp_fib6_entry *last;
5256
5257 list_for_each_entry(last, &fib_node->entry_list, common.list) {
5258 struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(last);
5259
5260 if (nrt->fib6_table->tb6_id > rt->fib6_table->tb6_id)
5261 break;
5262 fib6_entry = last;
5263 }
5264
5265 if (fib6_entry)
5266 list_add(&new6_entry->common.list,
5267 &fib6_entry->common.list);
5268 else
5269 list_add(&new6_entry->common.list,
5270 &fib_node->entry_list);
5271 }
5272
5273 return 0;
5274 }
5275
5276 static void
mlxsw_sp_fib6_node_list_remove(struct mlxsw_sp_fib6_entry * fib6_entry)5277 mlxsw_sp_fib6_node_list_remove(struct mlxsw_sp_fib6_entry *fib6_entry)
5278 {
5279 list_del(&fib6_entry->common.list);
5280 }
5281
mlxsw_sp_fib6_node_entry_link(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry,bool replace)5282 static int mlxsw_sp_fib6_node_entry_link(struct mlxsw_sp *mlxsw_sp,
5283 struct mlxsw_sp_fib6_entry *fib6_entry,
5284 bool replace)
5285 {
5286 int err;
5287
5288 err = mlxsw_sp_fib6_node_list_insert(fib6_entry, replace);
5289 if (err)
5290 return err;
5291
5292 err = mlxsw_sp_fib_node_entry_add(mlxsw_sp, &fib6_entry->common);
5293 if (err)
5294 goto err_fib_node_entry_add;
5295
5296 return 0;
5297
5298 err_fib_node_entry_add:
5299 mlxsw_sp_fib6_node_list_remove(fib6_entry);
5300 return err;
5301 }
5302
5303 static void
mlxsw_sp_fib6_node_entry_unlink(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)5304 mlxsw_sp_fib6_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
5305 struct mlxsw_sp_fib6_entry *fib6_entry)
5306 {
5307 mlxsw_sp_fib_node_entry_del(mlxsw_sp, &fib6_entry->common);
5308 mlxsw_sp_fib6_node_list_remove(fib6_entry);
5309 }
5310
5311 static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp * mlxsw_sp,const struct fib6_info * rt)5312 mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
5313 const struct fib6_info *rt)
5314 {
5315 struct mlxsw_sp_fib6_entry *fib6_entry;
5316 struct mlxsw_sp_fib_node *fib_node;
5317 struct mlxsw_sp_fib *fib;
5318 struct mlxsw_sp_vr *vr;
5319
5320 vr = mlxsw_sp_vr_find(mlxsw_sp, rt->fib6_table->tb6_id);
5321 if (!vr)
5322 return NULL;
5323 fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV6);
5324
5325 fib_node = mlxsw_sp_fib_node_lookup(fib, &rt->fib6_dst.addr,
5326 sizeof(rt->fib6_dst.addr),
5327 rt->fib6_dst.plen);
5328 if (!fib_node)
5329 return NULL;
5330
5331 list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
5332 struct fib6_info *iter_rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
5333
5334 if (rt->fib6_table->tb6_id == iter_rt->fib6_table->tb6_id &&
5335 rt->fib6_metric == iter_rt->fib6_metric &&
5336 mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt))
5337 return fib6_entry;
5338 }
5339
5340 return NULL;
5341 }
5342
mlxsw_sp_fib6_entry_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry,bool replace)5343 static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp,
5344 struct mlxsw_sp_fib6_entry *fib6_entry,
5345 bool replace)
5346 {
5347 struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
5348 struct mlxsw_sp_fib6_entry *replaced;
5349
5350 if (!replace)
5351 return;
5352
5353 replaced = list_next_entry(fib6_entry, common.list);
5354
5355 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp, replaced);
5356 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, replaced);
5357 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5358 }
5359
mlxsw_sp_router_fib6_add(struct mlxsw_sp * mlxsw_sp,struct fib6_info * rt,bool replace)5360 static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
5361 struct fib6_info *rt, bool replace)
5362 {
5363 struct mlxsw_sp_fib6_entry *fib6_entry;
5364 struct mlxsw_sp_fib_node *fib_node;
5365 int err;
5366
5367 if (mlxsw_sp->router->aborted)
5368 return 0;
5369
5370 if (rt->fib6_src.plen)
5371 return -EINVAL;
5372
5373 if (mlxsw_sp_fib6_rt_should_ignore(rt))
5374 return 0;
5375
5376 fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->fib6_table->tb6_id,
5377 &rt->fib6_dst.addr,
5378 sizeof(rt->fib6_dst.addr),
5379 rt->fib6_dst.plen,
5380 MLXSW_SP_L3_PROTO_IPV6);
5381 if (IS_ERR(fib_node))
5382 return PTR_ERR(fib_node);
5383
5384 /* Before creating a new entry, try to append route to an existing
5385 * multipath entry.
5386 */
5387 fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, replace);
5388 if (fib6_entry) {
5389 err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt);
5390 if (err)
5391 goto err_fib6_entry_nexthop_add;
5392 return 0;
5393 }
5394
5395 fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt);
5396 if (IS_ERR(fib6_entry)) {
5397 err = PTR_ERR(fib6_entry);
5398 goto err_fib6_entry_create;
5399 }
5400
5401 err = mlxsw_sp_fib6_node_entry_link(mlxsw_sp, fib6_entry, replace);
5402 if (err)
5403 goto err_fib6_node_entry_link;
5404
5405 mlxsw_sp_fib6_entry_replace(mlxsw_sp, fib6_entry, replace);
5406
5407 return 0;
5408
5409 err_fib6_node_entry_link:
5410 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
5411 err_fib6_entry_create:
5412 err_fib6_entry_nexthop_add:
5413 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5414 return err;
5415 }
5416
mlxsw_sp_router_fib6_del(struct mlxsw_sp * mlxsw_sp,struct fib6_info * rt)5417 static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
5418 struct fib6_info *rt)
5419 {
5420 struct mlxsw_sp_fib6_entry *fib6_entry;
5421 struct mlxsw_sp_fib_node *fib_node;
5422
5423 if (mlxsw_sp->router->aborted)
5424 return;
5425
5426 if (mlxsw_sp_fib6_rt_should_ignore(rt))
5427 return;
5428
5429 fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt);
5430 if (WARN_ON(!fib6_entry))
5431 return;
5432
5433 /* If route is part of a multipath entry, but not the last one
5434 * removed, then only reduce its nexthop group.
5435 */
5436 if (!list_is_singular(&fib6_entry->rt6_list)) {
5437 mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt);
5438 return;
5439 }
5440
5441 fib_node = fib6_entry->common.fib_node;
5442
5443 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp, fib6_entry);
5444 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
5445 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5446 }
5447
__mlxsw_sp_router_set_abort_trap(struct mlxsw_sp * mlxsw_sp,enum mlxsw_reg_ralxx_protocol proto,u8 tree_id)5448 static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp,
5449 enum mlxsw_reg_ralxx_protocol proto,
5450 u8 tree_id)
5451 {
5452 char ralta_pl[MLXSW_REG_RALTA_LEN];
5453 char ralst_pl[MLXSW_REG_RALST_LEN];
5454 int i, err;
5455
5456 mlxsw_reg_ralta_pack(ralta_pl, true, proto, tree_id);
5457 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
5458 if (err)
5459 return err;
5460
5461 mlxsw_reg_ralst_pack(ralst_pl, 0xff, tree_id);
5462 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
5463 if (err)
5464 return err;
5465
5466 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
5467 struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
5468 char raltb_pl[MLXSW_REG_RALTB_LEN];
5469 char ralue_pl[MLXSW_REG_RALUE_LEN];
5470
5471 mlxsw_reg_raltb_pack(raltb_pl, vr->id, proto, tree_id);
5472 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb),
5473 raltb_pl);
5474 if (err)
5475 return err;
5476
5477 mlxsw_reg_ralue_pack(ralue_pl, proto,
5478 MLXSW_REG_RALUE_OP_WRITE_WRITE, vr->id, 0);
5479 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
5480 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue),
5481 ralue_pl);
5482 if (err)
5483 return err;
5484 }
5485
5486 return 0;
5487 }
5488
5489 static struct mlxsw_sp_mr_table *
mlxsw_sp_router_fibmr_family_to_table(struct mlxsw_sp_vr * vr,int family)5490 mlxsw_sp_router_fibmr_family_to_table(struct mlxsw_sp_vr *vr, int family)
5491 {
5492 if (family == RTNL_FAMILY_IPMR)
5493 return vr->mr_table[MLXSW_SP_L3_PROTO_IPV4];
5494 else
5495 return vr->mr_table[MLXSW_SP_L3_PROTO_IPV6];
5496 }
5497
mlxsw_sp_router_fibmr_add(struct mlxsw_sp * mlxsw_sp,struct mfc_entry_notifier_info * men_info,bool replace)5498 static int mlxsw_sp_router_fibmr_add(struct mlxsw_sp *mlxsw_sp,
5499 struct mfc_entry_notifier_info *men_info,
5500 bool replace)
5501 {
5502 struct mlxsw_sp_mr_table *mrt;
5503 struct mlxsw_sp_vr *vr;
5504
5505 if (mlxsw_sp->router->aborted)
5506 return 0;
5507
5508 vr = mlxsw_sp_vr_get(mlxsw_sp, men_info->tb_id, NULL);
5509 if (IS_ERR(vr))
5510 return PTR_ERR(vr);
5511
5512 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, men_info->info.family);
5513 return mlxsw_sp_mr_route_add(mrt, men_info->mfc, replace);
5514 }
5515
mlxsw_sp_router_fibmr_del(struct mlxsw_sp * mlxsw_sp,struct mfc_entry_notifier_info * men_info)5516 static void mlxsw_sp_router_fibmr_del(struct mlxsw_sp *mlxsw_sp,
5517 struct mfc_entry_notifier_info *men_info)
5518 {
5519 struct mlxsw_sp_mr_table *mrt;
5520 struct mlxsw_sp_vr *vr;
5521
5522 if (mlxsw_sp->router->aborted)
5523 return;
5524
5525 vr = mlxsw_sp_vr_find(mlxsw_sp, men_info->tb_id);
5526 if (WARN_ON(!vr))
5527 return;
5528
5529 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, men_info->info.family);
5530 mlxsw_sp_mr_route_del(mrt, men_info->mfc);
5531 mlxsw_sp_vr_put(mlxsw_sp, vr);
5532 }
5533
5534 static int
mlxsw_sp_router_fibmr_vif_add(struct mlxsw_sp * mlxsw_sp,struct vif_entry_notifier_info * ven_info)5535 mlxsw_sp_router_fibmr_vif_add(struct mlxsw_sp *mlxsw_sp,
5536 struct vif_entry_notifier_info *ven_info)
5537 {
5538 struct mlxsw_sp_mr_table *mrt;
5539 struct mlxsw_sp_rif *rif;
5540 struct mlxsw_sp_vr *vr;
5541
5542 if (mlxsw_sp->router->aborted)
5543 return 0;
5544
5545 vr = mlxsw_sp_vr_get(mlxsw_sp, ven_info->tb_id, NULL);
5546 if (IS_ERR(vr))
5547 return PTR_ERR(vr);
5548
5549 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, ven_info->info.family);
5550 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, ven_info->dev);
5551 return mlxsw_sp_mr_vif_add(mrt, ven_info->dev,
5552 ven_info->vif_index,
5553 ven_info->vif_flags, rif);
5554 }
5555
5556 static void
mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp * mlxsw_sp,struct vif_entry_notifier_info * ven_info)5557 mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp,
5558 struct vif_entry_notifier_info *ven_info)
5559 {
5560 struct mlxsw_sp_mr_table *mrt;
5561 struct mlxsw_sp_vr *vr;
5562
5563 if (mlxsw_sp->router->aborted)
5564 return;
5565
5566 vr = mlxsw_sp_vr_find(mlxsw_sp, ven_info->tb_id);
5567 if (WARN_ON(!vr))
5568 return;
5569
5570 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, ven_info->info.family);
5571 mlxsw_sp_mr_vif_del(mrt, ven_info->vif_index);
5572 mlxsw_sp_vr_put(mlxsw_sp, vr);
5573 }
5574
mlxsw_sp_router_set_abort_trap(struct mlxsw_sp * mlxsw_sp)5575 static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
5576 {
5577 enum mlxsw_reg_ralxx_protocol proto = MLXSW_REG_RALXX_PROTOCOL_IPV4;
5578 int err;
5579
5580 err = __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto,
5581 MLXSW_SP_LPM_TREE_MIN);
5582 if (err)
5583 return err;
5584
5585 /* The multicast router code does not need an abort trap as by default,
5586 * packets that don't match any routes are trapped to the CPU.
5587 */
5588
5589 proto = MLXSW_REG_RALXX_PROTOCOL_IPV6;
5590 return __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto,
5591 MLXSW_SP_LPM_TREE_MIN + 1);
5592 }
5593
mlxsw_sp_fib4_node_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)5594 static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp *mlxsw_sp,
5595 struct mlxsw_sp_fib_node *fib_node)
5596 {
5597 struct mlxsw_sp_fib4_entry *fib4_entry, *tmp;
5598
5599 list_for_each_entry_safe(fib4_entry, tmp, &fib_node->entry_list,
5600 common.list) {
5601 bool do_break = &tmp->common.list == &fib_node->entry_list;
5602
5603 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp, fib4_entry);
5604 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
5605 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5606 /* Break when entry list is empty and node was freed.
5607 * Otherwise, we'll access freed memory in the next
5608 * iteration.
5609 */
5610 if (do_break)
5611 break;
5612 }
5613 }
5614
mlxsw_sp_fib6_node_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)5615 static void mlxsw_sp_fib6_node_flush(struct mlxsw_sp *mlxsw_sp,
5616 struct mlxsw_sp_fib_node *fib_node)
5617 {
5618 struct mlxsw_sp_fib6_entry *fib6_entry, *tmp;
5619
5620 list_for_each_entry_safe(fib6_entry, tmp, &fib_node->entry_list,
5621 common.list) {
5622 bool do_break = &tmp->common.list == &fib_node->entry_list;
5623
5624 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp, fib6_entry);
5625 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
5626 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5627 if (do_break)
5628 break;
5629 }
5630 }
5631
mlxsw_sp_fib_node_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)5632 static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp,
5633 struct mlxsw_sp_fib_node *fib_node)
5634 {
5635 switch (fib_node->fib->proto) {
5636 case MLXSW_SP_L3_PROTO_IPV4:
5637 mlxsw_sp_fib4_node_flush(mlxsw_sp, fib_node);
5638 break;
5639 case MLXSW_SP_L3_PROTO_IPV6:
5640 mlxsw_sp_fib6_node_flush(mlxsw_sp, fib_node);
5641 break;
5642 }
5643 }
5644
mlxsw_sp_vr_fib_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr,enum mlxsw_sp_l3proto proto)5645 static void mlxsw_sp_vr_fib_flush(struct mlxsw_sp *mlxsw_sp,
5646 struct mlxsw_sp_vr *vr,
5647 enum mlxsw_sp_l3proto proto)
5648 {
5649 struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
5650 struct mlxsw_sp_fib_node *fib_node, *tmp;
5651
5652 list_for_each_entry_safe(fib_node, tmp, &fib->node_list, list) {
5653 bool do_break = &tmp->list == &fib->node_list;
5654
5655 mlxsw_sp_fib_node_flush(mlxsw_sp, fib_node);
5656 if (do_break)
5657 break;
5658 }
5659 }
5660
mlxsw_sp_router_fib_flush(struct mlxsw_sp * mlxsw_sp)5661 static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
5662 {
5663 int i, j;
5664
5665 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
5666 struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
5667
5668 if (!mlxsw_sp_vr_is_used(vr))
5669 continue;
5670
5671 for (j = 0; j < MLXSW_SP_L3_PROTO_MAX; j++)
5672 mlxsw_sp_mr_table_flush(vr->mr_table[j]);
5673 mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
5674
5675 /* If virtual router was only used for IPv4, then it's no
5676 * longer used.
5677 */
5678 if (!mlxsw_sp_vr_is_used(vr))
5679 continue;
5680 mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
5681 }
5682 }
5683
mlxsw_sp_router_fib_abort(struct mlxsw_sp * mlxsw_sp)5684 static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp)
5685 {
5686 int err;
5687
5688 if (mlxsw_sp->router->aborted)
5689 return;
5690 dev_warn(mlxsw_sp->bus_info->dev, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n");
5691 mlxsw_sp_router_fib_flush(mlxsw_sp);
5692 mlxsw_sp->router->aborted = true;
5693 err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
5694 if (err)
5695 dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
5696 }
5697
5698 struct mlxsw_sp_fib_event_work {
5699 struct work_struct work;
5700 union {
5701 struct fib6_entry_notifier_info fen6_info;
5702 struct fib_entry_notifier_info fen_info;
5703 struct fib_rule_notifier_info fr_info;
5704 struct fib_nh_notifier_info fnh_info;
5705 struct mfc_entry_notifier_info men_info;
5706 struct vif_entry_notifier_info ven_info;
5707 };
5708 struct mlxsw_sp *mlxsw_sp;
5709 unsigned long event;
5710 };
5711
mlxsw_sp_router_fib4_event_work(struct work_struct * work)5712 static void mlxsw_sp_router_fib4_event_work(struct work_struct *work)
5713 {
5714 struct mlxsw_sp_fib_event_work *fib_work =
5715 container_of(work, struct mlxsw_sp_fib_event_work, work);
5716 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
5717 bool replace, append;
5718 int err;
5719
5720 /* Protect internal structures from changes */
5721 rtnl_lock();
5722 mlxsw_sp_span_respin(mlxsw_sp);
5723
5724 switch (fib_work->event) {
5725 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
5726 case FIB_EVENT_ENTRY_APPEND: /* fall through */
5727 case FIB_EVENT_ENTRY_ADD:
5728 replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
5729 append = fib_work->event == FIB_EVENT_ENTRY_APPEND;
5730 err = mlxsw_sp_router_fib4_add(mlxsw_sp, &fib_work->fen_info,
5731 replace, append);
5732 if (err)
5733 mlxsw_sp_router_fib_abort(mlxsw_sp);
5734 fib_info_put(fib_work->fen_info.fi);
5735 break;
5736 case FIB_EVENT_ENTRY_DEL:
5737 mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info);
5738 fib_info_put(fib_work->fen_info.fi);
5739 break;
5740 case FIB_EVENT_RULE_ADD:
5741 /* if we get here, a rule was added that we do not support.
5742 * just do the fib_abort
5743 */
5744 mlxsw_sp_router_fib_abort(mlxsw_sp);
5745 break;
5746 case FIB_EVENT_NH_ADD: /* fall through */
5747 case FIB_EVENT_NH_DEL:
5748 mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event,
5749 fib_work->fnh_info.fib_nh);
5750 fib_info_put(fib_work->fnh_info.fib_nh->nh_parent);
5751 break;
5752 }
5753 rtnl_unlock();
5754 kfree(fib_work);
5755 }
5756
mlxsw_sp_router_fib6_event_work(struct work_struct * work)5757 static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
5758 {
5759 struct mlxsw_sp_fib_event_work *fib_work =
5760 container_of(work, struct mlxsw_sp_fib_event_work, work);
5761 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
5762 bool replace;
5763 int err;
5764
5765 rtnl_lock();
5766 mlxsw_sp_span_respin(mlxsw_sp);
5767
5768 switch (fib_work->event) {
5769 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
5770 case FIB_EVENT_ENTRY_APPEND: /* fall through */
5771 case FIB_EVENT_ENTRY_ADD:
5772 replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
5773 err = mlxsw_sp_router_fib6_add(mlxsw_sp,
5774 fib_work->fen6_info.rt, replace);
5775 if (err)
5776 mlxsw_sp_router_fib_abort(mlxsw_sp);
5777 mlxsw_sp_rt6_release(fib_work->fen6_info.rt);
5778 break;
5779 case FIB_EVENT_ENTRY_DEL:
5780 mlxsw_sp_router_fib6_del(mlxsw_sp, fib_work->fen6_info.rt);
5781 mlxsw_sp_rt6_release(fib_work->fen6_info.rt);
5782 break;
5783 case FIB_EVENT_RULE_ADD:
5784 /* if we get here, a rule was added that we do not support.
5785 * just do the fib_abort
5786 */
5787 mlxsw_sp_router_fib_abort(mlxsw_sp);
5788 break;
5789 }
5790 rtnl_unlock();
5791 kfree(fib_work);
5792 }
5793
mlxsw_sp_router_fibmr_event_work(struct work_struct * work)5794 static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work)
5795 {
5796 struct mlxsw_sp_fib_event_work *fib_work =
5797 container_of(work, struct mlxsw_sp_fib_event_work, work);
5798 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
5799 bool replace;
5800 int err;
5801
5802 rtnl_lock();
5803 switch (fib_work->event) {
5804 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
5805 case FIB_EVENT_ENTRY_ADD:
5806 replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
5807
5808 err = mlxsw_sp_router_fibmr_add(mlxsw_sp, &fib_work->men_info,
5809 replace);
5810 if (err)
5811 mlxsw_sp_router_fib_abort(mlxsw_sp);
5812 mr_cache_put(fib_work->men_info.mfc);
5813 break;
5814 case FIB_EVENT_ENTRY_DEL:
5815 mlxsw_sp_router_fibmr_del(mlxsw_sp, &fib_work->men_info);
5816 mr_cache_put(fib_work->men_info.mfc);
5817 break;
5818 case FIB_EVENT_VIF_ADD:
5819 err = mlxsw_sp_router_fibmr_vif_add(mlxsw_sp,
5820 &fib_work->ven_info);
5821 if (err)
5822 mlxsw_sp_router_fib_abort(mlxsw_sp);
5823 dev_put(fib_work->ven_info.dev);
5824 break;
5825 case FIB_EVENT_VIF_DEL:
5826 mlxsw_sp_router_fibmr_vif_del(mlxsw_sp,
5827 &fib_work->ven_info);
5828 dev_put(fib_work->ven_info.dev);
5829 break;
5830 case FIB_EVENT_RULE_ADD:
5831 /* if we get here, a rule was added that we do not support.
5832 * just do the fib_abort
5833 */
5834 mlxsw_sp_router_fib_abort(mlxsw_sp);
5835 break;
5836 }
5837 rtnl_unlock();
5838 kfree(fib_work);
5839 }
5840
mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work * fib_work,struct fib_notifier_info * info)5841 static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work,
5842 struct fib_notifier_info *info)
5843 {
5844 struct fib_entry_notifier_info *fen_info;
5845 struct fib_nh_notifier_info *fnh_info;
5846
5847 switch (fib_work->event) {
5848 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
5849 case FIB_EVENT_ENTRY_APPEND: /* fall through */
5850 case FIB_EVENT_ENTRY_ADD: /* fall through */
5851 case FIB_EVENT_ENTRY_DEL:
5852 fen_info = container_of(info, struct fib_entry_notifier_info,
5853 info);
5854 fib_work->fen_info = *fen_info;
5855 /* Take reference on fib_info to prevent it from being
5856 * freed while work is queued. Release it afterwards.
5857 */
5858 fib_info_hold(fib_work->fen_info.fi);
5859 break;
5860 case FIB_EVENT_NH_ADD: /* fall through */
5861 case FIB_EVENT_NH_DEL:
5862 fnh_info = container_of(info, struct fib_nh_notifier_info,
5863 info);
5864 fib_work->fnh_info = *fnh_info;
5865 fib_info_hold(fib_work->fnh_info.fib_nh->nh_parent);
5866 break;
5867 }
5868 }
5869
mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work * fib_work,struct fib_notifier_info * info)5870 static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
5871 struct fib_notifier_info *info)
5872 {
5873 struct fib6_entry_notifier_info *fen6_info;
5874
5875 switch (fib_work->event) {
5876 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
5877 case FIB_EVENT_ENTRY_APPEND: /* fall through */
5878 case FIB_EVENT_ENTRY_ADD: /* fall through */
5879 case FIB_EVENT_ENTRY_DEL:
5880 fen6_info = container_of(info, struct fib6_entry_notifier_info,
5881 info);
5882 fib_work->fen6_info = *fen6_info;
5883 fib6_info_hold(fib_work->fen6_info.rt);
5884 break;
5885 }
5886 }
5887
5888 static void
mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work * fib_work,struct fib_notifier_info * info)5889 mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work *fib_work,
5890 struct fib_notifier_info *info)
5891 {
5892 switch (fib_work->event) {
5893 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
5894 case FIB_EVENT_ENTRY_ADD: /* fall through */
5895 case FIB_EVENT_ENTRY_DEL:
5896 memcpy(&fib_work->men_info, info, sizeof(fib_work->men_info));
5897 mr_cache_hold(fib_work->men_info.mfc);
5898 break;
5899 case FIB_EVENT_VIF_ADD: /* fall through */
5900 case FIB_EVENT_VIF_DEL:
5901 memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info));
5902 dev_hold(fib_work->ven_info.dev);
5903 break;
5904 }
5905 }
5906
mlxsw_sp_router_fib_rule_event(unsigned long event,struct fib_notifier_info * info,struct mlxsw_sp * mlxsw_sp)5907 static int mlxsw_sp_router_fib_rule_event(unsigned long event,
5908 struct fib_notifier_info *info,
5909 struct mlxsw_sp *mlxsw_sp)
5910 {
5911 struct netlink_ext_ack *extack = info->extack;
5912 struct fib_rule_notifier_info *fr_info;
5913 struct fib_rule *rule;
5914 int err = 0;
5915
5916 /* nothing to do at the moment */
5917 if (event == FIB_EVENT_RULE_DEL)
5918 return 0;
5919
5920 if (mlxsw_sp->router->aborted)
5921 return 0;
5922
5923 fr_info = container_of(info, struct fib_rule_notifier_info, info);
5924 rule = fr_info->rule;
5925
5926 switch (info->family) {
5927 case AF_INET:
5928 if (!fib4_rule_default(rule) && !rule->l3mdev)
5929 err = -EOPNOTSUPP;
5930 break;
5931 case AF_INET6:
5932 if (!fib6_rule_default(rule) && !rule->l3mdev)
5933 err = -EOPNOTSUPP;
5934 break;
5935 case RTNL_FAMILY_IPMR:
5936 if (!ipmr_rule_default(rule) && !rule->l3mdev)
5937 err = -EOPNOTSUPP;
5938 break;
5939 case RTNL_FAMILY_IP6MR:
5940 if (!ip6mr_rule_default(rule) && !rule->l3mdev)
5941 err = -EOPNOTSUPP;
5942 break;
5943 }
5944
5945 if (err < 0)
5946 NL_SET_ERR_MSG_MOD(extack, "FIB rules not supported");
5947
5948 return err;
5949 }
5950
5951 /* Called with rcu_read_lock() */
mlxsw_sp_router_fib_event(struct notifier_block * nb,unsigned long event,void * ptr)5952 static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
5953 unsigned long event, void *ptr)
5954 {
5955 struct mlxsw_sp_fib_event_work *fib_work;
5956 struct fib_notifier_info *info = ptr;
5957 struct mlxsw_sp_router *router;
5958 int err;
5959
5960 if (!net_eq(info->net, &init_net) ||
5961 (info->family != AF_INET && info->family != AF_INET6 &&
5962 info->family != RTNL_FAMILY_IPMR &&
5963 info->family != RTNL_FAMILY_IP6MR))
5964 return NOTIFY_DONE;
5965
5966 router = container_of(nb, struct mlxsw_sp_router, fib_nb);
5967
5968 switch (event) {
5969 case FIB_EVENT_RULE_ADD: /* fall through */
5970 case FIB_EVENT_RULE_DEL:
5971 err = mlxsw_sp_router_fib_rule_event(event, info,
5972 router->mlxsw_sp);
5973 if (!err || info->extack)
5974 return notifier_from_errno(err);
5975 break;
5976 case FIB_EVENT_ENTRY_ADD:
5977 if (router->aborted) {
5978 NL_SET_ERR_MSG_MOD(info->extack, "FIB offload was aborted. Not configuring route");
5979 return notifier_from_errno(-EINVAL);
5980 }
5981 break;
5982 }
5983
5984 fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC);
5985 if (!fib_work)
5986 return NOTIFY_BAD;
5987
5988 fib_work->mlxsw_sp = router->mlxsw_sp;
5989 fib_work->event = event;
5990
5991 switch (info->family) {
5992 case AF_INET:
5993 INIT_WORK(&fib_work->work, mlxsw_sp_router_fib4_event_work);
5994 mlxsw_sp_router_fib4_event(fib_work, info);
5995 break;
5996 case AF_INET6:
5997 INIT_WORK(&fib_work->work, mlxsw_sp_router_fib6_event_work);
5998 mlxsw_sp_router_fib6_event(fib_work, info);
5999 break;
6000 case RTNL_FAMILY_IP6MR:
6001 case RTNL_FAMILY_IPMR:
6002 INIT_WORK(&fib_work->work, mlxsw_sp_router_fibmr_event_work);
6003 mlxsw_sp_router_fibmr_event(fib_work, info);
6004 break;
6005 }
6006
6007 mlxsw_core_schedule_work(&fib_work->work);
6008
6009 return NOTIFY_DONE;
6010 }
6011
6012 struct mlxsw_sp_rif *
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev)6013 mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
6014 const struct net_device *dev)
6015 {
6016 int i;
6017
6018 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
6019 if (mlxsw_sp->router->rifs[i] &&
6020 mlxsw_sp->router->rifs[i]->dev == dev)
6021 return mlxsw_sp->router->rifs[i];
6022
6023 return NULL;
6024 }
6025
mlxsw_sp_router_rif_disable(struct mlxsw_sp * mlxsw_sp,u16 rif)6026 static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif)
6027 {
6028 char ritr_pl[MLXSW_REG_RITR_LEN];
6029 int err;
6030
6031 mlxsw_reg_ritr_rif_pack(ritr_pl, rif);
6032 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6033 if (WARN_ON_ONCE(err))
6034 return err;
6035
6036 mlxsw_reg_ritr_enable_set(ritr_pl, false);
6037 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6038 }
6039
mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)6040 static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
6041 struct mlxsw_sp_rif *rif)
6042 {
6043 mlxsw_sp_router_rif_disable(mlxsw_sp, rif->rif_index);
6044 mlxsw_sp_nexthop_rif_gone_sync(mlxsw_sp, rif);
6045 mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
6046 }
6047
6048 static bool
mlxsw_sp_rif_should_config(struct mlxsw_sp_rif * rif,struct net_device * dev,unsigned long event)6049 mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, struct net_device *dev,
6050 unsigned long event)
6051 {
6052 struct inet6_dev *inet6_dev;
6053 bool addr_list_empty = true;
6054 struct in_device *idev;
6055
6056 switch (event) {
6057 case NETDEV_UP:
6058 return rif == NULL;
6059 case NETDEV_DOWN:
6060 idev = __in_dev_get_rtnl(dev);
6061 if (idev && idev->ifa_list)
6062 addr_list_empty = false;
6063
6064 inet6_dev = __in6_dev_get(dev);
6065 if (addr_list_empty && inet6_dev &&
6066 !list_empty(&inet6_dev->addr_list))
6067 addr_list_empty = false;
6068
6069 /* macvlans do not have a RIF, but rather piggy back on the
6070 * RIF of their lower device.
6071 */
6072 if (netif_is_macvlan(dev) && addr_list_empty)
6073 return true;
6074
6075 if (rif && addr_list_empty &&
6076 !netif_is_l3_slave(rif->dev))
6077 return true;
6078 /* It is possible we already removed the RIF ourselves
6079 * if it was assigned to a netdev that is now a bridge
6080 * or LAG slave.
6081 */
6082 return false;
6083 }
6084
6085 return false;
6086 }
6087
6088 static enum mlxsw_sp_rif_type
mlxsw_sp_dev_rif_type(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev)6089 mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp,
6090 const struct net_device *dev)
6091 {
6092 enum mlxsw_sp_fid_type type;
6093
6094 if (mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL))
6095 return MLXSW_SP_RIF_TYPE_IPIP_LB;
6096
6097 /* Otherwise RIF type is derived from the type of the underlying FID. */
6098 if (is_vlan_dev(dev) && netif_is_bridge_master(vlan_dev_real_dev(dev)))
6099 type = MLXSW_SP_FID_TYPE_8021Q;
6100 else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev))
6101 type = MLXSW_SP_FID_TYPE_8021Q;
6102 else if (netif_is_bridge_master(dev))
6103 type = MLXSW_SP_FID_TYPE_8021D;
6104 else
6105 type = MLXSW_SP_FID_TYPE_RFID;
6106
6107 return mlxsw_sp_fid_type_rif_type(mlxsw_sp, type);
6108 }
6109
mlxsw_sp_rif_index_alloc(struct mlxsw_sp * mlxsw_sp,u16 * p_rif_index)6110 static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_rif_index)
6111 {
6112 int i;
6113
6114 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
6115 if (!mlxsw_sp->router->rifs[i]) {
6116 *p_rif_index = i;
6117 return 0;
6118 }
6119 }
6120
6121 return -ENOBUFS;
6122 }
6123
mlxsw_sp_rif_alloc(size_t rif_size,u16 rif_index,u16 vr_id,struct net_device * l3_dev)6124 static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index,
6125 u16 vr_id,
6126 struct net_device *l3_dev)
6127 {
6128 struct mlxsw_sp_rif *rif;
6129
6130 rif = kzalloc(rif_size, GFP_KERNEL);
6131 if (!rif)
6132 return NULL;
6133
6134 INIT_LIST_HEAD(&rif->nexthop_list);
6135 INIT_LIST_HEAD(&rif->neigh_list);
6136 ether_addr_copy(rif->addr, l3_dev->dev_addr);
6137 rif->mtu = l3_dev->mtu;
6138 rif->vr_id = vr_id;
6139 rif->dev = l3_dev;
6140 rif->rif_index = rif_index;
6141
6142 return rif;
6143 }
6144
mlxsw_sp_rif_by_index(const struct mlxsw_sp * mlxsw_sp,u16 rif_index)6145 struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
6146 u16 rif_index)
6147 {
6148 return mlxsw_sp->router->rifs[rif_index];
6149 }
6150
mlxsw_sp_rif_index(const struct mlxsw_sp_rif * rif)6151 u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif)
6152 {
6153 return rif->rif_index;
6154 }
6155
mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb * lb_rif)6156 u16 mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb *lb_rif)
6157 {
6158 return lb_rif->common.rif_index;
6159 }
6160
mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb * lb_rif)6161 u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif)
6162 {
6163 return lb_rif->ul_vr_id;
6164 }
6165
mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif * rif)6166 int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif)
6167 {
6168 return rif->dev->ifindex;
6169 }
6170
mlxsw_sp_rif_dev(const struct mlxsw_sp_rif * rif)6171 const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif)
6172 {
6173 return rif->dev;
6174 }
6175
mlxsw_sp_rif_fid(const struct mlxsw_sp_rif * rif)6176 struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif)
6177 {
6178 return rif->fid;
6179 }
6180
6181 static struct mlxsw_sp_rif *
mlxsw_sp_rif_create(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_rif_params * params,struct netlink_ext_ack * extack)6182 mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
6183 const struct mlxsw_sp_rif_params *params,
6184 struct netlink_ext_ack *extack)
6185 {
6186 u32 tb_id = l3mdev_fib_table(params->dev);
6187 const struct mlxsw_sp_rif_ops *ops;
6188 struct mlxsw_sp_fid *fid = NULL;
6189 enum mlxsw_sp_rif_type type;
6190 struct mlxsw_sp_rif *rif;
6191 struct mlxsw_sp_vr *vr;
6192 u16 rif_index;
6193 int i, err;
6194
6195 type = mlxsw_sp_dev_rif_type(mlxsw_sp, params->dev);
6196 ops = mlxsw_sp->router->rif_ops_arr[type];
6197
6198 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN, extack);
6199 if (IS_ERR(vr))
6200 return ERR_CAST(vr);
6201 vr->rif_count++;
6202
6203 err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index);
6204 if (err) {
6205 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interfaces");
6206 goto err_rif_index_alloc;
6207 }
6208
6209 rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, params->dev);
6210 if (!rif) {
6211 err = -ENOMEM;
6212 goto err_rif_alloc;
6213 }
6214 rif->mlxsw_sp = mlxsw_sp;
6215 rif->ops = ops;
6216
6217 if (ops->fid_get) {
6218 fid = ops->fid_get(rif, extack);
6219 if (IS_ERR(fid)) {
6220 err = PTR_ERR(fid);
6221 goto err_fid_get;
6222 }
6223 rif->fid = fid;
6224 }
6225
6226 if (ops->setup)
6227 ops->setup(rif, params);
6228
6229 err = ops->configure(rif);
6230 if (err)
6231 goto err_configure;
6232
6233 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++) {
6234 err = mlxsw_sp_mr_rif_add(vr->mr_table[i], rif);
6235 if (err)
6236 goto err_mr_rif_add;
6237 }
6238
6239 mlxsw_sp_rif_counters_alloc(rif);
6240 mlxsw_sp->router->rifs[rif_index] = rif;
6241
6242 return rif;
6243
6244 err_mr_rif_add:
6245 for (i--; i >= 0; i--)
6246 mlxsw_sp_mr_rif_del(vr->mr_table[i], rif);
6247 ops->deconfigure(rif);
6248 err_configure:
6249 if (fid)
6250 mlxsw_sp_fid_put(fid);
6251 err_fid_get:
6252 kfree(rif);
6253 err_rif_alloc:
6254 err_rif_index_alloc:
6255 vr->rif_count--;
6256 mlxsw_sp_vr_put(mlxsw_sp, vr);
6257 return ERR_PTR(err);
6258 }
6259
mlxsw_sp_rif_destroy(struct mlxsw_sp_rif * rif)6260 void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
6261 {
6262 const struct mlxsw_sp_rif_ops *ops = rif->ops;
6263 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
6264 struct mlxsw_sp_fid *fid = rif->fid;
6265 struct mlxsw_sp_vr *vr;
6266 int i;
6267
6268 mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
6269 vr = &mlxsw_sp->router->vrs[rif->vr_id];
6270
6271 mlxsw_sp->router->rifs[rif->rif_index] = NULL;
6272 mlxsw_sp_rif_counters_free(rif);
6273 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++)
6274 mlxsw_sp_mr_rif_del(vr->mr_table[i], rif);
6275 ops->deconfigure(rif);
6276 if (fid)
6277 /* Loopback RIFs are not associated with a FID. */
6278 mlxsw_sp_fid_put(fid);
6279 kfree(rif);
6280 vr->rif_count--;
6281 mlxsw_sp_vr_put(mlxsw_sp, vr);
6282 }
6283
mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp * mlxsw_sp,struct net_device * dev)6284 void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
6285 struct net_device *dev)
6286 {
6287 struct mlxsw_sp_rif *rif;
6288
6289 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6290 if (!rif)
6291 return;
6292 mlxsw_sp_rif_destroy(rif);
6293 }
6294
6295 static void
mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params * params,struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)6296 mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
6297 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
6298 {
6299 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
6300
6301 params->vid = mlxsw_sp_port_vlan->vid;
6302 params->lag = mlxsw_sp_port->lagged;
6303 if (params->lag)
6304 params->lag_id = mlxsw_sp_port->lag_id;
6305 else
6306 params->system_port = mlxsw_sp_port->local_port;
6307 }
6308
6309 static int
mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan,struct net_device * l3_dev,struct netlink_ext_ack * extack)6310 mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
6311 struct net_device *l3_dev,
6312 struct netlink_ext_ack *extack)
6313 {
6314 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
6315 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
6316 u16 vid = mlxsw_sp_port_vlan->vid;
6317 struct mlxsw_sp_rif *rif;
6318 struct mlxsw_sp_fid *fid;
6319 int err;
6320
6321 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
6322 if (!rif) {
6323 struct mlxsw_sp_rif_params params = {
6324 .dev = l3_dev,
6325 };
6326
6327 mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan);
6328 rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms, extack);
6329 if (IS_ERR(rif))
6330 return PTR_ERR(rif);
6331 }
6332
6333 /* FID was already created, just take a reference */
6334 fid = rif->ops->fid_get(rif, extack);
6335 err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
6336 if (err)
6337 goto err_fid_port_vid_map;
6338
6339 err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
6340 if (err)
6341 goto err_port_vid_learning_set;
6342
6343 err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid,
6344 BR_STATE_FORWARDING);
6345 if (err)
6346 goto err_port_vid_stp_set;
6347
6348 mlxsw_sp_port_vlan->fid = fid;
6349
6350 return 0;
6351
6352 err_port_vid_stp_set:
6353 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
6354 err_port_vid_learning_set:
6355 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
6356 err_fid_port_vid_map:
6357 mlxsw_sp_fid_put(fid);
6358 return err;
6359 }
6360
6361 void
mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)6362 mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
6363 {
6364 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
6365 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
6366 u16 vid = mlxsw_sp_port_vlan->vid;
6367
6368 if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID))
6369 return;
6370
6371 mlxsw_sp_port_vlan->fid = NULL;
6372 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING);
6373 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
6374 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
6375 /* If router port holds the last reference on the rFID, then the
6376 * associated Sub-port RIF will be destroyed.
6377 */
6378 mlxsw_sp_fid_put(fid);
6379 }
6380
mlxsw_sp_inetaddr_port_vlan_event(struct net_device * l3_dev,struct net_device * port_dev,unsigned long event,u16 vid,struct netlink_ext_ack * extack)6381 static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
6382 struct net_device *port_dev,
6383 unsigned long event, u16 vid,
6384 struct netlink_ext_ack *extack)
6385 {
6386 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(port_dev);
6387 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
6388
6389 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
6390 if (WARN_ON(!mlxsw_sp_port_vlan))
6391 return -EINVAL;
6392
6393 switch (event) {
6394 case NETDEV_UP:
6395 return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan,
6396 l3_dev, extack);
6397 case NETDEV_DOWN:
6398 mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
6399 break;
6400 }
6401
6402 return 0;
6403 }
6404
mlxsw_sp_inetaddr_port_event(struct net_device * port_dev,unsigned long event,struct netlink_ext_ack * extack)6405 static int mlxsw_sp_inetaddr_port_event(struct net_device *port_dev,
6406 unsigned long event,
6407 struct netlink_ext_ack *extack)
6408 {
6409 if (netif_is_bridge_port(port_dev) ||
6410 netif_is_lag_port(port_dev) ||
6411 netif_is_ovs_port(port_dev))
6412 return 0;
6413
6414 return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event, 1,
6415 extack);
6416 }
6417
__mlxsw_sp_inetaddr_lag_event(struct net_device * l3_dev,struct net_device * lag_dev,unsigned long event,u16 vid,struct netlink_ext_ack * extack)6418 static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev,
6419 struct net_device *lag_dev,
6420 unsigned long event, u16 vid,
6421 struct netlink_ext_ack *extack)
6422 {
6423 struct net_device *port_dev;
6424 struct list_head *iter;
6425 int err;
6426
6427 netdev_for_each_lower_dev(lag_dev, port_dev, iter) {
6428 if (mlxsw_sp_port_dev_check(port_dev)) {
6429 err = mlxsw_sp_inetaddr_port_vlan_event(l3_dev,
6430 port_dev,
6431 event, vid,
6432 extack);
6433 if (err)
6434 return err;
6435 }
6436 }
6437
6438 return 0;
6439 }
6440
mlxsw_sp_inetaddr_lag_event(struct net_device * lag_dev,unsigned long event,struct netlink_ext_ack * extack)6441 static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
6442 unsigned long event,
6443 struct netlink_ext_ack *extack)
6444 {
6445 if (netif_is_bridge_port(lag_dev))
6446 return 0;
6447
6448 return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1,
6449 extack);
6450 }
6451
mlxsw_sp_inetaddr_bridge_event(struct net_device * l3_dev,unsigned long event,struct netlink_ext_ack * extack)6452 static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev,
6453 unsigned long event,
6454 struct netlink_ext_ack *extack)
6455 {
6456 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
6457 struct mlxsw_sp_rif_params params = {
6458 .dev = l3_dev,
6459 };
6460 struct mlxsw_sp_rif *rif;
6461
6462 switch (event) {
6463 case NETDEV_UP:
6464 rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms, extack);
6465 if (IS_ERR(rif))
6466 return PTR_ERR(rif);
6467 break;
6468 case NETDEV_DOWN:
6469 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
6470 mlxsw_sp_rif_destroy(rif);
6471 break;
6472 }
6473
6474 return 0;
6475 }
6476
mlxsw_sp_inetaddr_vlan_event(struct net_device * vlan_dev,unsigned long event,struct netlink_ext_ack * extack)6477 static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
6478 unsigned long event,
6479 struct netlink_ext_ack *extack)
6480 {
6481 struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
6482 u16 vid = vlan_dev_vlan_id(vlan_dev);
6483
6484 if (netif_is_bridge_port(vlan_dev))
6485 return 0;
6486
6487 if (mlxsw_sp_port_dev_check(real_dev))
6488 return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev, real_dev,
6489 event, vid, extack);
6490 else if (netif_is_lag_master(real_dev))
6491 return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
6492 vid, extack);
6493 else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev))
6494 return mlxsw_sp_inetaddr_bridge_event(vlan_dev, event, extack);
6495
6496 return 0;
6497 }
6498
mlxsw_sp_rif_macvlan_is_vrrp4(const u8 * mac)6499 static bool mlxsw_sp_rif_macvlan_is_vrrp4(const u8 *mac)
6500 {
6501 u8 vrrp4[ETH_ALEN] = { 0x00, 0x00, 0x5e, 0x00, 0x01, 0x00 };
6502 u8 mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
6503
6504 return ether_addr_equal_masked(mac, vrrp4, mask);
6505 }
6506
mlxsw_sp_rif_macvlan_is_vrrp6(const u8 * mac)6507 static bool mlxsw_sp_rif_macvlan_is_vrrp6(const u8 *mac)
6508 {
6509 u8 vrrp6[ETH_ALEN] = { 0x00, 0x00, 0x5e, 0x00, 0x02, 0x00 };
6510 u8 mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
6511
6512 return ether_addr_equal_masked(mac, vrrp6, mask);
6513 }
6514
mlxsw_sp_rif_vrrp_op(struct mlxsw_sp * mlxsw_sp,u16 rif_index,const u8 * mac,bool adding)6515 static int mlxsw_sp_rif_vrrp_op(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
6516 const u8 *mac, bool adding)
6517 {
6518 char ritr_pl[MLXSW_REG_RITR_LEN];
6519 u8 vrrp_id = adding ? mac[5] : 0;
6520 int err;
6521
6522 if (!mlxsw_sp_rif_macvlan_is_vrrp4(mac) &&
6523 !mlxsw_sp_rif_macvlan_is_vrrp6(mac))
6524 return 0;
6525
6526 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
6527 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6528 if (err)
6529 return err;
6530
6531 if (mlxsw_sp_rif_macvlan_is_vrrp4(mac))
6532 mlxsw_reg_ritr_if_vrrp_id_ipv4_set(ritr_pl, vrrp_id);
6533 else
6534 mlxsw_reg_ritr_if_vrrp_id_ipv6_set(ritr_pl, vrrp_id);
6535
6536 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6537 }
6538
mlxsw_sp_rif_macvlan_add(struct mlxsw_sp * mlxsw_sp,const struct net_device * macvlan_dev,struct netlink_ext_ack * extack)6539 static int mlxsw_sp_rif_macvlan_add(struct mlxsw_sp *mlxsw_sp,
6540 const struct net_device *macvlan_dev,
6541 struct netlink_ext_ack *extack)
6542 {
6543 struct macvlan_dev *vlan = netdev_priv(macvlan_dev);
6544 struct mlxsw_sp_rif *rif;
6545 int err;
6546
6547 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan->lowerdev);
6548 if (!rif) {
6549 NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
6550 return -EOPNOTSUPP;
6551 }
6552
6553 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
6554 mlxsw_sp_fid_index(rif->fid), true);
6555 if (err)
6556 return err;
6557
6558 err = mlxsw_sp_rif_vrrp_op(mlxsw_sp, rif->rif_index,
6559 macvlan_dev->dev_addr, true);
6560 if (err)
6561 goto err_rif_vrrp_add;
6562
6563 /* Make sure the bridge driver does not have this MAC pointing at
6564 * some other port.
6565 */
6566 if (rif->ops->fdb_del)
6567 rif->ops->fdb_del(rif, macvlan_dev->dev_addr);
6568
6569 return 0;
6570
6571 err_rif_vrrp_add:
6572 mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
6573 mlxsw_sp_fid_index(rif->fid), false);
6574 return err;
6575 }
6576
mlxsw_sp_rif_macvlan_del(struct mlxsw_sp * mlxsw_sp,const struct net_device * macvlan_dev)6577 void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
6578 const struct net_device *macvlan_dev)
6579 {
6580 struct macvlan_dev *vlan = netdev_priv(macvlan_dev);
6581 struct mlxsw_sp_rif *rif;
6582
6583 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan->lowerdev);
6584 /* If we do not have a RIF, then we already took care of
6585 * removing the macvlan's MAC during RIF deletion.
6586 */
6587 if (!rif)
6588 return;
6589 mlxsw_sp_rif_vrrp_op(mlxsw_sp, rif->rif_index, macvlan_dev->dev_addr,
6590 false);
6591 mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
6592 mlxsw_sp_fid_index(rif->fid), false);
6593 }
6594
mlxsw_sp_inetaddr_macvlan_event(struct net_device * macvlan_dev,unsigned long event,struct netlink_ext_ack * extack)6595 static int mlxsw_sp_inetaddr_macvlan_event(struct net_device *macvlan_dev,
6596 unsigned long event,
6597 struct netlink_ext_ack *extack)
6598 {
6599 struct mlxsw_sp *mlxsw_sp;
6600
6601 mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev);
6602 if (!mlxsw_sp)
6603 return 0;
6604
6605 switch (event) {
6606 case NETDEV_UP:
6607 return mlxsw_sp_rif_macvlan_add(mlxsw_sp, macvlan_dev, extack);
6608 case NETDEV_DOWN:
6609 mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev);
6610 break;
6611 }
6612
6613 return 0;
6614 }
6615
__mlxsw_sp_inetaddr_event(struct net_device * dev,unsigned long event,struct netlink_ext_ack * extack)6616 static int __mlxsw_sp_inetaddr_event(struct net_device *dev,
6617 unsigned long event,
6618 struct netlink_ext_ack *extack)
6619 {
6620 if (mlxsw_sp_port_dev_check(dev))
6621 return mlxsw_sp_inetaddr_port_event(dev, event, extack);
6622 else if (netif_is_lag_master(dev))
6623 return mlxsw_sp_inetaddr_lag_event(dev, event, extack);
6624 else if (netif_is_bridge_master(dev))
6625 return mlxsw_sp_inetaddr_bridge_event(dev, event, extack);
6626 else if (is_vlan_dev(dev))
6627 return mlxsw_sp_inetaddr_vlan_event(dev, event, extack);
6628 else if (netif_is_macvlan(dev))
6629 return mlxsw_sp_inetaddr_macvlan_event(dev, event, extack);
6630 else
6631 return 0;
6632 }
6633
mlxsw_sp_inetaddr_event(struct notifier_block * unused,unsigned long event,void * ptr)6634 int mlxsw_sp_inetaddr_event(struct notifier_block *unused,
6635 unsigned long event, void *ptr)
6636 {
6637 struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
6638 struct net_device *dev = ifa->ifa_dev->dev;
6639 struct mlxsw_sp *mlxsw_sp;
6640 struct mlxsw_sp_rif *rif;
6641 int err = 0;
6642
6643 /* NETDEV_UP event is handled by mlxsw_sp_inetaddr_valid_event */
6644 if (event == NETDEV_UP)
6645 goto out;
6646
6647 mlxsw_sp = mlxsw_sp_lower_get(dev);
6648 if (!mlxsw_sp)
6649 goto out;
6650
6651 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6652 if (!mlxsw_sp_rif_should_config(rif, dev, event))
6653 goto out;
6654
6655 err = __mlxsw_sp_inetaddr_event(dev, event, NULL);
6656 out:
6657 return notifier_from_errno(err);
6658 }
6659
mlxsw_sp_inetaddr_valid_event(struct notifier_block * unused,unsigned long event,void * ptr)6660 int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
6661 unsigned long event, void *ptr)
6662 {
6663 struct in_validator_info *ivi = (struct in_validator_info *) ptr;
6664 struct net_device *dev = ivi->ivi_dev->dev;
6665 struct mlxsw_sp *mlxsw_sp;
6666 struct mlxsw_sp_rif *rif;
6667 int err = 0;
6668
6669 mlxsw_sp = mlxsw_sp_lower_get(dev);
6670 if (!mlxsw_sp)
6671 goto out;
6672
6673 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6674 if (!mlxsw_sp_rif_should_config(rif, dev, event))
6675 goto out;
6676
6677 err = __mlxsw_sp_inetaddr_event(dev, event, ivi->extack);
6678 out:
6679 return notifier_from_errno(err);
6680 }
6681
6682 struct mlxsw_sp_inet6addr_event_work {
6683 struct work_struct work;
6684 struct net_device *dev;
6685 unsigned long event;
6686 };
6687
mlxsw_sp_inet6addr_event_work(struct work_struct * work)6688 static void mlxsw_sp_inet6addr_event_work(struct work_struct *work)
6689 {
6690 struct mlxsw_sp_inet6addr_event_work *inet6addr_work =
6691 container_of(work, struct mlxsw_sp_inet6addr_event_work, work);
6692 struct net_device *dev = inet6addr_work->dev;
6693 unsigned long event = inet6addr_work->event;
6694 struct mlxsw_sp *mlxsw_sp;
6695 struct mlxsw_sp_rif *rif;
6696
6697 rtnl_lock();
6698 mlxsw_sp = mlxsw_sp_lower_get(dev);
6699 if (!mlxsw_sp)
6700 goto out;
6701
6702 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6703 if (!mlxsw_sp_rif_should_config(rif, dev, event))
6704 goto out;
6705
6706 __mlxsw_sp_inetaddr_event(dev, event, NULL);
6707 out:
6708 rtnl_unlock();
6709 dev_put(dev);
6710 kfree(inet6addr_work);
6711 }
6712
6713 /* Called with rcu_read_lock() */
mlxsw_sp_inet6addr_event(struct notifier_block * unused,unsigned long event,void * ptr)6714 int mlxsw_sp_inet6addr_event(struct notifier_block *unused,
6715 unsigned long event, void *ptr)
6716 {
6717 struct inet6_ifaddr *if6 = (struct inet6_ifaddr *) ptr;
6718 struct mlxsw_sp_inet6addr_event_work *inet6addr_work;
6719 struct net_device *dev = if6->idev->dev;
6720
6721 /* NETDEV_UP event is handled by mlxsw_sp_inet6addr_valid_event */
6722 if (event == NETDEV_UP)
6723 return NOTIFY_DONE;
6724
6725 if (!mlxsw_sp_port_dev_lower_find_rcu(dev))
6726 return NOTIFY_DONE;
6727
6728 inet6addr_work = kzalloc(sizeof(*inet6addr_work), GFP_ATOMIC);
6729 if (!inet6addr_work)
6730 return NOTIFY_BAD;
6731
6732 INIT_WORK(&inet6addr_work->work, mlxsw_sp_inet6addr_event_work);
6733 inet6addr_work->dev = dev;
6734 inet6addr_work->event = event;
6735 dev_hold(dev);
6736 mlxsw_core_schedule_work(&inet6addr_work->work);
6737
6738 return NOTIFY_DONE;
6739 }
6740
mlxsw_sp_inet6addr_valid_event(struct notifier_block * unused,unsigned long event,void * ptr)6741 int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
6742 unsigned long event, void *ptr)
6743 {
6744 struct in6_validator_info *i6vi = (struct in6_validator_info *) ptr;
6745 struct net_device *dev = i6vi->i6vi_dev->dev;
6746 struct mlxsw_sp *mlxsw_sp;
6747 struct mlxsw_sp_rif *rif;
6748 int err = 0;
6749
6750 mlxsw_sp = mlxsw_sp_lower_get(dev);
6751 if (!mlxsw_sp)
6752 goto out;
6753
6754 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6755 if (!mlxsw_sp_rif_should_config(rif, dev, event))
6756 goto out;
6757
6758 err = __mlxsw_sp_inetaddr_event(dev, event, i6vi->extack);
6759 out:
6760 return notifier_from_errno(err);
6761 }
6762
mlxsw_sp_rif_edit(struct mlxsw_sp * mlxsw_sp,u16 rif_index,const char * mac,int mtu)6763 static int mlxsw_sp_rif_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
6764 const char *mac, int mtu)
6765 {
6766 char ritr_pl[MLXSW_REG_RITR_LEN];
6767 int err;
6768
6769 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
6770 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6771 if (err)
6772 return err;
6773
6774 mlxsw_reg_ritr_mtu_set(ritr_pl, mtu);
6775 mlxsw_reg_ritr_if_mac_memcpy_to(ritr_pl, mac);
6776 mlxsw_reg_ritr_op_set(ritr_pl, MLXSW_REG_RITR_RIF_CREATE);
6777 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6778 }
6779
mlxsw_sp_netdevice_router_port_event(struct net_device * dev)6780 int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
6781 {
6782 struct mlxsw_sp *mlxsw_sp;
6783 struct mlxsw_sp_rif *rif;
6784 u16 fid_index;
6785 int err;
6786
6787 mlxsw_sp = mlxsw_sp_lower_get(dev);
6788 if (!mlxsw_sp)
6789 return 0;
6790
6791 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6792 if (!rif)
6793 return 0;
6794 fid_index = mlxsw_sp_fid_index(rif->fid);
6795
6796 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false);
6797 if (err)
6798 return err;
6799
6800 err = mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, dev->dev_addr,
6801 dev->mtu);
6802 if (err)
6803 goto err_rif_edit;
6804
6805 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, fid_index, true);
6806 if (err)
6807 goto err_rif_fdb_op;
6808
6809 if (rif->mtu != dev->mtu) {
6810 struct mlxsw_sp_vr *vr;
6811 int i;
6812
6813 /* The RIF is relevant only to its mr_table instance, as unlike
6814 * unicast routing, in multicast routing a RIF cannot be shared
6815 * between several multicast routing tables.
6816 */
6817 vr = &mlxsw_sp->router->vrs[rif->vr_id];
6818 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++)
6819 mlxsw_sp_mr_rif_mtu_update(vr->mr_table[i],
6820 rif, dev->mtu);
6821 }
6822
6823 ether_addr_copy(rif->addr, dev->dev_addr);
6824 rif->mtu = dev->mtu;
6825
6826 netdev_dbg(dev, "Updated RIF=%d\n", rif->rif_index);
6827
6828 return 0;
6829
6830 err_rif_fdb_op:
6831 mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu);
6832 err_rif_edit:
6833 mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true);
6834 return err;
6835 }
6836
mlxsw_sp_port_vrf_join(struct mlxsw_sp * mlxsw_sp,struct net_device * l3_dev,struct netlink_ext_ack * extack)6837 static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
6838 struct net_device *l3_dev,
6839 struct netlink_ext_ack *extack)
6840 {
6841 struct mlxsw_sp_rif *rif;
6842
6843 /* If netdev is already associated with a RIF, then we need to
6844 * destroy it and create a new one with the new virtual router ID.
6845 */
6846 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
6847 if (rif)
6848 __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN, extack);
6849
6850 return __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_UP, extack);
6851 }
6852
mlxsw_sp_port_vrf_leave(struct mlxsw_sp * mlxsw_sp,struct net_device * l3_dev)6853 static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
6854 struct net_device *l3_dev)
6855 {
6856 struct mlxsw_sp_rif *rif;
6857
6858 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
6859 if (!rif)
6860 return;
6861 __mlxsw_sp_inetaddr_event(l3_dev, NETDEV_DOWN, NULL);
6862 }
6863
mlxsw_sp_netdevice_vrf_event(struct net_device * l3_dev,unsigned long event,struct netdev_notifier_changeupper_info * info)6864 int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
6865 struct netdev_notifier_changeupper_info *info)
6866 {
6867 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
6868 int err = 0;
6869
6870 /* We do not create a RIF for a macvlan, but only use it to
6871 * direct more MAC addresses to the router.
6872 */
6873 if (!mlxsw_sp || netif_is_macvlan(l3_dev))
6874 return 0;
6875
6876 switch (event) {
6877 case NETDEV_PRECHANGEUPPER:
6878 return 0;
6879 case NETDEV_CHANGEUPPER:
6880 if (info->linking) {
6881 struct netlink_ext_ack *extack;
6882
6883 extack = netdev_notifier_info_to_extack(&info->info);
6884 err = mlxsw_sp_port_vrf_join(mlxsw_sp, l3_dev, extack);
6885 } else {
6886 mlxsw_sp_port_vrf_leave(mlxsw_sp, l3_dev);
6887 }
6888 break;
6889 }
6890
6891 return err;
6892 }
6893
__mlxsw_sp_rif_macvlan_flush(struct net_device * dev,void * data)6894 static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, void *data)
6895 {
6896 struct mlxsw_sp_rif *rif = data;
6897
6898 if (!netif_is_macvlan(dev))
6899 return 0;
6900
6901 return mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
6902 mlxsw_sp_fid_index(rif->fid), false);
6903 }
6904
mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif * rif)6905 static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif)
6906 {
6907 if (!netif_is_macvlan_port(rif->dev))
6908 return 0;
6909
6910 netdev_warn(rif->dev, "Router interface is deleted. Upper macvlans will not work\n");
6911 return netdev_walk_all_upper_dev_rcu(rif->dev,
6912 __mlxsw_sp_rif_macvlan_flush, rif);
6913 }
6914
6915 static struct mlxsw_sp_rif_subport *
mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif * rif)6916 mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif)
6917 {
6918 return container_of(rif, struct mlxsw_sp_rif_subport, common);
6919 }
6920
mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif * rif,const struct mlxsw_sp_rif_params * params)6921 static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
6922 const struct mlxsw_sp_rif_params *params)
6923 {
6924 struct mlxsw_sp_rif_subport *rif_subport;
6925
6926 rif_subport = mlxsw_sp_rif_subport_rif(rif);
6927 rif_subport->vid = params->vid;
6928 rif_subport->lag = params->lag;
6929 if (params->lag)
6930 rif_subport->lag_id = params->lag_id;
6931 else
6932 rif_subport->system_port = params->system_port;
6933 }
6934
mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif * rif,bool enable)6935 static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable)
6936 {
6937 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
6938 struct mlxsw_sp_rif_subport *rif_subport;
6939 char ritr_pl[MLXSW_REG_RITR_LEN];
6940
6941 rif_subport = mlxsw_sp_rif_subport_rif(rif);
6942 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF,
6943 rif->rif_index, rif->vr_id, rif->dev->mtu);
6944 mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
6945 mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
6946 rif_subport->lag ? rif_subport->lag_id :
6947 rif_subport->system_port,
6948 rif_subport->vid);
6949
6950 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6951 }
6952
mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif * rif)6953 static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif)
6954 {
6955 int err;
6956
6957 err = mlxsw_sp_rif_subport_op(rif, true);
6958 if (err)
6959 return err;
6960
6961 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
6962 mlxsw_sp_fid_index(rif->fid), true);
6963 if (err)
6964 goto err_rif_fdb_op;
6965
6966 mlxsw_sp_fid_rif_set(rif->fid, rif);
6967 return 0;
6968
6969 err_rif_fdb_op:
6970 mlxsw_sp_rif_subport_op(rif, false);
6971 return err;
6972 }
6973
mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif * rif)6974 static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
6975 {
6976 struct mlxsw_sp_fid *fid = rif->fid;
6977
6978 mlxsw_sp_fid_rif_set(fid, NULL);
6979 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
6980 mlxsw_sp_fid_index(fid), false);
6981 mlxsw_sp_rif_macvlan_flush(rif);
6982 mlxsw_sp_rif_subport_op(rif, false);
6983 }
6984
6985 static struct mlxsw_sp_fid *
mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)6986 mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif,
6987 struct netlink_ext_ack *extack)
6988 {
6989 return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index);
6990 }
6991
6992 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = {
6993 .type = MLXSW_SP_RIF_TYPE_SUBPORT,
6994 .rif_size = sizeof(struct mlxsw_sp_rif_subport),
6995 .setup = mlxsw_sp_rif_subport_setup,
6996 .configure = mlxsw_sp_rif_subport_configure,
6997 .deconfigure = mlxsw_sp_rif_subport_deconfigure,
6998 .fid_get = mlxsw_sp_rif_subport_fid_get,
6999 };
7000
mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif * rif,enum mlxsw_reg_ritr_if_type type,u16 vid_fid,bool enable)7001 static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif,
7002 enum mlxsw_reg_ritr_if_type type,
7003 u16 vid_fid, bool enable)
7004 {
7005 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7006 char ritr_pl[MLXSW_REG_RITR_LEN];
7007
7008 mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id,
7009 rif->dev->mtu);
7010 mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
7011 mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid);
7012
7013 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
7014 }
7015
mlxsw_sp_router_port(const struct mlxsw_sp * mlxsw_sp)7016 u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
7017 {
7018 return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
7019 }
7020
mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif * rif)7021 static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif)
7022 {
7023 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7024 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
7025 int err;
7026
7027 err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, true);
7028 if (err)
7029 return err;
7030
7031 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7032 mlxsw_sp_router_port(mlxsw_sp), true);
7033 if (err)
7034 goto err_fid_mc_flood_set;
7035
7036 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7037 mlxsw_sp_router_port(mlxsw_sp), true);
7038 if (err)
7039 goto err_fid_bc_flood_set;
7040
7041 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7042 mlxsw_sp_fid_index(rif->fid), true);
7043 if (err)
7044 goto err_rif_fdb_op;
7045
7046 mlxsw_sp_fid_rif_set(rif->fid, rif);
7047 return 0;
7048
7049 err_rif_fdb_op:
7050 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7051 mlxsw_sp_router_port(mlxsw_sp), false);
7052 err_fid_bc_flood_set:
7053 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7054 mlxsw_sp_router_port(mlxsw_sp), false);
7055 err_fid_mc_flood_set:
7056 mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false);
7057 return err;
7058 }
7059
mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif * rif)7060 static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif)
7061 {
7062 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
7063 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7064 struct mlxsw_sp_fid *fid = rif->fid;
7065
7066 mlxsw_sp_fid_rif_set(fid, NULL);
7067 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7068 mlxsw_sp_fid_index(fid), false);
7069 mlxsw_sp_rif_macvlan_flush(rif);
7070 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7071 mlxsw_sp_router_port(mlxsw_sp), false);
7072 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7073 mlxsw_sp_router_port(mlxsw_sp), false);
7074 mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false);
7075 }
7076
7077 static struct mlxsw_sp_fid *
mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)7078 mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif,
7079 struct netlink_ext_ack *extack)
7080 {
7081 u16 vid;
7082 int err;
7083
7084 if (is_vlan_dev(rif->dev)) {
7085 vid = vlan_dev_vlan_id(rif->dev);
7086 } else {
7087 err = br_vlan_get_pvid(rif->dev, &vid);
7088 if (err < 0 || !vid) {
7089 NL_SET_ERR_MSG_MOD(extack, "Couldn't determine bridge PVID");
7090 return ERR_PTR(-EINVAL);
7091 }
7092 }
7093
7094 return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid);
7095 }
7096
mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif * rif,const char * mac)7097 static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
7098 {
7099 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
7100 struct switchdev_notifier_fdb_info info;
7101 struct net_device *br_dev;
7102 struct net_device *dev;
7103
7104 br_dev = is_vlan_dev(rif->dev) ? vlan_dev_real_dev(rif->dev) : rif->dev;
7105 dev = br_fdb_find_port(br_dev, mac, vid);
7106 if (!dev)
7107 return;
7108
7109 info.addr = mac;
7110 info.vid = vid;
7111 call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info);
7112 }
7113
7114 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops = {
7115 .type = MLXSW_SP_RIF_TYPE_VLAN,
7116 .rif_size = sizeof(struct mlxsw_sp_rif),
7117 .configure = mlxsw_sp_rif_vlan_configure,
7118 .deconfigure = mlxsw_sp_rif_vlan_deconfigure,
7119 .fid_get = mlxsw_sp_rif_vlan_fid_get,
7120 .fdb_del = mlxsw_sp_rif_vlan_fdb_del,
7121 };
7122
mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif * rif)7123 static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif)
7124 {
7125 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7126 u16 fid_index = mlxsw_sp_fid_index(rif->fid);
7127 int err;
7128
7129 err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index,
7130 true);
7131 if (err)
7132 return err;
7133
7134 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7135 mlxsw_sp_router_port(mlxsw_sp), true);
7136 if (err)
7137 goto err_fid_mc_flood_set;
7138
7139 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7140 mlxsw_sp_router_port(mlxsw_sp), true);
7141 if (err)
7142 goto err_fid_bc_flood_set;
7143
7144 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7145 mlxsw_sp_fid_index(rif->fid), true);
7146 if (err)
7147 goto err_rif_fdb_op;
7148
7149 mlxsw_sp_fid_rif_set(rif->fid, rif);
7150 return 0;
7151
7152 err_rif_fdb_op:
7153 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7154 mlxsw_sp_router_port(mlxsw_sp), false);
7155 err_fid_bc_flood_set:
7156 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7157 mlxsw_sp_router_port(mlxsw_sp), false);
7158 err_fid_mc_flood_set:
7159 mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
7160 return err;
7161 }
7162
mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif * rif)7163 static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
7164 {
7165 u16 fid_index = mlxsw_sp_fid_index(rif->fid);
7166 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7167 struct mlxsw_sp_fid *fid = rif->fid;
7168
7169 mlxsw_sp_fid_rif_set(fid, NULL);
7170 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7171 mlxsw_sp_fid_index(fid), false);
7172 mlxsw_sp_rif_macvlan_flush(rif);
7173 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7174 mlxsw_sp_router_port(mlxsw_sp), false);
7175 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7176 mlxsw_sp_router_port(mlxsw_sp), false);
7177 mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
7178 }
7179
7180 static struct mlxsw_sp_fid *
mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)7181 mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif,
7182 struct netlink_ext_ack *extack)
7183 {
7184 return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex);
7185 }
7186
mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif * rif,const char * mac)7187 static void mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
7188 {
7189 struct switchdev_notifier_fdb_info info;
7190 struct net_device *dev;
7191
7192 dev = br_fdb_find_port(rif->dev, mac, 0);
7193 if (!dev)
7194 return;
7195
7196 info.addr = mac;
7197 info.vid = 0;
7198 call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info);
7199 }
7200
7201 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
7202 .type = MLXSW_SP_RIF_TYPE_FID,
7203 .rif_size = sizeof(struct mlxsw_sp_rif),
7204 .configure = mlxsw_sp_rif_fid_configure,
7205 .deconfigure = mlxsw_sp_rif_fid_deconfigure,
7206 .fid_get = mlxsw_sp_rif_fid_fid_get,
7207 .fdb_del = mlxsw_sp_rif_fid_fdb_del,
7208 };
7209
7210 static struct mlxsw_sp_rif_ipip_lb *
mlxsw_sp_rif_ipip_lb_rif(struct mlxsw_sp_rif * rif)7211 mlxsw_sp_rif_ipip_lb_rif(struct mlxsw_sp_rif *rif)
7212 {
7213 return container_of(rif, struct mlxsw_sp_rif_ipip_lb, common);
7214 }
7215
7216 static void
mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif * rif,const struct mlxsw_sp_rif_params * params)7217 mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif *rif,
7218 const struct mlxsw_sp_rif_params *params)
7219 {
7220 struct mlxsw_sp_rif_params_ipip_lb *params_lb;
7221 struct mlxsw_sp_rif_ipip_lb *rif_lb;
7222
7223 params_lb = container_of(params, struct mlxsw_sp_rif_params_ipip_lb,
7224 common);
7225 rif_lb = mlxsw_sp_rif_ipip_lb_rif(rif);
7226 rif_lb->lb_config = params_lb->lb_config;
7227 }
7228
7229 static int
mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif * rif)7230 mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif)
7231 {
7232 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
7233 u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev);
7234 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7235 struct mlxsw_sp_vr *ul_vr;
7236 int err;
7237
7238 ul_vr = mlxsw_sp_vr_get(mlxsw_sp, ul_tb_id, NULL);
7239 if (IS_ERR(ul_vr))
7240 return PTR_ERR(ul_vr);
7241
7242 err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, true);
7243 if (err)
7244 goto err_loopback_op;
7245
7246 lb_rif->ul_vr_id = ul_vr->id;
7247 ++ul_vr->rif_count;
7248 return 0;
7249
7250 err_loopback_op:
7251 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
7252 return err;
7253 }
7254
mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif * rif)7255 static void mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif)
7256 {
7257 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
7258 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7259 struct mlxsw_sp_vr *ul_vr;
7260
7261 ul_vr = &mlxsw_sp->router->vrs[lb_rif->ul_vr_id];
7262 mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, false);
7263
7264 --ul_vr->rif_count;
7265 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
7266 }
7267
7268 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops = {
7269 .type = MLXSW_SP_RIF_TYPE_IPIP_LB,
7270 .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb),
7271 .setup = mlxsw_sp_rif_ipip_lb_setup,
7272 .configure = mlxsw_sp_rif_ipip_lb_configure,
7273 .deconfigure = mlxsw_sp_rif_ipip_lb_deconfigure,
7274 };
7275
7276 static const struct mlxsw_sp_rif_ops *mlxsw_sp_rif_ops_arr[] = {
7277 [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops,
7278 [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_ops,
7279 [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops,
7280 [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp_rif_ipip_lb_ops,
7281 };
7282
mlxsw_sp_rifs_init(struct mlxsw_sp * mlxsw_sp)7283 static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
7284 {
7285 u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
7286
7287 mlxsw_sp->router->rifs = kcalloc(max_rifs,
7288 sizeof(struct mlxsw_sp_rif *),
7289 GFP_KERNEL);
7290 if (!mlxsw_sp->router->rifs)
7291 return -ENOMEM;
7292
7293 mlxsw_sp->router->rif_ops_arr = mlxsw_sp_rif_ops_arr;
7294
7295 return 0;
7296 }
7297
mlxsw_sp_rifs_fini(struct mlxsw_sp * mlxsw_sp)7298 static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
7299 {
7300 int i;
7301
7302 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
7303 WARN_ON_ONCE(mlxsw_sp->router->rifs[i]);
7304
7305 kfree(mlxsw_sp->router->rifs);
7306 }
7307
7308 static int
mlxsw_sp_ipip_config_tigcr(struct mlxsw_sp * mlxsw_sp)7309 mlxsw_sp_ipip_config_tigcr(struct mlxsw_sp *mlxsw_sp)
7310 {
7311 char tigcr_pl[MLXSW_REG_TIGCR_LEN];
7312
7313 mlxsw_reg_tigcr_pack(tigcr_pl, true, 0);
7314 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tigcr), tigcr_pl);
7315 }
7316
mlxsw_sp_ipips_init(struct mlxsw_sp * mlxsw_sp)7317 static int mlxsw_sp_ipips_init(struct mlxsw_sp *mlxsw_sp)
7318 {
7319 mlxsw_sp->router->ipip_ops_arr = mlxsw_sp_ipip_ops_arr;
7320 INIT_LIST_HEAD(&mlxsw_sp->router->ipip_list);
7321 return mlxsw_sp_ipip_config_tigcr(mlxsw_sp);
7322 }
7323
mlxsw_sp_ipips_fini(struct mlxsw_sp * mlxsw_sp)7324 static void mlxsw_sp_ipips_fini(struct mlxsw_sp *mlxsw_sp)
7325 {
7326 WARN_ON(!list_empty(&mlxsw_sp->router->ipip_list));
7327 }
7328
mlxsw_sp_router_fib_dump_flush(struct notifier_block * nb)7329 static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
7330 {
7331 struct mlxsw_sp_router *router;
7332
7333 /* Flush pending FIB notifications and then flush the device's
7334 * table before requesting another dump. The FIB notification
7335 * block is unregistered, so no need to take RTNL.
7336 */
7337 mlxsw_core_flush_owq();
7338 router = container_of(nb, struct mlxsw_sp_router, fib_nb);
7339 mlxsw_sp_router_fib_flush(router->mlxsw_sp);
7340 }
7341
7342 #ifdef CONFIG_IP_ROUTE_MULTIPATH
mlxsw_sp_mp_hash_header_set(char * recr2_pl,int header)7343 static void mlxsw_sp_mp_hash_header_set(char *recr2_pl, int header)
7344 {
7345 mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, header, true);
7346 }
7347
mlxsw_sp_mp_hash_field_set(char * recr2_pl,int field)7348 static void mlxsw_sp_mp_hash_field_set(char *recr2_pl, int field)
7349 {
7350 mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true);
7351 }
7352
mlxsw_sp_mp4_hash_init(char * recr2_pl)7353 static void mlxsw_sp_mp4_hash_init(char *recr2_pl)
7354 {
7355 bool only_l3 = !init_net.ipv4.sysctl_fib_multipath_hash_policy;
7356
7357 mlxsw_sp_mp_hash_header_set(recr2_pl,
7358 MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP);
7359 mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_TCP_UDP);
7360 mlxsw_reg_recr2_ipv4_sip_enable(recr2_pl);
7361 mlxsw_reg_recr2_ipv4_dip_enable(recr2_pl);
7362 if (only_l3)
7363 return;
7364 mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_EN_IPV4);
7365 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV4_PROTOCOL);
7366 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_SPORT);
7367 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT);
7368 }
7369
mlxsw_sp_mp6_hash_init(char * recr2_pl)7370 static void mlxsw_sp_mp6_hash_init(char *recr2_pl)
7371 {
7372 bool only_l3 = !ip6_multipath_hash_policy(&init_net);
7373
7374 mlxsw_sp_mp_hash_header_set(recr2_pl,
7375 MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP);
7376 mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_TCP_UDP);
7377 mlxsw_reg_recr2_ipv6_sip_enable(recr2_pl);
7378 mlxsw_reg_recr2_ipv6_dip_enable(recr2_pl);
7379 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV6_NEXT_HEADER);
7380 if (only_l3) {
7381 mlxsw_sp_mp_hash_field_set(recr2_pl,
7382 MLXSW_REG_RECR2_IPV6_FLOW_LABEL);
7383 } else {
7384 mlxsw_sp_mp_hash_header_set(recr2_pl,
7385 MLXSW_REG_RECR2_TCP_UDP_EN_IPV6);
7386 mlxsw_sp_mp_hash_field_set(recr2_pl,
7387 MLXSW_REG_RECR2_TCP_UDP_SPORT);
7388 mlxsw_sp_mp_hash_field_set(recr2_pl,
7389 MLXSW_REG_RECR2_TCP_UDP_DPORT);
7390 }
7391 }
7392
mlxsw_sp_mp_hash_init(struct mlxsw_sp * mlxsw_sp)7393 static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
7394 {
7395 char recr2_pl[MLXSW_REG_RECR2_LEN];
7396 u32 seed;
7397
7398 get_random_bytes(&seed, sizeof(seed));
7399 mlxsw_reg_recr2_pack(recr2_pl, seed);
7400 mlxsw_sp_mp4_hash_init(recr2_pl);
7401 mlxsw_sp_mp6_hash_init(recr2_pl);
7402
7403 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl);
7404 }
7405 #else
mlxsw_sp_mp_hash_init(struct mlxsw_sp * mlxsw_sp)7406 static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
7407 {
7408 return 0;
7409 }
7410 #endif
7411
mlxsw_sp_dscp_init(struct mlxsw_sp * mlxsw_sp)7412 static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp)
7413 {
7414 char rdpm_pl[MLXSW_REG_RDPM_LEN];
7415 unsigned int i;
7416
7417 MLXSW_REG_ZERO(rdpm, rdpm_pl);
7418
7419 /* HW is determining switch priority based on DSCP-bits, but the
7420 * kernel is still doing that based on the ToS. Since there's a
7421 * mismatch in bits we need to make sure to translate the right
7422 * value ToS would observe, skipping the 2 least-significant ECN bits.
7423 */
7424 for (i = 0; i < MLXSW_REG_RDPM_DSCP_ENTRY_REC_MAX_COUNT; i++)
7425 mlxsw_reg_rdpm_pack(rdpm_pl, i, rt_tos2priority(i << 2));
7426
7427 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rdpm), rdpm_pl);
7428 }
7429
__mlxsw_sp_router_init(struct mlxsw_sp * mlxsw_sp)7430 static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
7431 {
7432 bool usp = init_net.ipv4.sysctl_ip_fwd_update_priority;
7433 char rgcr_pl[MLXSW_REG_RGCR_LEN];
7434 u64 max_rifs;
7435 int err;
7436
7437 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS))
7438 return -EIO;
7439 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
7440
7441 mlxsw_reg_rgcr_pack(rgcr_pl, true, true);
7442 mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs);
7443 mlxsw_reg_rgcr_usp_set(rgcr_pl, usp);
7444 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
7445 if (err)
7446 return err;
7447 return 0;
7448 }
7449
__mlxsw_sp_router_fini(struct mlxsw_sp * mlxsw_sp)7450 static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
7451 {
7452 char rgcr_pl[MLXSW_REG_RGCR_LEN];
7453
7454 mlxsw_reg_rgcr_pack(rgcr_pl, false, false);
7455 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
7456 }
7457
mlxsw_sp_router_init(struct mlxsw_sp * mlxsw_sp)7458 int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
7459 {
7460 struct mlxsw_sp_router *router;
7461 int err;
7462
7463 router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL);
7464 if (!router)
7465 return -ENOMEM;
7466 mlxsw_sp->router = router;
7467 router->mlxsw_sp = mlxsw_sp;
7468
7469 INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
7470 err = __mlxsw_sp_router_init(mlxsw_sp);
7471 if (err)
7472 goto err_router_init;
7473
7474 err = mlxsw_sp_rifs_init(mlxsw_sp);
7475 if (err)
7476 goto err_rifs_init;
7477
7478 err = mlxsw_sp_ipips_init(mlxsw_sp);
7479 if (err)
7480 goto err_ipips_init;
7481
7482 err = rhashtable_init(&mlxsw_sp->router->nexthop_ht,
7483 &mlxsw_sp_nexthop_ht_params);
7484 if (err)
7485 goto err_nexthop_ht_init;
7486
7487 err = rhashtable_init(&mlxsw_sp->router->nexthop_group_ht,
7488 &mlxsw_sp_nexthop_group_ht_params);
7489 if (err)
7490 goto err_nexthop_group_ht_init;
7491
7492 INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_list);
7493 err = mlxsw_sp_lpm_init(mlxsw_sp);
7494 if (err)
7495 goto err_lpm_init;
7496
7497 err = mlxsw_sp_mr_init(mlxsw_sp, &mlxsw_sp_mr_tcam_ops);
7498 if (err)
7499 goto err_mr_init;
7500
7501 err = mlxsw_sp_vrs_init(mlxsw_sp);
7502 if (err)
7503 goto err_vrs_init;
7504
7505 err = mlxsw_sp_neigh_init(mlxsw_sp);
7506 if (err)
7507 goto err_neigh_init;
7508
7509 mlxsw_sp->router->netevent_nb.notifier_call =
7510 mlxsw_sp_router_netevent_event;
7511 err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb);
7512 if (err)
7513 goto err_register_netevent_notifier;
7514
7515 err = mlxsw_sp_mp_hash_init(mlxsw_sp);
7516 if (err)
7517 goto err_mp_hash_init;
7518
7519 err = mlxsw_sp_dscp_init(mlxsw_sp);
7520 if (err)
7521 goto err_dscp_init;
7522
7523 mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
7524 err = register_fib_notifier(&mlxsw_sp->router->fib_nb,
7525 mlxsw_sp_router_fib_dump_flush);
7526 if (err)
7527 goto err_register_fib_notifier;
7528
7529 return 0;
7530
7531 err_register_fib_notifier:
7532 err_dscp_init:
7533 err_mp_hash_init:
7534 unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
7535 err_register_netevent_notifier:
7536 mlxsw_sp_neigh_fini(mlxsw_sp);
7537 err_neigh_init:
7538 mlxsw_sp_vrs_fini(mlxsw_sp);
7539 err_vrs_init:
7540 mlxsw_sp_mr_fini(mlxsw_sp);
7541 err_mr_init:
7542 mlxsw_sp_lpm_fini(mlxsw_sp);
7543 err_lpm_init:
7544 rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
7545 err_nexthop_group_ht_init:
7546 rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
7547 err_nexthop_ht_init:
7548 mlxsw_sp_ipips_fini(mlxsw_sp);
7549 err_ipips_init:
7550 mlxsw_sp_rifs_fini(mlxsw_sp);
7551 err_rifs_init:
7552 __mlxsw_sp_router_fini(mlxsw_sp);
7553 err_router_init:
7554 kfree(mlxsw_sp->router);
7555 return err;
7556 }
7557
mlxsw_sp_router_fini(struct mlxsw_sp * mlxsw_sp)7558 void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
7559 {
7560 unregister_fib_notifier(&mlxsw_sp->router->fib_nb);
7561 unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
7562 mlxsw_sp_neigh_fini(mlxsw_sp);
7563 mlxsw_sp_vrs_fini(mlxsw_sp);
7564 mlxsw_sp_mr_fini(mlxsw_sp);
7565 mlxsw_sp_lpm_fini(mlxsw_sp);
7566 rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
7567 rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
7568 mlxsw_sp_ipips_fini(mlxsw_sp);
7569 mlxsw_sp_rifs_fini(mlxsw_sp);
7570 __mlxsw_sp_router_fini(mlxsw_sp);
7571 kfree(mlxsw_sp->router);
7572 }
7573