1.\" $NetBSD: altq.9,v 1.5 2001/10/29 23:04:29 jdolecek Exp $ 2.\" $OpenBSD: altq.9,v 1.4 2001/07/12 12:41:42 itojun Exp $ 3.\" 4.\" Copyright (C) 2001 5.\" Sony Computer Science Laboratories Inc. All rights reserved. 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.\" 1. Redistributions of source code must retain the above copyright 11.\" notice, this list of conditions and the following disclaimer. 12.\" 2. Redistributions in binary form must reproduce the above copyright 13.\" notice, this list of conditions and the following disclaimer in the 14.\" documentation and/or other materials provided with the distribution. 15.\" 16.\" THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 17.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19.\" ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 20.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26.\" SUCH DAMAGE. 27.\" 28.Dd July 10, 2001 29.Dt ALTQ 9 30.Os 31.\" 32.Sh NAME 33.Nm ALTQ 34.Nd kernel interfaces for manipulating output queues on network interfaces 35.Sh SYNOPSIS 36.Fd #include <sys/types.h> 37.Fd #include <sys/socket.h> 38.Fd #include <net/if.h> 39.Ft void \"macro 40.Fn IFQ_ENQUEUE "struct ifaltq *ifq" "struct mbuf *m" "int error" 41.Ft void \"macro 42.Fn IFQ_DEQUEUE "struct ifaltq *ifq" "struct mbuf *m" 43.Ft void \"macro 44.Fn IFQ_POLL "struct ifaltq *ifq" "struct mbuf *m" 45.Ft void \"macro 46.Fn IFQ_PURGE "struct ifaltq *ifq" 47.Ft void \"macro 48.Fn IFQ_CLASSIFY "struct ifaltq *ifq" "struct mbuf *m" "int af" "struct altq_pktattr *pktattr" 49.Ft void \"macro 50.Fn IFQ_IS_EMPTY "struct ifaltq *ifq" 51.Ft void \"macro 52.Fn IFQ_SET_MAXLEN "struct ifaltq *ifq" "int len" 53.Ft void \"macro 54.Fn IFQ_INC_LEN "struct ifaltq *ifq" 55.Ft void \"macro 56.Fn IFQ_DEC_LEN "struct ifaltq *ifq" 57.Ft void \"macro 58.Fn IFQ_INC_DROPS "struct ifaltq *ifq" 59.Ft void \"macro 60.Fn IFQ_SET_READY "struct ifaltq *ifq" 61.Sh DESCRIPTION 62The ALTQ system is a framework to manage queueing disciplines on network 63interfaces. ALTQ introduces new macros to manipulate output queues. 64The output queue macros are used to abstract queue operations and not to 65touch the internal fields of the output queue structure. 66The macros are independent from the ALTQ implementation, and compatible with the 67traditional 68.Dv ifqueue 69macros for ease of transition. 70.Pp 71.Fn IFQ_ENQUEUE 72enqueues a packet 73.Fa m 74to the queue 75.Fa ifq . 76The underlying queueing discipline may discard the packet. 77.Fa error 78is set to 0 on success, or 79.Dv ENOBUFS 80if the packet is discarded. 81.Fa m 82will be freed by the device driver on success or by the queueing discipline on 83failure so that the caller should not touch 84.Fa m 85after calling 86.Fn IFQ_ENQUEUE . 87.Pp 88.Fn IFQ_DEQUEUE 89dequeues a packet from the queue. The dequeued packet is returned in 90.Fa m , 91or 92.Fa m 93is set to 94.Dv NULL 95if no packet is dequeued. 96The caller must always check 97.Fa m 98since a non-empty queue could return 99.Dv NULL 100under rate-limiting. 101.Pp 102.Fn IFQ_POLL 103returns the next packet without removing it from the queue. 104It is guaranteed by the underlying queueing discipline that 105.Fn IFQ_DEQUEUE 106immediately after 107.Fn IFQ_POLL 108returns the same packet. 109.Pp 110.Fn IFQ_PURGE 111discards all the packets in the queue. 112The purge operation is needed since a non-work conserving queue cannot be 113emptied by a dequeue loop. 114.Pp 115.Fn IFQ_CLASSIFY 116classifies a packet to a scheduling class, and returns the result in 117.Fa pktattr . 118.Pp 119.Fn IFQ_IS_EMPTY 120can be used to check if the queue is empty. 121Note that 122.Fn IFQ_DEQUEUE 123could still return 124.Dv NULL 125if the queueing discipline is non-work conserving. 126.Pp 127.Fn IFQ_SET_MAXLEN 128sets the queue length limit to the default FIFO queue. 129.Pp 130.Fn IFQ_INC_LEN 131and 132.Fn IFQ_DEC_LEN 133increment or decrement the current queue length in packets. 134.Pp 135.Fn IFQ_INC_DROPS 136increments the drop counter and is equal to 137.Fn IF_DROP . 138It is defined for naming consistency. 139.Pp 140.Fn IFQ_SET_READY 141sets a flag to indicate this driver is converted to use the new macros. 142ALTQ can be enabled only on interfaces with this flag. 143.Sh COMPATIBILITY 144.Ss ifaltq structure 145In order to keep compatibility with the existing code, the new 146output queue structure 147.Dv ifaltq 148has the same fields. The traditional 149.Fn IF_XXX 150macros and the code directly referencing the fields within 151.Dv if_snd 152still work with 153.Dv ifaltq . 154(Once we finish conversions of all the drivers, we no longer need 155these fields.) 156.Bd -literal 157 ##old-style## ##new-style## 158 | 159 struct ifqueue { | struct ifaltq { 160 struct mbuf *ifq_head; | struct mbuf *ifq_head; 161 struct mbuf *ifq_tail; | struct mbuf *ifq_tail; 162 int ifq_len; | int ifq_len; 163 int ifq_maxlen; | int ifq_maxlen; 164 int ifq_drops; | int ifq_drops; 165 }; | /* altq related fields */ 166 | ...... 167 | }; 168 | 169.Ed 170The new structure replaces 171.Dv struct ifqueue 172in 173.Dv struct ifnet . 174.Bd -literal 175 ##old-style## ##new-style## 176 | 177 struct ifnet { | struct ifnet { 178 .... | .... 179 | 180 struct ifqueue if_snd; | struct ifaltq if_snd; 181 | 182 .... | .... 183 }; | }; 184 | 185.Ed 186The (simplified) new 187.Fn IFQ_XXX 188macros looks like: 189.Bd -literal 190 #ifdef ALTQ 191 #define IFQ_DEQUEUE(ifq, m) \e 192 if (ALTQ_IS_ENABLED((ifq)) \e 193 ALTQ_DEQUEUE((ifq), (m)); \e 194 else \e 195 IF_DEQUEUE((ifq), (m)); 196 #else 197 #define IFQ_DEQUEUE(ifq, m) IF_DEQUEUE((ifq), (m)); 198 #endif 199.Ed 200.Ss Enqueue operation 201The semantics of the enqueue operation are changed. In the new style, 202enqueue and packet drop are combined since they cannot be easily 203separated in many queueing disciplines. 204The new enqueue operation corresponds to the following macro that is 205written with the old macros. 206.Bd -literal 207#define IFQ_ENQUEUE(ifq, m, error) \e 208do { \e 209 if (IF_QFULL((ifq))) { \e 210 m_freem((m)); \e 211 (error) = ENOBUFS; \e 212 IF_DROP(ifq); \e 213 } else { \e 214 IF_ENQUEUE((ifq), (m)); \e 215 (error) = 0; \e 216 } \e 217} while (0) 218.Ed 219.Pp 220.Fn IFQ_ENQUEUE 221does the followings: 222.Bl -hyphen -compact 223.It 224queue a packet 225.It 226drop (and free) a packet if the enqueue operation fails 227.El 228If the enqueue operation fails, 229.Fa error 230is set to 231.Dv ENOBUFS . 232.Fa mbuf 233is freed by the queueing discipline. 234The caller should not touch mbuf after calling 235.Fn IFQ_ENQUEUE 236so that the caller may need to copy 237.Fa m_pkthdr.len 238or 239.Fa m_flags 240field beforehand for statistics. 241The caller should not use 242.Fn senderr 243since mbuf was already freed. 244.Pp 245The new style 246.Fn if_output 247looks as follows: 248.Bd -literal 249 ##old-style## ##new-style## 250 | 251 int | int 252 ether_output(ifp, m0, dst, rt0) | ether_output(ifp, m0, dst, rt0) 253 { | { 254 ...... | ...... 255 | 256 | mflags = m->m_flags; 257 | len = m->m_pkthdr.len; 258 s = splimp(); | s = splimp(); 259 if (IF_QFULL(&ifp->if_snd)) { | IFQ_ENQUEUE(&ifp->if_snd, m, 260 | error); 261 IF_DROP(&ifp->if_snd); | if (error != 0) { 262 splx(s); | splx(s); 263 senderr(ENOBUFS); | return (error); 264 } | } 265 IF_ENQUEUE(&ifp->if_snd, m); | 266 ifp->if_obytes += | ifp->if_obytes += len; 267 m->m_pkthdr.len; | 268 if (m->m_flags & M_MCAST) | if (mflags & M_MCAST) 269 ifp->if_omcasts++; | ifp->if_omcasts++; 270 | 271 if ((ifp->if_flags & IFF_OACTIVE) | if ((ifp->if_flags & IFF_OACTIVE) 272 == 0) | == 0) 273 (*ifp->if_start)(ifp); | (*ifp->if_start)(ifp); 274 splx(s); | splx(s); 275 return (error); | return (error); 276 | 277 bad: | bad: 278 if (m) | if (m) 279 m_freem(m); | m_freem(m); 280 return (error); | return (error); 281 } | } 282 | 283.Ed 284.Ss Classifier 285The classifier mechanism is currently implemented in 286.Fn if_output . 287.Dv struct altq_pktattr 288is used to store the classifier result, and it is passed to the enqueue 289function. 290(We will change the method to tag the classifier result to mbuf in the future.) 291.Bd -literal 292int 293ether_output(ifp, m0, dst, rt0) 294{ 295 ...... 296 struct altq_pktattr pktattr; 297 298 ...... 299 300 /* classify the packet before prepending link-headers */ 301 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr); 302 303 /* prepend link-level headers */ 304 ...... 305 306 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error); 307 308 ...... 309} 310.Ed 311.Sh HOW TO CONVERT THE EXISTING DRIVERS 312First, make sure the corresponding 313.Fn if_output 314is already converted to the new style. 315.Pp 316Look for 317.Fa if_snd 318in the driver. Probably, you need to make changes to the lines that include 319.Fa if_snd . 320.Ss Empty check operation 321If the code checks 322.Fa ifq_head 323to see whether the queue is empty or not, use 324.Fn IFQ_IS_EMPTY . 325.Bd -literal 326 ##old-style## ##new-style## 327 | 328 if (ifp->if_snd.ifq_head != NULL) | if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) 329 | 330.Ed 331Note that 332.Fn IFQ_POLL 333can be used for the same purpose, but 334.Fn IFQ_POLL 335could be costly for a complex scheduling algorithm since 336.Fn IFQ_POLL 337needs to run the scheduling algorithm to select the next packet. 338On the other hand, 339.Fn IFQ_IS_EMPTY 340checks only if there is any packet stored in the queue. 341Another difference is that even when 342.Fn IFQ_IS_EMPTY 343is 344.Dv FALSE , 345.Fn IFQ_DEQUEUE 346could still return 347.Dv NULL 348if the queue is under rate-limiting. 349.Ss Dequeue operation 350Replace 351.Fn IF_DEQUEUE 352by 353.Fn IFQ_DEQUEUE . 354Always check whether the dequeued mbuf is 355.Dv NULL 356or not. 357Note that even when 358.Fn IFQ_IS_EMPTY 359is 360.Dv FALSE , 361.Fn IFQ_DEQUEUE 362could return 363.Dv NULL 364due to rate-limiting. 365.Bd -literal 366 ##old-style## ##new-style## 367 | 368 IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE(&ifp->if_snd, m); 369 | if (m == NULL) 370 | return; 371 | 372.Ed 373A driver is supposed to call 374.Fn if_start 375from transmission complete interrupts in order to trigger the next dequeue. 376.Ss Poll-and-dequeue operation 377If the code polls the packet at the head of the queue and actually uses 378the packet before dequeueing it, use 379.Fn IFQ_POLL 380and 381.Fn IFQ_DEQUEUE . 382.Bd -literal 383 ##old-style## ##new-style## 384 | 385 m = ifp->if_snd.ifq_head; | IFQ_POLL(&ifp->if_snd, m); 386 if (m != NULL) { | if (m != NULL) { 387 | 388 /* use m to get resources */ | /* use m to get resources */ 389 if (something goes wrong) | if (something goes wrong) 390 return; | return; 391 | 392 IF_DEQUEUE(&ifp->if_snd, m); | IFQ_DEQUEUE(&ifp->if_snd, m); 393 | 394 /* kick the hardware */ | /* kick the hardware */ 395 } | } 396 | 397.Ed 398It is guaranteed that 399.Fn IFQ_DEQUEUE 400immediately after 401.Fn IFQ_POLL 402returns the same packet. 403Note that they need to be guarded by 404.Fn splimp 405if called from outside of 406.Fn if_start . 407.Ss Eliminating IF_PREPEND 408If the code uses 409.Fn IF_PREPEND , 410you have to eliminate it since the prepend operation is not possible for many 411queueing disciplines. A common use of 412.Fn IF_PREPEND 413is to cancel the previous dequeue operation. 414You have to convert the logic into poll-and-dequeue. 415.Bd -literal 416 ##old-style## ##new-style## 417 | 418 IF_DEQUEUE(&ifp->if_snd, m); | IFQ_POLL(&ifp->if_snd, m); 419 if (m != NULL) { | if (m != NULL) { 420 | 421 if (something_goes_wrong) { | if (something_goes_wrong) { 422 IF_PREPEND(&ifp->if_snd, m); | 423 return; | return; 424 } | } 425 | 426 | /* at this point, the driver 427 | * is committed to send this 428 | * packet. 429 | */ 430 | IFQ_DEQUEUE(&ifp->if_snd, m); 431 | 432 /* kick the hardware */ | /* kick the hardware */ 433 } | } 434 | 435.Ed 436.Ss Purge operation 437Use 438.Fn IFQ_PURGE 439to empty the queue. 440Note that a non-work conserving queue cannot be emptied by a dequeue loop. 441.Bd -literal 442 ##old-style## ##new-style## 443 | 444 while (ifp->if_snd.ifq_head != NULL) {| IFQ_PURGE(&ifp->if_snd); 445 IF_DEQUEUE(&ifp->if_snd, m); | 446 m_freem(m); | 447 } | 448 | 449.Ed 450.Ss Attach routine 451Use 452.Fn IFQ_SET_MAXLEN 453to set 454.Fa ifq_maxlen 455to 456.Fa len . 457Add 458.Fn IFQ_SET_READY 459to show this driver is converted to the new style. 460(This is used to distinguish new-style drivers.) 461.Bd -literal 462 ##old-style## ##new-style## 463 | 464 ifp->if_snd.ifq_maxlen = qsize; | IFQ_SET_MAXLEN(&ifp->if_snd, qsize); 465 | IFQ_SET_READY(&ifp->if_snd); 466 if_attach(ifp); | if_attach(ifp); 467 | 468.Ed 469.Ss Other issues 470The new macros for statistics: 471.Bd -literal 472 ##old-style## ##new-style## 473 | 474 IF_DROP(&ifp->if_snd); | IFQ_INC_DROPS(&ifp->if_snd); 475 | 476 ifp->if_snd.ifq_len++; | IFQ_INC_LEN(&ifp->if_snd); 477 | 478 ifp->if_snd.ifq_len--; | IFQ_DEC_LEN(&ifp->if_snd); 479 | 480.Ed 481Some drivers instruct the hardware to invoke transmission complete 482interrupts only when it thinks necessary. Rate-limiting breaks its assumption. 483.Ss How to convert drivers using multiple ifqueues 484Some (pseudo) devices (such as slip) have another 485.Dv ifqueue 486to prioritize packets. It is possible to eliminate the second queue 487since ALTQ provides more flexible mechanisms but the following shows 488how to keep the original behavior. 489.Bd -literal 490struct sl_softc { 491 struct ifnet sc_if; /* network-visible interface */ 492 ... 493 struct ifqueue sc_fastq; /* interactive output queue */ 494 ... 495}; 496.Ed 497The driver doesn't compile in the new model since it has the following 498line 499.Po 500.Fa if_snd 501is no longer a type of 502.Dv struct ifqueue 503.Pc . 504.Bd -literal 505 struct ifqueue *ifq = &ifp->if_snd; 506.Ed 507A simple way is to use the original 508.Fn IF_XXX 509macros for 510.Fa sc_fastq 511and use the new 512.Fn IFQ_XXX 513macros for 514.Fa if_snd . 515The enqueue operation looks like: 516.Bd -literal 517 ##old-style## ##new-style## 518 | 519 struct ifqueue *ifq = &ifp->if_snd; | struct ifqueue *ifq = NULL; 520 | 521 if (ip->ip_tos & IPTOS_LOWDELAY) | if ((ip->ip_tos & IPTOS_LOWDELAY) && 522 ifq = &sc->sc_fastq; | !ALTQ_IS_ENABLED(&sc->sc_if.if_snd)) { 523 | ifq = &sc->sc_fastq; 524 if (IF_QFULL(ifq)) { | if (IF_QFULL(ifq)) { 525 IF_DROP(ifq); | IF_DROP(ifq); 526 m_freem(m); | m_freem(m); 527 splx(s); | error = ENOBUFS; 528 sc->sc_if.if_oerrors++; | } else { 529 return (ENOBUFS); | IF_ENQUEUE(ifq, m); 530 } | error = 0; 531 IF_ENQUEUE(ifq, m); | } 532 | } else 533 | IFQ_ENQUEUE(&sc->sc_if.if_snd, 534 | m, error); 535 | 536 | if (error) { 537 | splx(s); 538 | sc->sc_if.if_oerrors++; 539 | return (error); 540 | } 541 if ((sc->sc_oqlen = | if ((sc->sc_oqlen = 542 sc->sc_ttyp->t_outq.c_cc) == 0) | sc->sc_ttyp->t_outq.c_cc) == 0) 543 slstart(sc->sc_ttyp); | slstart(sc->sc_ttyp); 544 splx(s); | splx(s); 545 | 546.Ed 547The dequeue operations looks like: 548.Bd -literal 549 ##old-style## ##new-style## 550 | 551 s = splimp(); | s = splimp(); 552 IF_DEQUEUE(&sc->sc_fastq, m); | IF_DEQUEUE(&sc->sc_fastq, m); 553 if (m == NULL) | if (m == NULL) 554 IF_DEQUEUE(&sc->sc_if.if_snd, m); | IFQ_DEQUEUE(&sc->sc_if.if_snd, m); 555 splx(s); | splx(s); 556 | 557.Ed 558.Sh QUEUEING DISCIPLINES 559Queueing disciplines need to maintain 560.Fa ifq_len 561.Po 562used by 563.Fn IFQ_IS_EMPTY 564.Pc . 565Queueing disciplines also need to guarantee the same mbuf is returned if 566.Fn IFQ_DEQUEUE 567is called immediately after 568.Fn IFQ_POLL . 569.Sh SEE ALSO 570.Xr altq.conf 5 , 571.Xr altqd 8 , 572.Xr tbrconfig 8 573.Sh HISTORY 574The 575.Nm 576system first appeared in March 1997. 577