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