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