1 /* 2 * Handling of a single switch port 3 * 4 * Copyright (c) 2017 Savoir-faire Linux Inc. 5 * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 */ 12 13 #include <linux/if_bridge.h> 14 #include <linux/notifier.h> 15 16 #include "dsa_priv.h" 17 18 static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v) 19 { 20 struct raw_notifier_head *nh = &dp->ds->dst->nh; 21 int err; 22 23 err = raw_notifier_call_chain(nh, e, v); 24 25 return notifier_to_errno(err); 26 } 27 28 int dsa_port_set_state(struct dsa_port *dp, u8 state, 29 struct switchdev_trans *trans) 30 { 31 struct dsa_switch *ds = dp->ds; 32 int port = dp->index; 33 34 if (switchdev_trans_ph_prepare(trans)) 35 return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; 36 37 if (ds->ops->port_stp_state_set) 38 ds->ops->port_stp_state_set(ds, port, state); 39 40 if (ds->ops->port_fast_age) { 41 /* Fast age FDB entries or flush appropriate forwarding database 42 * for the given port, if we are moving it from Learning or 43 * Forwarding state, to Disabled or Blocking or Listening state. 44 */ 45 46 if ((dp->stp_state == BR_STATE_LEARNING || 47 dp->stp_state == BR_STATE_FORWARDING) && 48 (state == BR_STATE_DISABLED || 49 state == BR_STATE_BLOCKING || 50 state == BR_STATE_LISTENING)) 51 ds->ops->port_fast_age(ds, port); 52 } 53 54 dp->stp_state = state; 55 56 return 0; 57 } 58 59 void dsa_port_set_state_now(struct dsa_port *dp, u8 state) 60 { 61 int err; 62 63 err = dsa_port_set_state(dp, state, NULL); 64 if (err) 65 pr_err("DSA: failed to set STP state %u (%d)\n", state, err); 66 } 67 68 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) 69 { 70 struct dsa_notifier_bridge_info info = { 71 .sw_index = dp->ds->index, 72 .port = dp->index, 73 .br = br, 74 }; 75 int err; 76 77 /* Here the port is already bridged. Reflect the current configuration 78 * so that drivers can program their chips accordingly. 79 */ 80 dp->bridge_dev = br; 81 82 err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); 83 84 /* The bridging is rolled back on error */ 85 if (err) 86 dp->bridge_dev = NULL; 87 88 return err; 89 } 90 91 void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) 92 { 93 struct dsa_notifier_bridge_info info = { 94 .sw_index = dp->ds->index, 95 .port = dp->index, 96 .br = br, 97 }; 98 int err; 99 100 /* Here the port is already unbridged. Reflect the current configuration 101 * so that drivers can program their chips accordingly. 102 */ 103 dp->bridge_dev = NULL; 104 105 err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info); 106 if (err) 107 pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); 108 109 /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, 110 * so allow it to be in BR_STATE_FORWARDING to be kept functional 111 */ 112 dsa_port_set_state_now(dp, BR_STATE_FORWARDING); 113 } 114 115 int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, 116 struct switchdev_trans *trans) 117 { 118 struct dsa_switch *ds = dp->ds; 119 120 /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ 121 if (switchdev_trans_ph_prepare(trans)) 122 return 0; 123 124 if (ds->ops->port_vlan_filtering) 125 return ds->ops->port_vlan_filtering(ds, dp->index, 126 vlan_filtering); 127 128 return 0; 129 } 130 131 int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, 132 struct switchdev_trans *trans) 133 { 134 unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); 135 unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); 136 struct dsa_notifier_ageing_time_info info = { 137 .ageing_time = ageing_time, 138 .trans = trans, 139 }; 140 141 if (switchdev_trans_ph_prepare(trans)) 142 return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); 143 144 dp->ageing_time = ageing_time; 145 146 return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); 147 } 148 149 int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, 150 u16 vid) 151 { 152 struct dsa_notifier_fdb_info info = { 153 .sw_index = dp->ds->index, 154 .port = dp->index, 155 .addr = addr, 156 .vid = vid, 157 }; 158 159 return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info); 160 } 161 162 int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr, 163 u16 vid) 164 { 165 struct dsa_notifier_fdb_info info = { 166 .sw_index = dp->ds->index, 167 .port = dp->index, 168 .addr = addr, 169 .vid = vid, 170 171 }; 172 173 return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info); 174 } 175 176 int dsa_port_mdb_add(struct dsa_port *dp, 177 const struct switchdev_obj_port_mdb *mdb, 178 struct switchdev_trans *trans) 179 { 180 struct dsa_notifier_mdb_info info = { 181 .sw_index = dp->ds->index, 182 .port = dp->index, 183 .trans = trans, 184 .mdb = mdb, 185 }; 186 187 return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info); 188 } 189 190 int dsa_port_mdb_del(struct dsa_port *dp, 191 const struct switchdev_obj_port_mdb *mdb) 192 { 193 struct dsa_notifier_mdb_info info = { 194 .sw_index = dp->ds->index, 195 .port = dp->index, 196 .mdb = mdb, 197 }; 198 199 return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info); 200 } 201 202 int dsa_port_vlan_add(struct dsa_port *dp, 203 const struct switchdev_obj_port_vlan *vlan, 204 struct switchdev_trans *trans) 205 { 206 struct dsa_notifier_vlan_info info = { 207 .sw_index = dp->ds->index, 208 .port = dp->index, 209 .trans = trans, 210 .vlan = vlan, 211 }; 212 213 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info); 214 } 215 216 int dsa_port_vlan_del(struct dsa_port *dp, 217 const struct switchdev_obj_port_vlan *vlan) 218 { 219 struct dsa_notifier_vlan_info info = { 220 .sw_index = dp->ds->index, 221 .port = dp->index, 222 .vlan = vlan, 223 }; 224 225 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); 226 } 227