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 "fd(<fd number>)," \ 52 "mac=mac_addr," \ 53 "hotplug_poll=u64" \ 54 "" 55 56 #define FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS 2000 57 58 #define FAILSAFE_MAX_ETHPORTS 2 59 #define FAILSAFE_MAX_ETHADDR 128 60 61 /* TYPES */ 62 63 struct rxq { 64 struct fs_priv *priv; 65 uint16_t qid; 66 /* next sub_device to poll */ 67 struct sub_device *sdev; 68 unsigned int socket_id; 69 struct rte_eth_rxq_info info; 70 rte_atomic64_t refcnt[]; 71 }; 72 73 struct txq { 74 struct fs_priv *priv; 75 uint16_t qid; 76 unsigned int socket_id; 77 struct rte_eth_txq_info info; 78 rte_atomic64_t refcnt[]; 79 }; 80 81 struct rte_flow { 82 TAILQ_ENTRY(rte_flow) next; 83 /* sub_flows */ 84 struct rte_flow *flows[FAILSAFE_MAX_ETHPORTS]; 85 /* flow description for synchronization */ 86 struct rte_flow_desc *fd; 87 }; 88 89 enum dev_state { 90 DEV_UNDEFINED, 91 DEV_PARSED, 92 DEV_PROBED, 93 DEV_ACTIVE, 94 DEV_STARTED, 95 }; 96 97 struct fs_stats { 98 struct rte_eth_stats stats; 99 uint64_t timestamp; 100 }; 101 102 struct sub_device { 103 /* Exhaustive DPDK device description */ 104 struct sub_device *next; 105 struct rte_devargs devargs; 106 struct rte_bus *bus; 107 struct rte_device *dev; 108 struct rte_eth_dev *edev; 109 uint8_t sid; 110 /* Device state machine */ 111 enum dev_state state; 112 /* Last stats snapshot passed to user */ 113 struct fs_stats stats_snapshot; 114 /* Some device are defined as a command line */ 115 char *cmdline; 116 /* Others are retrieved through a file descriptor */ 117 char *fd_str; 118 /* fail-safe device backreference */ 119 struct rte_eth_dev *fs_dev; 120 /* flag calling for recollection */ 121 volatile unsigned int remove:1; 122 /* flow isolation state */ 123 int flow_isolated: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_dev_remove(struct rte_eth_dev *dev); 195 void failsafe_stats_increment(struct rte_eth_stats *to, 196 struct rte_eth_stats *from); 197 int failsafe_eth_rmv_event_callback(uint16_t port_id, 198 enum rte_eth_event_type type, 199 void *arg, void *out); 200 int failsafe_eth_lsc_event_callback(uint16_t port_id, 201 enum rte_eth_event_type event, 202 void *cb_arg, void *out); 203 204 /* GLOBALS */ 205 206 extern const char pmd_failsafe_driver_name[]; 207 extern const struct eth_dev_ops failsafe_ops; 208 extern const struct rte_flow_ops fs_flow_ops; 209 extern uint64_t hotplug_poll; 210 extern int mac_from_arg; 211 212 /* HELPERS */ 213 214 /* dev: (struct rte_eth_dev *) fail-safe device */ 215 #define PRIV(dev) \ 216 ((struct fs_priv *)(dev)->data->dev_private) 217 218 /* sdev: (struct sub_device *) */ 219 #define ETH(sdev) \ 220 ((sdev)->edev) 221 222 /* sdev: (struct sub_device *) */ 223 #define PORT_ID(sdev) \ 224 (ETH(sdev)->data->port_id) 225 226 /* sdev: (struct sub_device *) */ 227 #define SUB_ID(sdev) \ 228 ((sdev)->sid) 229 230 /** 231 * Stateful iterator construct over fail-safe sub-devices: 232 * s: (struct sub_device *), iterator 233 * i: (uint8_t), increment 234 * dev: (struct rte_eth_dev *), fail-safe ethdev 235 * state: (enum dev_state), minimum acceptable device state 236 */ 237 #define FOREACH_SUBDEV_STATE(s, i, dev, state) \ 238 for (s = fs_find_next((dev), 0, state, &i); \ 239 s != NULL; \ 240 s = fs_find_next((dev), i + 1, state, &i)) 241 242 /** 243 * Iterator construct over fail-safe sub-devices: 244 * s: (struct sub_device *), iterator 245 * i: (uint8_t), increment 246 * dev: (struct rte_eth_dev *), fail-safe ethdev 247 */ 248 #define FOREACH_SUBDEV(s, i, dev) \ 249 FOREACH_SUBDEV_STATE(s, i, dev, DEV_UNDEFINED) 250 251 /* dev: (struct rte_eth_dev *) fail-safe device */ 252 #define PREFERRED_SUBDEV(dev) \ 253 (&PRIV(dev)->subs[0]) 254 255 /* dev: (struct rte_eth_dev *) fail-safe device */ 256 #define TX_SUBDEV(dev) \ 257 (PRIV(dev)->subs_tx >= PRIV(dev)->subs_tail ? NULL \ 258 : (PRIV(dev)->subs[PRIV(dev)->subs_tx].state < DEV_PROBED ? NULL \ 259 : &PRIV(dev)->subs[PRIV(dev)->subs_tx])) 260 261 /** 262 * s: (struct sub_device *) 263 * ops: (struct eth_dev_ops) member 264 */ 265 #define SUBOPS(s, ops) \ 266 (ETH(s)->dev_ops->ops) 267 268 /** 269 * Atomic guard 270 */ 271 272 /** 273 * a: (rte_atomic64_t) 274 */ 275 #define FS_ATOMIC_P(a) \ 276 rte_atomic64_set(&(a), 1) 277 278 /** 279 * a: (rte_atomic64_t) 280 */ 281 #define FS_ATOMIC_V(a) \ 282 rte_atomic64_set(&(a), 0) 283 284 /** 285 * s: (struct sub_device *) 286 * i: uint16_t qid 287 */ 288 #define FS_ATOMIC_RX(s, i) \ 289 rte_atomic64_read( \ 290 &((struct rxq *)((s)->fs_dev->data->rx_queues[i]))->refcnt[(s)->sid] \ 291 ) 292 /** 293 * s: (struct sub_device *) 294 * i: uint16_t qid 295 */ 296 #define FS_ATOMIC_TX(s, i) \ 297 rte_atomic64_read( \ 298 &((struct txq *)((s)->fs_dev->data->tx_queues[i]))->refcnt[(s)->sid] \ 299 ) 300 301 #define LOG__(level, m, ...) \ 302 RTE_LOG(level, PMD, "net_failsafe: " m "%c", __VA_ARGS__) 303 #define LOG_(level, ...) LOG__(level, __VA_ARGS__, '\n') 304 #define DEBUG(...) LOG_(DEBUG, __VA_ARGS__) 305 #define INFO(...) LOG_(INFO, __VA_ARGS__) 306 #define WARN(...) LOG_(WARNING, __VA_ARGS__) 307 #define ERROR(...) LOG_(ERR, __VA_ARGS__) 308 309 /* inlined functions */ 310 311 static inline struct sub_device * 312 fs_find_next(struct rte_eth_dev *dev, 313 uint8_t sid, 314 enum dev_state min_state, 315 uint8_t *sid_out) 316 { 317 struct sub_device *subs; 318 uint8_t tail; 319 320 subs = PRIV(dev)->subs; 321 tail = PRIV(dev)->subs_tail; 322 while (sid < tail) { 323 if (subs[sid].state >= min_state) 324 break; 325 sid++; 326 } 327 *sid_out = sid; 328 if (sid >= tail) 329 return NULL; 330 return &subs[sid]; 331 } 332 333 /* 334 * Switch emitting device. 335 * If banned is set, banned must not be considered for 336 * the role of emitting device. 337 */ 338 static inline void 339 fs_switch_dev(struct rte_eth_dev *dev, 340 struct sub_device *banned) 341 { 342 struct sub_device *txd; 343 enum dev_state req_state; 344 345 req_state = PRIV(dev)->state; 346 txd = TX_SUBDEV(dev); 347 if (PREFERRED_SUBDEV(dev)->state >= req_state && 348 PREFERRED_SUBDEV(dev) != banned) { 349 if (txd != PREFERRED_SUBDEV(dev) && 350 (txd == NULL || 351 (req_state == DEV_STARTED) || 352 (txd && txd->state < DEV_STARTED))) { 353 DEBUG("Switching tx_dev to preferred sub_device"); 354 PRIV(dev)->subs_tx = 0; 355 } 356 } else if ((txd && txd->state < req_state) || 357 txd == NULL || 358 txd == banned) { 359 struct sub_device *sdev = NULL; 360 uint8_t i; 361 362 /* Using acceptable device */ 363 FOREACH_SUBDEV_STATE(sdev, i, dev, req_state) { 364 if (sdev == banned) 365 continue; 366 DEBUG("Switching tx_dev to sub_device %d", 367 i); 368 PRIV(dev)->subs_tx = i; 369 break; 370 } 371 if (i >= PRIV(dev)->subs_tail || sdev == NULL) { 372 DEBUG("No device ready, deactivating tx_dev"); 373 PRIV(dev)->subs_tx = PRIV(dev)->subs_tail; 374 } 375 } else { 376 return; 377 } 378 set_burst_fn(dev, 0); 379 rte_wmb(); 380 } 381 382 #endif /* _RTE_ETH_FAILSAFE_PRIVATE_H_ */ 383