]> Git Repo - J-linux.git/blob - drivers/net/ethernet/intel/ice/ice_lag.c
Merge tag 'trace-tools-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[J-linux.git] / drivers / net / ethernet / intel / ice / ice_lag.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2018-2021, Intel Corporation. */
3
4 /* Link Aggregation code */
5
6 #include "ice.h"
7 #include "ice_lag.h"
8
9 /**
10  * ice_lag_set_primary - set PF LAG state as Primary
11  * @lag: LAG info struct
12  */
13 static void ice_lag_set_primary(struct ice_lag *lag)
14 {
15         struct ice_pf *pf = lag->pf;
16
17         if (!pf)
18                 return;
19
20         if (lag->role != ICE_LAG_UNSET && lag->role != ICE_LAG_BACKUP) {
21                 dev_warn(ice_pf_to_dev(pf), "%s: Attempt to be Primary, but incompatible state.\n",
22                          netdev_name(lag->netdev));
23                 return;
24         }
25
26         lag->role = ICE_LAG_PRIMARY;
27 }
28
29 /**
30  * ice_lag_set_backup - set PF LAG state to Backup
31  * @lag: LAG info struct
32  */
33 static void ice_lag_set_backup(struct ice_lag *lag)
34 {
35         struct ice_pf *pf = lag->pf;
36
37         if (!pf)
38                 return;
39
40         if (lag->role != ICE_LAG_UNSET && lag->role != ICE_LAG_PRIMARY) {
41                 dev_dbg(ice_pf_to_dev(pf), "%s: Attempt to be Backup, but incompatible state\n",
42                         netdev_name(lag->netdev));
43                 return;
44         }
45
46         lag->role = ICE_LAG_BACKUP;
47 }
48
49 /**
50  * ice_display_lag_info - print LAG info
51  * @lag: LAG info struct
52  */
53 static void ice_display_lag_info(struct ice_lag *lag)
54 {
55         const char *name, *peer, *upper, *role, *bonded, *primary;
56         struct device *dev = &lag->pf->pdev->dev;
57
58         name = lag->netdev ? netdev_name(lag->netdev) : "unset";
59         peer = lag->peer_netdev ? netdev_name(lag->peer_netdev) : "unset";
60         upper = lag->upper_netdev ? netdev_name(lag->upper_netdev) : "unset";
61         primary = lag->primary ? "TRUE" : "FALSE";
62         bonded = lag->bonded ? "BONDED" : "UNBONDED";
63
64         switch (lag->role) {
65         case ICE_LAG_NONE:
66                 role = "NONE";
67                 break;
68         case ICE_LAG_PRIMARY:
69                 role = "PRIMARY";
70                 break;
71         case ICE_LAG_BACKUP:
72                 role = "BACKUP";
73                 break;
74         case ICE_LAG_UNSET:
75                 role = "UNSET";
76                 break;
77         default:
78                 role = "ERROR";
79         }
80
81         dev_dbg(dev, "%s %s, peer:%s, upper:%s, role:%s, primary:%s\n", name,
82                 bonded, peer, upper, role, primary);
83 }
84
85 /**
86  * ice_lag_info_event - handle NETDEV_BONDING_INFO event
87  * @lag: LAG info struct
88  * @ptr: opaque data pointer
89  *
90  * ptr is to be cast to (netdev_notifier_bonding_info *)
91  */
92 static void ice_lag_info_event(struct ice_lag *lag, void *ptr)
93 {
94         struct netdev_notifier_bonding_info *info;
95         struct netdev_bonding_info *bonding_info;
96         struct net_device *event_netdev;
97         const char *lag_netdev_name;
98
99         event_netdev = netdev_notifier_info_to_dev(ptr);
100         info = ptr;
101         lag_netdev_name = netdev_name(lag->netdev);
102         bonding_info = &info->bonding_info;
103
104         if (event_netdev != lag->netdev || !lag->bonded || !lag->upper_netdev)
105                 return;
106
107         if (bonding_info->master.bond_mode != BOND_MODE_ACTIVEBACKUP) {
108                 netdev_dbg(lag->netdev, "Bonding event recv, but mode not active/backup\n");
109                 goto lag_out;
110         }
111
112         if (strcmp(bonding_info->slave.slave_name, lag_netdev_name)) {
113                 netdev_dbg(lag->netdev, "Bonding event recv, but secondary info not for us\n");
114                 goto lag_out;
115         }
116
117         if (bonding_info->slave.state)
118                 ice_lag_set_backup(lag);
119         else
120                 ice_lag_set_primary(lag);
121
122 lag_out:
123         ice_display_lag_info(lag);
124 }
125
126 /**
127  * ice_lag_link - handle LAG link event
128  * @lag: LAG info struct
129  * @info: info from the netdev notifier
130  */
131 static void
132 ice_lag_link(struct ice_lag *lag, struct netdev_notifier_changeupper_info *info)
133 {
134         struct net_device *netdev_tmp, *upper = info->upper_dev;
135         struct ice_pf *pf = lag->pf;
136         int peers = 0;
137
138         if (lag->bonded)
139                 dev_warn(ice_pf_to_dev(pf), "%s Already part of a bond\n",
140                          netdev_name(lag->netdev));
141
142         rcu_read_lock();
143         for_each_netdev_in_bond_rcu(upper, netdev_tmp)
144                 peers++;
145         rcu_read_unlock();
146
147         if (lag->upper_netdev != upper) {
148                 dev_hold(upper);
149                 lag->upper_netdev = upper;
150         }
151
152         ice_clear_rdma_cap(pf);
153
154         lag->bonded = true;
155         lag->role = ICE_LAG_UNSET;
156
157         /* if this is the first element in an LAG mark as primary */
158         lag->primary = !!(peers == 1);
159 }
160
161 /**
162  * ice_lag_unlink - handle unlink event
163  * @lag: LAG info struct
164  * @info: info from netdev notification
165  */
166 static void
167 ice_lag_unlink(struct ice_lag *lag,
168                struct netdev_notifier_changeupper_info *info)
169 {
170         struct net_device *netdev_tmp, *upper = info->upper_dev;
171         struct ice_pf *pf = lag->pf;
172         bool found = false;
173
174         if (!lag->bonded) {
175                 netdev_dbg(lag->netdev, "bonding unlink event on non-LAG netdev\n");
176                 return;
177         }
178
179         /* determine if we are in the new LAG config or not */
180         rcu_read_lock();
181         for_each_netdev_in_bond_rcu(upper, netdev_tmp) {
182                 if (netdev_tmp == lag->netdev) {
183                         found = true;
184                         break;
185                 }
186         }
187         rcu_read_unlock();
188
189         if (found)
190                 return;
191
192         if (lag->upper_netdev) {
193                 dev_put(lag->upper_netdev);
194                 lag->upper_netdev = NULL;
195         }
196
197         lag->peer_netdev = NULL;
198         ice_set_rdma_cap(pf);
199         lag->bonded = false;
200         lag->role = ICE_LAG_NONE;
201 }
202
203 /**
204  * ice_lag_unregister - handle netdev unregister events
205  * @lag: LAG info struct
206  * @netdev: netdev reporting the event
207  */
208 static void ice_lag_unregister(struct ice_lag *lag, struct net_device *netdev)
209 {
210         struct ice_pf *pf = lag->pf;
211
212         /* check to see if this event is for this netdev
213          * check that we are in an aggregate
214          */
215         if (netdev != lag->netdev || !lag->bonded)
216                 return;
217
218         if (lag->upper_netdev) {
219                 dev_put(lag->upper_netdev);
220                 lag->upper_netdev = NULL;
221                 ice_set_rdma_cap(pf);
222         }
223         /* perform some cleanup in case we come back */
224         lag->bonded = false;
225         lag->role = ICE_LAG_NONE;
226 }
227
228 /**
229  * ice_lag_changeupper_event - handle LAG changeupper event
230  * @lag: LAG info struct
231  * @ptr: opaque pointer data
232  *
233  * ptr is to be cast into netdev_notifier_changeupper_info
234  */
235 static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr)
236 {
237         struct netdev_notifier_changeupper_info *info;
238         struct net_device *netdev;
239
240         info = ptr;
241         netdev = netdev_notifier_info_to_dev(ptr);
242
243         /* not for this netdev */
244         if (netdev != lag->netdev)
245                 return;
246
247         if (!info->upper_dev) {
248                 netdev_dbg(netdev, "changeupper rcvd, but no upper defined\n");
249                 return;
250         }
251
252         netdev_dbg(netdev, "bonding %s\n", info->linking ? "LINK" : "UNLINK");
253
254         if (!netif_is_lag_master(info->upper_dev)) {
255                 netdev_dbg(netdev, "changeupper rcvd, but not primary. bail\n");
256                 return;
257         }
258
259         if (info->linking)
260                 ice_lag_link(lag, info);
261         else
262                 ice_lag_unlink(lag, info);
263
264         ice_display_lag_info(lag);
265 }
266
267 /**
268  * ice_lag_changelower_event - handle LAG changelower event
269  * @lag: LAG info struct
270  * @ptr: opaque data pointer
271  *
272  * ptr to be cast to netdev_notifier_changelowerstate_info
273  */
274 static void ice_lag_changelower_event(struct ice_lag *lag, void *ptr)
275 {
276         struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
277
278         if (netdev != lag->netdev)
279                 return;
280
281         netdev_dbg(netdev, "bonding info\n");
282
283         if (!netif_is_lag_port(netdev))
284                 netdev_dbg(netdev, "CHANGELOWER rcvd, but netdev not in LAG. Bail\n");
285 }
286
287 /**
288  * ice_lag_event_handler - handle LAG events from netdev
289  * @notif_blk: notifier block registered by this netdev
290  * @event: event type
291  * @ptr: opaque data containing notifier event
292  */
293 static int
294 ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event,
295                       void *ptr)
296 {
297         struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
298         struct ice_lag *lag;
299
300         lag = container_of(notif_blk, struct ice_lag, notif_block);
301
302         if (!lag->netdev)
303                 return NOTIFY_DONE;
304
305         /* Check that the netdev is in the working namespace */
306         if (!net_eq(dev_net(netdev), &init_net))
307                 return NOTIFY_DONE;
308
309         switch (event) {
310         case NETDEV_CHANGEUPPER:
311                 ice_lag_changeupper_event(lag, ptr);
312                 break;
313         case NETDEV_CHANGELOWERSTATE:
314                 ice_lag_changelower_event(lag, ptr);
315                 break;
316         case NETDEV_BONDING_INFO:
317                 ice_lag_info_event(lag, ptr);
318                 break;
319         case NETDEV_UNREGISTER:
320                 ice_lag_unregister(lag, netdev);
321                 break;
322         default:
323                 break;
324         }
325
326         return NOTIFY_DONE;
327 }
328
329 /**
330  * ice_register_lag_handler - register LAG handler on netdev
331  * @lag: LAG struct
332  */
333 static int ice_register_lag_handler(struct ice_lag *lag)
334 {
335         struct device *dev = ice_pf_to_dev(lag->pf);
336         struct notifier_block *notif_blk;
337
338         notif_blk = &lag->notif_block;
339
340         if (!notif_blk->notifier_call) {
341                 notif_blk->notifier_call = ice_lag_event_handler;
342                 if (register_netdevice_notifier(notif_blk)) {
343                         notif_blk->notifier_call = NULL;
344                         dev_err(dev, "FAIL register LAG event handler!\n");
345                         return -EINVAL;
346                 }
347                 dev_dbg(dev, "LAG event handler registered\n");
348         }
349         return 0;
350 }
351
352 /**
353  * ice_unregister_lag_handler - unregister LAG handler on netdev
354  * @lag: LAG struct
355  */
356 static void ice_unregister_lag_handler(struct ice_lag *lag)
357 {
358         struct device *dev = ice_pf_to_dev(lag->pf);
359         struct notifier_block *notif_blk;
360
361         notif_blk = &lag->notif_block;
362         if (notif_blk->notifier_call) {
363                 unregister_netdevice_notifier(notif_blk);
364                 dev_dbg(dev, "LAG event handler unregistered\n");
365         }
366 }
367
368 /**
369  * ice_init_lag - initialize support for LAG
370  * @pf: PF struct
371  *
372  * Alloc memory for LAG structs and initialize the elements.
373  * Memory will be freed in ice_deinit_lag
374  */
375 int ice_init_lag(struct ice_pf *pf)
376 {
377         struct device *dev = ice_pf_to_dev(pf);
378         struct ice_lag *lag;
379         struct ice_vsi *vsi;
380         int err;
381
382         pf->lag = kzalloc(sizeof(*lag), GFP_KERNEL);
383         if (!pf->lag)
384                 return -ENOMEM;
385         lag = pf->lag;
386
387         vsi = ice_get_main_vsi(pf);
388         if (!vsi) {
389                 dev_err(dev, "couldn't get main vsi, link aggregation init fail\n");
390                 err = -EIO;
391                 goto lag_error;
392         }
393
394         lag->pf = pf;
395         lag->netdev = vsi->netdev;
396         lag->role = ICE_LAG_NONE;
397         lag->bonded = false;
398         lag->peer_netdev = NULL;
399         lag->upper_netdev = NULL;
400         lag->notif_block.notifier_call = NULL;
401
402         err = ice_register_lag_handler(lag);
403         if (err) {
404                 dev_warn(dev, "INIT LAG: Failed to register event handler\n");
405                 goto lag_error;
406         }
407
408         ice_display_lag_info(lag);
409
410         dev_dbg(dev, "INIT LAG complete\n");
411         return 0;
412
413 lag_error:
414         kfree(lag);
415         pf->lag = NULL;
416         return err;
417 }
418
419 /**
420  * ice_deinit_lag - Clean up LAG
421  * @pf: PF struct
422  *
423  * Clean up kernel LAG info and free memory
424  * This function is meant to only be called on driver remove/shutdown
425  */
426 void ice_deinit_lag(struct ice_pf *pf)
427 {
428         struct ice_lag *lag;
429
430         lag = pf->lag;
431
432         if (!lag)
433                 return;
434
435         if (lag->pf)
436                 ice_unregister_lag_handler(lag);
437
438         dev_put(lag->upper_netdev);
439
440         dev_put(lag->peer_netdev);
441
442         kfree(lag);
443
444         pf->lag = NULL;
445 }
This page took 0.054464 seconds and 4 git commands to generate.