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 fs_stats { 97 struct rte_eth_stats stats; 98 uint64_t timestamp; 99 }; 100 101 struct sub_device { 102 /* Exhaustive DPDK device description */ 103 struct rte_devargs devargs; 104 struct rte_bus *bus; 105 struct rte_device *dev; 106 struct rte_eth_dev *edev; 107 uint8_t sid; 108 /* Device state machine */ 109 enum dev_state state; 110 /* Last stats snapshot passed to user */ 111 struct fs_stats stats_snapshot; 112 /* Some device are defined as a command line */ 113 char *cmdline; 114 /* fail-safe device backreference */ 115 struct rte_eth_dev *fs_dev; 116 /* flag calling for recollection */ 117 volatile unsigned int remove:1; 118 /* flow isolation state */ 119 int flow_isolated:1; 120 /* RMV callback registration state */ 121 unsigned int rmv_callback:1; 122 /* LSC callback registration state */ 123 unsigned int lsc_callback:1; 124 }; 125 126 struct fs_priv { 127 struct rte_eth_dev *dev; 128 /* 129 * Set of sub_devices. 130 * subs[0] is the preferred device 131 * any other is just another slave 132 */ 133 struct sub_device *subs; 134 uint8_t subs_head; /* if head == tail, no subs */ 135 uint8_t subs_tail; /* first invalid */ 136 uint8_t subs_tx; /* current emitting device */ 137 uint8_t current_probed; 138 /* flow mapping */ 139 TAILQ_HEAD(sub_flows, rte_flow) flow_list; 140 /* current number of mac_addr slots allocated. */ 141 uint32_t nb_mac_addr; 142 struct ether_addr mac_addrs[FAILSAFE_MAX_ETHADDR]; 143 uint32_t mac_addr_pool[FAILSAFE_MAX_ETHADDR]; 144 /* current capabilities */ 145 struct rte_eth_dev_info infos; 146 /* 147 * Fail-safe state machine. 148 * This level will be tracking state of the EAL and eth 149 * layer at large as defined by the user application. 150 * It will then steer the sub_devices toward the same 151 * synchronized state. 152 */ 153 enum dev_state state; 154 struct rte_eth_stats stats_accumulator; 155 unsigned int pending_alarm:1; /* An alarm is pending */ 156 /* flow isolation state */ 157 int flow_isolated:1; 158 }; 159 160 /* MISC */ 161 162 int failsafe_hotplug_alarm_install(struct rte_eth_dev *dev); 163 int failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev); 164 165 /* RX / TX */ 166 167 void set_burst_fn(struct rte_eth_dev *dev, int force_safe); 168 169 uint16_t failsafe_rx_burst(void *rxq, 170 struct rte_mbuf **rx_pkts, uint16_t nb_pkts); 171 uint16_t failsafe_tx_burst(void *txq, 172 struct rte_mbuf **tx_pkts, uint16_t nb_pkts); 173 174 uint16_t failsafe_rx_burst_fast(void *rxq, 175 struct rte_mbuf **rx_pkts, uint16_t nb_pkts); 176 uint16_t failsafe_tx_burst_fast(void *txq, 177 struct rte_mbuf **tx_pkts, uint16_t nb_pkts); 178 179 /* ARGS */ 180 181 int failsafe_args_parse(struct rte_eth_dev *dev, const char *params); 182 void failsafe_args_free(struct rte_eth_dev *dev); 183 int failsafe_args_count_subdevice(struct rte_eth_dev *dev, const char *params); 184 int failsafe_args_parse_subs(struct rte_eth_dev *dev); 185 186 /* EAL */ 187 188 int failsafe_eal_init(struct rte_eth_dev *dev); 189 int failsafe_eal_uninit(struct rte_eth_dev *dev); 190 191 /* ETH_DEV */ 192 193 int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev); 194 void failsafe_eth_dev_unregister_callbacks(struct sub_device *sdev); 195 void failsafe_dev_remove(struct rte_eth_dev *dev); 196 void failsafe_stats_increment(struct rte_eth_stats *to, 197 struct rte_eth_stats *from); 198 int failsafe_eth_rmv_event_callback(uint16_t port_id, 199 enum rte_eth_event_type type, 200 void *arg, void *out); 201 int failsafe_eth_lsc_event_callback(uint16_t port_id, 202 enum rte_eth_event_type event, 203 void *cb_arg, void *out); 204 205 /* GLOBALS */ 206 207 extern const char pmd_failsafe_driver_name[]; 208 extern const struct eth_dev_ops failsafe_ops; 209 extern const struct rte_flow_ops fs_flow_ops; 210 extern uint64_t hotplug_poll; 211 extern int mac_from_arg; 212 213 /* HELPERS */ 214 215 /* dev: (struct rte_eth_dev *) fail-safe device */ 216 #define PRIV(dev) \ 217 ((struct fs_priv *)(dev)->data->dev_private) 218 219 /* sdev: (struct sub_device *) */ 220 #define ETH(sdev) \ 221 ((sdev)->edev) 222 223 /* sdev: (struct sub_device *) */ 224 #define PORT_ID(sdev) \ 225 (ETH(sdev)->data->port_id) 226 227 /* sdev: (struct sub_device *) */ 228 #define SUB_ID(sdev) \ 229 ((sdev)->sid) 230 231 /** 232 * Stateful iterator construct over fail-safe sub-devices: 233 * s: (struct sub_device *), iterator 234 * i: (uint8_t), increment 235 * dev: (struct rte_eth_dev *), fail-safe ethdev 236 * state: (enum dev_state), minimum acceptable device state 237 */ 238 #define FOREACH_SUBDEV_STATE(s, i, dev, state) \ 239 for (s = fs_find_next((dev), 0, state, &i); \ 240 s != NULL; \ 241 s = fs_find_next((dev), i + 1, state, &i)) 242 243 /** 244 * Iterator construct over fail-safe sub-devices: 245 * s: (struct sub_device *), iterator 246 * i: (uint8_t), increment 247 * dev: (struct rte_eth_dev *), fail-safe ethdev 248 */ 249 #define FOREACH_SUBDEV(s, i, dev) \ 250 FOREACH_SUBDEV_STATE(s, i, dev, DEV_UNDEFINED) 251 252 /* dev: (struct rte_eth_dev *) fail-safe device */ 253 #define PREFERRED_SUBDEV(dev) \ 254 (&PRIV(dev)->subs[0]) 255 256 /* dev: (struct rte_eth_dev *) fail-safe device */ 257 #define TX_SUBDEV(dev) \ 258 (PRIV(dev)->subs_tx >= PRIV(dev)->subs_tail ? NULL \ 259 : (PRIV(dev)->subs[PRIV(dev)->subs_tx].state < DEV_PROBED ? NULL \ 260 : &PRIV(dev)->subs[PRIV(dev)->subs_tx])) 261 262 /** 263 * s: (struct sub_device *) 264 * ops: (struct eth_dev_ops) member 265 */ 266 #define SUBOPS(s, ops) \ 267 (ETH(s)->dev_ops->ops) 268 269 /** 270 * Atomic guard 271 */ 272 273 /** 274 * a: (rte_atomic64_t) 275 */ 276 #define FS_ATOMIC_P(a) \ 277 rte_atomic64_add(&(a), 1) 278 279 /** 280 * a: (rte_atomic64_t) 281 */ 282 #define FS_ATOMIC_V(a) \ 283 rte_atomic64_sub(&(a), 1) 284 285 /** 286 * s: (struct sub_device *) 287 * i: uint16_t qid 288 */ 289 #define FS_ATOMIC_RX(s, i) \ 290 rte_atomic64_read( \ 291 &((struct rxq *)((s)->fs_dev->data->rx_queues[i]))->refcnt[(s)->sid] \ 292 ) 293 /** 294 * s: (struct sub_device *) 295 * i: uint16_t qid 296 */ 297 #define FS_ATOMIC_TX(s, i) \ 298 rte_atomic64_read( \ 299 &((struct txq *)((s)->fs_dev->data->tx_queues[i]))->refcnt[(s)->sid] \ 300 ) 301 302 #define LOG__(level, m, ...) \ 303 RTE_LOG(level, PMD, "net_failsafe: " m "%c", __VA_ARGS__) 304 #define LOG_(level, ...) LOG__(level, __VA_ARGS__, '\n') 305 #define DEBUG(...) LOG_(DEBUG, __VA_ARGS__) 306 #define INFO(...) LOG_(INFO, __VA_ARGS__) 307 #define WARN(...) LOG_(WARNING, __VA_ARGS__) 308 #define ERROR(...) LOG_(ERR, __VA_ARGS__) 309 310 /* inlined functions */ 311 312 static inline struct sub_device * 313 fs_find_next(struct rte_eth_dev *dev, 314 uint8_t sid, 315 enum dev_state min_state, 316 uint8_t *sid_out) 317 { 318 struct sub_device *subs; 319 uint8_t tail; 320 321 subs = PRIV(dev)->subs; 322 tail = PRIV(dev)->subs_tail; 323 while (sid < tail) { 324 if (subs[sid].state >= min_state) 325 break; 326 sid++; 327 } 328 *sid_out = sid; 329 if (sid >= tail) 330 return NULL; 331 return &subs[sid]; 332 } 333 334 /* 335 * Switch emitting device. 336 * If banned is set, banned must not be considered for 337 * the role of emitting device. 338 */ 339 static inline void 340 fs_switch_dev(struct rte_eth_dev *dev, 341 struct sub_device *banned) 342 { 343 struct sub_device *txd; 344 enum dev_state req_state; 345 346 req_state = PRIV(dev)->state; 347 txd = TX_SUBDEV(dev); 348 if (PREFERRED_SUBDEV(dev)->state >= req_state && 349 PREFERRED_SUBDEV(dev) != banned) { 350 if (txd != PREFERRED_SUBDEV(dev) && 351 (txd == NULL || 352 (req_state == DEV_STARTED) || 353 (txd && txd->state < DEV_STARTED))) { 354 DEBUG("Switching tx_dev to preferred sub_device"); 355 PRIV(dev)->subs_tx = 0; 356 } 357 } else if ((txd && txd->state < req_state) || 358 txd == NULL || 359 txd == banned) { 360 struct sub_device *sdev = NULL; 361 uint8_t i; 362 363 /* Using acceptable device */ 364 FOREACH_SUBDEV_STATE(sdev, i, dev, req_state) { 365 if (sdev == banned) 366 continue; 367 DEBUG("Switching tx_dev to sub_device %d", 368 i); 369 PRIV(dev)->subs_tx = i; 370 break; 371 } 372 if (i >= PRIV(dev)->subs_tail || sdev == NULL) { 373 DEBUG("No device ready, deactivating tx_dev"); 374 PRIV(dev)->subs_tx = PRIV(dev)->subs_tail; 375 } 376 } else { 377 return; 378 } 379 set_burst_fn(dev, 0); 380 rte_wmb(); 381 } 382 383 #endif /* _RTE_ETH_FAILSAFE_PRIVATE_H_ */ 384