1 /*- 2 * BSD LICENSE 3 * 4 * Copyright 2017 6WIND S.A. 5 * Copyright 2017 Mellanox. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of 6WIND S.A. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #ifndef _RTE_ETH_FAILSAFE_PRIVATE_H_ 35 #define _RTE_ETH_FAILSAFE_PRIVATE_H_ 36 37 #include <sys/queue.h> 38 39 #include <rte_atomic.h> 40 #include <rte_dev.h> 41 #include <rte_ethdev.h> 42 #include <rte_devargs.h> 43 44 #define FAILSAFE_DRIVER_NAME "Fail-safe PMD" 45 46 #define PMD_FAILSAFE_MAC_KVARG "mac" 47 #define PMD_FAILSAFE_HOTPLUG_POLL_KVARG "hotplug_poll" 48 #define PMD_FAILSAFE_PARAM_STRING \ 49 "dev(<ifc>)," \ 50 "exec(<shell command>)," \ 51 "mac=mac_addr," \ 52 "hotplug_poll=u64" \ 53 "" 54 55 #define FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS 2000 56 57 #define FAILSAFE_MAX_ETHPORTS 2 58 #define FAILSAFE_MAX_ETHADDR 128 59 60 /* TYPES */ 61 62 struct rxq { 63 struct fs_priv *priv; 64 uint16_t qid; 65 /* id of last sub_device polled */ 66 uint8_t last_polled; 67 unsigned int socket_id; 68 struct rte_eth_rxq_info info; 69 rte_atomic64_t refcnt[]; 70 }; 71 72 struct txq { 73 struct fs_priv *priv; 74 uint16_t qid; 75 unsigned int socket_id; 76 struct rte_eth_txq_info info; 77 rte_atomic64_t refcnt[]; 78 }; 79 80 struct rte_flow { 81 TAILQ_ENTRY(rte_flow) next; 82 /* sub_flows */ 83 struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS]; 84 /* flow description for synchronization */ 85 struct rte_flow_desc *fd; 86 }; 87 88 enum dev_state { 89 DEV_UNDEFINED, 90 DEV_PARSED, 91 DEV_PROBED, 92 DEV_ACTIVE, 93 DEV_STARTED, 94 }; 95 96 struct sub_device { 97 /* Exhaustive DPDK device description */ 98 struct rte_devargs devargs; 99 struct rte_bus *bus; 100 struct rte_device *dev; 101 struct rte_eth_dev *edev; 102 uint8_t sid; 103 /* Device state machine */ 104 enum dev_state state; 105 /* Last stats snapshot passed to user */ 106 struct rte_eth_stats stats_snapshot; 107 /* Some device are defined as a command line */ 108 char *cmdline; 109 /* fail-safe device backreference */ 110 struct rte_eth_dev *fs_dev; 111 /* flag calling for recollection */ 112 volatile unsigned int remove:1; 113 /* flow isolation state */ 114 int flow_isolated:1; 115 }; 116 117 struct fs_priv { 118 struct rte_eth_dev *dev; 119 /* 120 * Set of sub_devices. 121 * subs[0] is the preferred device 122 * any other is just another slave 123 */ 124 struct sub_device *subs; 125 uint8_t subs_head; /* if head == tail, no subs */ 126 uint8_t subs_tail; /* first invalid */ 127 uint8_t subs_tx; /* current emitting device */ 128 uint8_t current_probed; 129 /* flow mapping */ 130 TAILQ_HEAD(sub_flows, rte_flow) flow_list; 131 /* current number of mac_addr slots allocated. */ 132 uint32_t nb_mac_addr; 133 struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR]; 134 uint32_t mac_addr_pool[FAILSAFE_MAX_ETHADDR]; 135 /* current capabilities */ 136 struct rte_eth_dev_info infos; 137 /* 138 * Fail-safe state machine. 139 * This level will be tracking state of the EAL and eth 140 * layer at large as defined by the user application. 141 * It will then steer the sub_devices toward the same 142 * synchronized state. 143 */ 144 enum dev_state state; 145 struct rte_eth_stats stats_accumulator; 146 unsigned int pending_alarm:1; /* An alarm is pending */ 147 /* flow isolation state */ 148 int flow_isolated:1; 149 }; 150 151 /* MISC */ 152 153 int failsafe_hotplug_alarm_install(struct rte_eth_dev *dev); 154 int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev); 155 156 /* RX / TX */ 157 158 void set_burst_fn(struct rte_eth_dev *dev, int force_safe); 159 160 uint16_t failsafe_rx_burst(void *rxq, 161 struct rte_mbuf **rx_pkts, uint16_t nb_pkts); 162 uint16_t failsafe_tx_burst(void *txq, 163 struct rte_mbuf **tx_pkts, uint16_t nb_pkts); 164 165 uint16_t failsafe_rx_burst_fast(void *rxq, 166 struct rte_mbuf **rx_pkts, uint16_t nb_pkts); 167 uint16_t failsafe_tx_burst_fast(void *txq, 168 struct rte_mbuf **tx_pkts, uint16_t nb_pkts); 169 170 /* ARGS */ 171 172 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params); 173 void failsafe_args_free(struct rte_eth_dev *dev); 174 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params); 175 int failsafe_args_parse_subs(struct rte_eth_dev *dev); 176 177 /* EAL */ 178 179 int failsafe_eal_init(struct rte_eth_dev *dev); 180 int failsafe_eal_uninit(struct rte_eth_dev *dev); 181 182 /* ETH_DEV */ 183 184 int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev); 185 void failsafe_dev_remove(struct rte_eth_dev *dev); 186 void failsafe_stats_increment(struct rte_eth_stats *to, 187 struct rte_eth_stats *from); 188 int failsafe_eth_rmv_event_callback(uint16_t port_id, 189 enum rte_eth_event_type type, 190 void *arg, void *out); 191 int failsafe_eth_lsc_event_callback(uint16_t port_id, 192 enum rte_eth_event_type event, 193 void *cb_arg, void *out); 194 195 /* GLOBALS */ 196 197 extern const char pmd_failsafe_driver_name[]; 198 extern const struct eth_dev_ops failsafe_ops; 199 extern const struct rte_flow_ops fs_flow_ops; 200 extern uint64_t hotplug_poll; 201 extern int mac_from_arg; 202 203 /* HELPERS */ 204 205 /* dev: (struct rte_eth_dev *) fail-safe device */ 206 #define PRIV(dev) \ 207 ((struct fs_priv *)(dev)->data->dev_private) 208 209 /* sdev: (struct sub_device *) */ 210 #define ETH(sdev) \ 211 ((sdev)->edev) 212 213 /* sdev: (struct sub_device *) */ 214 #define PORT_ID(sdev) \ 215 (ETH(sdev)->data->port_id) 216 217 /* sdev: (struct sub_device *) */ 218 #define SUB_ID(sdev) \ 219 ((sdev)->sid) 220 221 /** 222 * Stateful iterator construct over fail-safe sub-devices: 223 * s: (struct sub_device *), iterator 224 * i: (uint8_t), increment 225 * dev: (struct rte_eth_dev *), fail-safe ethdev 226 * state: (enum dev_state), minimum acceptable device state 227 */ 228 #define FOREACH_SUBDEV_STATE(s, i, dev, state) \ 229 for (s = fs_find_next((dev), 0, state, &i); \ 230 s != NULL; \ 231 s = fs_find_next((dev), i + 1, state, &i)) 232 233 /** 234 * Iterator construct over fail-safe sub-devices: 235 * s: (struct sub_device *), iterator 236 * i: (uint8_t), increment 237 * dev: (struct rte_eth_dev *), fail-safe ethdev 238 */ 239 #define FOREACH_SUBDEV(s, i, dev) \ 240 FOREACH_SUBDEV_STATE(s, i, dev, DEV_UNDEFINED) 241 242 /* dev: (struct rte_eth_dev *) fail-safe device */ 243 #define PREFERRED_SUBDEV(dev) \ 244 (&PRIV(dev)->subs[0]) 245 246 /* dev: (struct rte_eth_dev *) fail-safe device */ 247 #define TX_SUBDEV(dev) \ 248 (PRIV(dev)->subs_tx >= PRIV(dev)->subs_tail ? NULL \ 249 : (PRIV(dev)->subs[PRIV(dev)->subs_tx].state < DEV_PROBED ? NULL \ 250 : &PRIV(dev)->subs[PRIV(dev)->subs_tx])) 251 252 /** 253 * s: (struct sub_device *) 254 * ops: (struct eth_dev_ops) member 255 */ 256 #define SUBOPS(s, ops) \ 257 (ETH(s)->dev_ops->ops) 258 259 /** 260 * Atomic guard 261 */ 262 263 /** 264 * a: (rte_atomic64_t) 265 */ 266 #define FS_ATOMIC_P(a) \ 267 rte_atomic64_add(&(a), 1) 268 269 /** 270 * a: (rte_atomic64_t) 271 */ 272 #define FS_ATOMIC_V(a) \ 273 rte_atomic64_sub(&(a), 1) 274 275 /** 276 * s: (struct sub_device *) 277 * i: uint16_t qid 278 */ 279 #define FS_ATOMIC_RX(s, i) \ 280 rte_atomic64_read( \ 281 &((struct rxq *)((s)->fs_dev->data->rx_queues[i]))->refcnt[(s)->sid] \ 282 ) 283 /** 284 * s: (struct sub_device *) 285 * i: uint16_t qid 286 */ 287 #define FS_ATOMIC_TX(s, i) \ 288 rte_atomic64_read( \ 289 &((struct txq *)((s)->fs_dev->data->tx_queues[i]))->refcnt[(s)->sid] \ 290 ) 291 292 #define LOG__(level, m, ...) \ 293 RTE_LOG(level, PMD, "net_failsafe: " m "%c", __VA_ARGS__) 294 #define LOG_(level, ...) LOG__(level, __VA_ARGS__, '\n') 295 #define DEBUG(...) LOG_(DEBUG, __VA_ARGS__) 296 #define INFO(...) LOG_(INFO, __VA_ARGS__) 297 #define WARN(...) LOG_(WARNING, __VA_ARGS__) 298 #define ERROR(...) LOG_(ERR, __VA_ARGS__) 299 300 /* inlined functions */ 301 302 static inline struct sub_device * 303 fs_find_next(struct rte_eth_dev *dev, 304 uint8_t sid, 305 enum dev_state min_state, 306 uint8_t *sid_out) 307 { 308 struct sub_device *subs; 309 uint8_t tail; 310 311 subs = PRIV(dev)->subs; 312 tail = PRIV(dev)->subs_tail; 313 while (sid < tail) { 314 if (subs[sid].state >= min_state) 315 break; 316 sid++; 317 } 318 *sid_out = sid; 319 if (sid >= tail) 320 return NULL; 321 return &subs[sid]; 322 } 323 324 /* 325 * Switch emitting device. 326 * If banned is set, banned must not be considered for 327 * the role of emitting device. 328 */ 329 static inline void 330 fs_switch_dev(struct rte_eth_dev *dev, 331 struct sub_device *banned) 332 { 333 struct sub_device *txd; 334 enum dev_state req_state; 335 336 req_state = PRIV(dev)->state; 337 txd = TX_SUBDEV(dev); 338 if (PREFERRED_SUBDEV(dev)->state >= req_state && 339 PREFERRED_SUBDEV(dev) != banned) { 340 if (txd != PREFERRED_SUBDEV(dev) && 341 (txd == NULL || 342 (req_state == DEV_STARTED) || 343 (txd && txd->state < DEV_STARTED))) { 344 DEBUG("Switching tx_dev to preferred sub_device"); 345 PRIV(dev)->subs_tx = 0; 346 } 347 } else if ((txd && txd->state < req_state) || 348 txd == NULL || 349 txd == banned) { 350 struct sub_device *sdev = NULL; 351 uint8_t i; 352 353 /* Using acceptable device */ 354 FOREACH_SUBDEV_STATE(sdev, i, dev, req_state) { 355 if (sdev == banned) 356 continue; 357 DEBUG("Switching tx_dev to sub_device %d", 358 i); 359 PRIV(dev)->subs_tx = i; 360 break; 361 } 362 if (i >= PRIV(dev)->subs_tail || sdev == NULL) { 363 DEBUG("No device ready, deactivating tx_dev"); 364 PRIV(dev)->subs_tx = PRIV(dev)->subs_tail; 365 } 366 } else { 367 return; 368 } 369 set_burst_fn(dev, 0); 370 rte_wmb(); 371 } 372 373 #endif /* _RTE_ETH_FAILSAFE_PRIVATE_H_ */ 374