2 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/types.h>
32 #include <sys/filedesc.h>
33 #include <sys/file_internal.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/errno.h>
38 #include <sys/protosw.h>
39 #include <sys/domain.h>
41 #include <sys/queue.h>
44 #include <net/route.h>
46 #include <netinet/in.h>
47 #include <netinet/in_var.h>
48 #include <netinet/in_pcb.h>
49 #include <netinet/ip.h>
50 #include <netinet/ip_var.h>
51 #include <netinet/ip6.h>
52 #include <netinet6/ip6_var.h>
53 #include <netinet/udp.h>
54 #include <netinet/udp_var.h>
55 #include <netinet/tcp.h>
56 #include <netinet/tcp_var.h>
57 #include <netinet/tcp_cc.h>
59 extern char *proc_name_address(void *p
);
61 static int tfp_count
= 0;
63 static TAILQ_HEAD(, tclass_for_proc
) tfp_head
=
64 TAILQ_HEAD_INITIALIZER(tfp_head
);
66 struct tclass_for_proc
{
67 TAILQ_ENTRY(tclass_for_proc
) tfp_link
;
70 char tfp_pname
[MAXCOMLEN
+ 1];
73 static int dscp_code_from_mbuf_tclass(mbuf_traffic_class_t
);
74 static int get_pid_tclass(struct so_tcdbg
*);
75 static int get_pname_tclass(struct so_tcdbg
*);
76 static int set_pid_tclass(struct so_tcdbg
*);
77 static int set_pname_tclass(struct so_tcdbg
*);
78 static int flush_pid_tclass(struct so_tcdbg
*);
79 static int purge_tclass_for_proc(void);
80 static int flush_tclass_for_proc(void);
81 static void so_set_lro(struct socket
*, int);
82 int get_tclass_for_curr_proc(int *);
84 static lck_grp_attr_t
*tclass_lck_grp_attr
= NULL
; /* mutex group attributes */
85 static lck_grp_t
*tclass_lck_grp
= NULL
; /* mutex group definition */
86 static lck_attr_t
*tclass_lck_attr
= NULL
; /* mutex attributes */
87 decl_lck_mtx_data(static, tclass_lock_data
);
88 static lck_mtx_t
*tclass_lock
= &tclass_lock_data
;
91 * Must be called with tclass_lock held
93 static struct tclass_for_proc
*
94 find_tfp_by_pid(pid_t pid
)
96 struct tclass_for_proc
*tfp
;
98 TAILQ_FOREACH(tfp
, &tfp_head
, tfp_link
) {
99 if (tfp
->tfp_pid
== pid
)
106 * Must be called with tclass_lock held
108 static struct tclass_for_proc
*
109 find_tfp_by_pname(const char *pname
)
111 struct tclass_for_proc
*tfp
;
113 TAILQ_FOREACH(tfp
, &tfp_head
, tfp_link
) {
114 if (strncmp(pname
, tfp
->tfp_pname
,
115 sizeof (tfp
->tfp_pname
)) == 0)
121 __private_extern__
int
122 get_tclass_for_curr_proc(int *sotc
)
124 struct tclass_for_proc
*tfp
= NULL
;
125 proc_t p
= current_proc(); /* Not ref counted */
126 pid_t pid
= proc_pid(p
);
127 char *pname
= proc_name_address(p
);
131 lck_mtx_lock(tclass_lock
);
133 TAILQ_FOREACH(tfp
, &tfp_head
, tfp_link
) {
134 if ((tfp
->tfp_pid
== pid
) || (tfp
->tfp_pid
== -1 &&
135 strncmp(pname
, tfp
->tfp_pname
,
136 sizeof (tfp
->tfp_pname
)) == 0)) {
137 *sotc
= tfp
->tfp_class
;
142 lck_mtx_unlock(tclass_lock
);
144 return ((tfp
== NULL
) ? 0 : 1);
148 * Purge entries with PIDs of exited processes
151 purge_tclass_for_proc(void)
154 struct tclass_for_proc
*tfp
, *tvar
;
156 lck_mtx_lock(tclass_lock
);
158 TAILQ_FOREACH_SAFE(tfp
, &tfp_head
, tfp_link
, tvar
) {
161 if (tfp
->tfp_pid
== -1)
163 if ((p
= proc_find(tfp
->tfp_pid
)) == NULL
) {
165 TAILQ_REMOVE(&tfp_head
, tfp
, tfp_link
);
173 lck_mtx_unlock(tclass_lock
);
180 * Must be called with tclass_lock held
183 free_tclass_for_proc(struct tclass_for_proc
*tfp
)
188 TAILQ_REMOVE(&tfp_head
, tfp
, tfp_link
);
196 flush_tclass_for_proc(void)
199 struct tclass_for_proc
*tfp
, *tvar
;
201 lck_mtx_lock(tclass_lock
);
203 TAILQ_FOREACH_SAFE(tfp
, &tfp_head
, tfp_link
, tvar
) {
204 free_tclass_for_proc(tfp
);
207 lck_mtx_unlock(tclass_lock
);
214 * Must be called with tclass_lock held
216 static struct tclass_for_proc
*
217 alloc_tclass_for_proc(pid_t pid
, const char *pname
)
219 struct tclass_for_proc
*tfp
;
221 if (pid
== -1 && pname
== NULL
)
224 tfp
= _MALLOC(sizeof (struct tclass_for_proc
), M_TEMP
, M_NOWAIT
|M_ZERO
);
230 * Add per pid entries before per proc name so we can find
231 * a specific instance of a process before the general name base entry.
234 TAILQ_INSERT_HEAD(&tfp_head
, tfp
, tfp_link
);
236 strlcpy(tfp
->tfp_pname
, pname
, sizeof (tfp
->tfp_pname
));
237 TAILQ_INSERT_TAIL(&tfp_head
, tfp
, tfp_link
);
246 * -1 for tclass means to remove the entry
249 set_pid_tclass(struct so_tcdbg
*so_tcdbg
)
253 struct filedesc
*fdp
;
255 struct tclass_for_proc
*tfp
;
257 pid_t pid
= so_tcdbg
->so_tcdbg_pid
;
258 int tclass
= so_tcdbg
->so_tcdbg_tclass
;
262 printf("%s proc_find(%d) failed\n", __func__
, pid
);
267 lck_mtx_lock(tclass_lock
);
269 tfp
= find_tfp_by_pid(pid
);
271 tfp
= alloc_tclass_for_proc(pid
, NULL
);
273 lck_mtx_unlock(tclass_lock
);
278 tfp
->tfp_class
= tclass
;
280 lck_mtx_unlock(tclass_lock
);
286 for (i
= 0; i
< fdp
->fd_nfiles
; i
++) {
289 fp
= fdp
->fd_ofiles
[i
];
291 (fdp
->fd_ofileflags
[i
] & UF_RESERVED
) != 0 ||
292 fp
->f_fglob
->fg_type
!= DTYPE_SOCKET
)
295 so
= (struct socket
*)fp
->f_fglob
->fg_data
;
296 if (so
->so_proto
->pr_domain
->dom_family
!= AF_INET
&&
297 so
->so_proto
->pr_domain
->dom_family
!= AF_INET6
)
301 error
= so_set_traffic_class(so
, tclass
);
303 printf("%s: so_set_traffic_class"
304 "(so=%p, fd=%d, tclass=%d) "
305 "failed %d\n", __func__
,
306 so
, i
, tclass
, error
);
310 socket_unlock(so
, 1);
325 set_pname_tclass(struct so_tcdbg
*so_tcdbg
)
328 struct tclass_for_proc
*tfp
;
330 lck_mtx_lock(tclass_lock
);
332 tfp
= find_tfp_by_pname(so_tcdbg
->so_tcdbg_pname
);
334 tfp
= alloc_tclass_for_proc(-1, so_tcdbg
->so_tcdbg_pname
);
336 lck_mtx_unlock(tclass_lock
);
341 tfp
->tfp_class
= so_tcdbg
->so_tcdbg_tclass
;
343 lck_mtx_unlock(tclass_lock
);
352 flush_pid_tclass(struct so_tcdbg
*so_tcdbg
)
354 pid_t pid
= so_tcdbg
->so_tcdbg_pid
;
355 int tclass
= so_tcdbg
->so_tcdbg_tclass
;
356 struct filedesc
*fdp
;
362 if (p
== PROC_NULL
) {
363 printf("%s proc_find(%d) failed\n", __func__
, pid
);
369 for (i
= 0; i
< fdp
->fd_nfiles
; i
++) {
373 fp
= fdp
->fd_ofiles
[i
];
375 (fdp
->fd_ofileflags
[i
] & UF_RESERVED
) != 0 ||
376 fp
->f_fglob
->fg_type
!= DTYPE_SOCKET
)
379 so
= (struct socket
*)fp
->f_fglob
->fg_data
;
380 error
= sock_setsockopt(so
, SOL_SOCKET
, SO_FLUSH
, &tclass
,
383 printf("%s: setsockopt(SO_FLUSH) (so=%p, fd=%d, "
384 "tclass=%d) failed %d\n", __func__
, so
, i
, tclass
,
400 get_pid_tclass(struct so_tcdbg
*so_tcdbg
)
404 struct tclass_for_proc
*tfp
;
405 pid_t pid
= so_tcdbg
->so_tcdbg_pid
;
407 so_tcdbg
->so_tcdbg_tclass
= -1; /* Means not set */
408 so_tcdbg
->so_tcdbg_opportunistic
= -1; /* Means not set */
412 printf("%s proc_find(%d) failed\n", __func__
, pid
);
417 lck_mtx_lock(tclass_lock
);
419 tfp
= find_tfp_by_pid(pid
);
421 so_tcdbg
->so_tcdbg_tclass
= tfp
->tfp_class
;
424 lck_mtx_unlock(tclass_lock
);
433 get_pname_tclass(struct so_tcdbg
*so_tcdbg
)
436 struct tclass_for_proc
*tfp
;
438 so_tcdbg
->so_tcdbg_tclass
= -1; /* Means not set */
439 so_tcdbg
->so_tcdbg_opportunistic
= -1; /* Means not set */
442 lck_mtx_lock(tclass_lock
);
444 tfp
= find_tfp_by_pname(so_tcdbg
->so_tcdbg_pname
);
446 so_tcdbg
->so_tcdbg_tclass
= tfp
->tfp_class
;
449 lck_mtx_unlock(tclass_lock
);
455 delete_tclass_for_pid_pname(struct so_tcdbg
*so_tcdbg
)
458 pid_t pid
= so_tcdbg
->so_tcdbg_pid
;
459 struct tclass_for_proc
*tfp
= NULL
;
461 lck_mtx_lock(tclass_lock
);
464 tfp
= find_tfp_by_pid(pid
);
466 tfp
= find_tfp_by_pname(so_tcdbg
->so_tcdbg_pname
);
469 free_tclass_for_proc(tfp
);
473 lck_mtx_unlock(tclass_lock
);
479 * Setting options requires privileges
481 __private_extern__
int
482 so_set_tcdbg(struct socket
*so
, struct so_tcdbg
*so_tcdbg
)
486 if ((so
->so_state
& SS_PRIV
) == 0)
489 socket_unlock(so
, 0);
491 switch (so_tcdbg
->so_tcdbg_cmd
) {
493 error
= set_pid_tclass(so_tcdbg
);
497 error
= set_pname_tclass(so_tcdbg
);
501 error
= purge_tclass_for_proc();
505 error
= flush_tclass_for_proc();
508 case SO_TCDBG_DELETE
:
509 error
= delete_tclass_for_pid_pname(so_tcdbg
);
512 case SO_TCDBG_TCFLUSH_PID
:
513 error
= flush_pid_tclass(so_tcdbg
);
527 * Not required to be privileged to get
529 __private_extern__
int
530 sogetopt_tcdbg(struct socket
*so
, struct sockopt
*sopt
)
533 struct so_tcdbg so_tcdbg
;
535 size_t len
= sopt
->sopt_valsize
;
537 error
= sooptcopyin(sopt
, &so_tcdbg
, sizeof (struct so_tcdbg
),
538 sizeof (struct so_tcdbg
));
542 sopt
->sopt_valsize
= len
;
544 socket_unlock(so
, 0);
546 switch (so_tcdbg
.so_tcdbg_cmd
) {
548 error
= get_pid_tclass(&so_tcdbg
);
552 error
= get_pname_tclass(&so_tcdbg
);
556 lck_mtx_lock(tclass_lock
);
557 so_tcdbg
.so_tcdbg_count
= tfp_count
;
558 lck_mtx_unlock(tclass_lock
);
561 case SO_TCDBG_LIST
: {
562 struct tclass_for_proc
*tfp
;
564 struct so_tcdbg
*ptr
;
566 lck_mtx_lock(tclass_lock
);
567 if ((alloc_count
= tfp_count
) == 0) {
568 lck_mtx_unlock(tclass_lock
);
572 len
= alloc_count
* sizeof (struct so_tcdbg
);
573 lck_mtx_unlock(tclass_lock
);
575 buf
= _MALLOC(len
, M_TEMP
, M_WAITOK
| M_ZERO
);
581 lck_mtx_lock(tclass_lock
);
583 ptr
= (struct so_tcdbg
*)buf
;
584 TAILQ_FOREACH(tfp
, &tfp_head
, tfp_link
) {
585 if (++n
> alloc_count
)
587 if (tfp
->tfp_pid
!= -1) {
588 ptr
->so_tcdbg_cmd
= SO_TCDBG_PID
;
589 ptr
->so_tcdbg_pid
= tfp
->tfp_pid
;
591 ptr
->so_tcdbg_cmd
= SO_TCDBG_PNAME
;
592 ptr
->so_tcdbg_pid
= -1;
593 strlcpy(ptr
->so_tcdbg_pname
,
595 sizeof (ptr
->so_tcdbg_pname
));
597 ptr
->so_tcdbg_tclass
= tfp
->tfp_class
;
601 lck_mtx_unlock(tclass_lock
);
614 error
= sooptcopyout(sopt
, &so_tcdbg
,
615 sizeof (struct so_tcdbg
));
617 error
= sooptcopyout(sopt
, buf
, len
);
625 __private_extern__
int
626 so_set_traffic_class(struct socket
*so
, int optval
)
630 if (optval
< SO_TC_BE
|| optval
> SO_TC_CTL
) {
644 if (!SO_VALID_TC(optval
))
650 int oldval
= so
->so_traffic_class
;
652 VERIFY(SO_VALID_TC(optval
));
653 so
->so_traffic_class
= optval
;
655 if ((INP_SOCKAF(so
) == AF_INET
||
656 INP_SOCKAF(so
) == AF_INET6
) &&
657 INP_SOCKTYPE(so
) == SOCK_STREAM
) {
658 set_tcp_stream_priority(so
);
660 /* Set/unset use of Large Receive Offload */
661 so_set_lro(so
, optval
);
664 if ((INP_SOCKAF(so
) == AF_INET
||
665 INP_SOCKAF(so
) == AF_INET6
) &&
666 optval
!= oldval
&& (optval
== SO_TC_BK_SYS
||
667 oldval
== SO_TC_BK_SYS
)) {
669 * If the app switches from BK_SYS to something
670 * else, resume the socket if it was suspended.
672 if (oldval
== SO_TC_BK_SYS
)
673 inp_reset_fc_state(so
->so_pcb
);
675 SOTHROTTLELOG(("throttle[%d]: so %p [%d,%d] "
676 "opportunistic %s\n", so
->last_pid
,
677 so
, INP_SOCKAF(so
), INP_SOCKTYPE(so
),
678 (optval
== SO_TC_BK_SYS
) ? "ON" : "OFF"));
685 __private_extern__
void
686 so_set_default_traffic_class(struct socket
*so
)
691 (INP_SOCKAF(so
) == AF_INET
|| INP_SOCKAF(so
) == AF_INET6
)) {
692 get_tclass_for_curr_proc(&sotc
);
695 so
->so_traffic_class
= (sotc
!= -1) ? sotc
: SO_TC_BE
;
698 __private_extern__
int
699 so_set_opportunistic(struct socket
*so
, int optval
)
701 return (so_set_traffic_class(so
, (optval
== 0) ?
702 SO_TC_BE
: SO_TC_BK_SYS
));
705 __private_extern__
int
706 so_get_opportunistic(struct socket
*so
)
708 return (so
->so_traffic_class
== SO_TC_BK_SYS
);
711 __private_extern__ mbuf_svc_class_t
712 mbuf_service_class_from_control(struct mbuf
*control
)
715 mbuf_svc_class_t msc
= MBUF_SC_UNSPEC
;
717 for (cm
= M_FIRST_CMSGHDR(control
); cm
!= NULL
;
718 cm
= M_NXT_CMSGHDR(control
, cm
)) {
721 if (cm
->cmsg_len
< sizeof (struct cmsghdr
))
724 if (cm
->cmsg_level
!= SOL_SOCKET
||
725 cm
->cmsg_type
!= SO_TRAFFIC_CLASS
)
727 if (cm
->cmsg_len
!= CMSG_LEN(sizeof (int)))
730 tc
= *(int *)(void *)CMSG_DATA(cm
);
732 if (MBUF_VALID_SC(msc
))
739 __private_extern__
int
740 dscp_code_from_mbuf_tclass(mbuf_traffic_class_t mtc
)
763 __private_extern__
void
764 so_recv_data_stat(struct socket
*so
, struct mbuf
*m
, size_t off
)
766 uint32_t sotc
= m_get_traffic_class(m
);
768 if (sotc
>= SO_TC_STATS_MAX
)
771 so
->so_tc_stats
[sotc
].rxpackets
+= 1;
772 so
->so_tc_stats
[sotc
].rxbytes
+=
773 ((m
->m_flags
& M_PKTHDR
) ? m
->m_pkthdr
.len
: 0) + off
;
776 __private_extern__
void
777 set_tcp_stream_priority(struct socket
*so
)
779 struct tcpcb
*tp
= intotcpcb(sotoinpcb(so
));
780 int old_cc
= tp
->tcp_cc_index
;
781 int recvbg
= IS_TCP_RECV_BG(so
);
784 * If the socket was marked as a background socket or if the
785 * traffic class is set to background with traffic class socket
786 * option then make both send and recv side of the stream to be
787 * background. The variable sotcdb which can be set with sysctl
788 * is used to disable these settings for testing.
790 if (soisthrottled(so
) || IS_SO_TC_BACKGROUND(so
->so_traffic_class
)) {
791 if ((sotcdb
& SOTCDB_NO_SENDTCPBG
) != 0) {
792 if (old_cc
== TCP_CC_ALGO_BACKGROUND_INDEX
)
793 tcp_set_foreground_cc(so
);
795 if (old_cc
!= TCP_CC_ALGO_BACKGROUND_INDEX
)
796 tcp_set_background_cc(so
);
799 /* Set receive side background flags */
800 if ((sotcdb
& SOTCDB_NO_RECVTCPBG
) != 0)
801 tcp_clear_recv_bg(so
);
805 tcp_clear_recv_bg(so
);
806 if (old_cc
== TCP_CC_ALGO_BACKGROUND_INDEX
)
807 tcp_set_foreground_cc(so
);
810 if (old_cc
!= tp
->tcp_cc_index
|| recvbg
!= IS_TCP_RECV_BG(so
)) {
811 SOTHROTTLELOG(("throttle[%d]: so %p [%d,%d] TCP %s send; "
812 "%s recv\n", so
->last_pid
, so
, INP_SOCKAF(so
),
814 (tp
->tcp_cc_index
== TCP_CC_ALGO_BACKGROUND_INDEX
) ?
815 "background" : "foreground",
816 IS_TCP_RECV_BG(so
) ? "background" : "foreground"));
821 * Set traffic class to an IPv4 or IPv6 packet
823 * - set the DSCP code following the WMM mapping
825 __private_extern__
void
826 set_packet_service_class(struct mbuf
*m
, struct socket
*so
,
827 mbuf_svc_class_t in_msc
, u_int32_t flags
)
829 mbuf_svc_class_t msc
= MBUF_SC_BE
; /* Best effort by default */
830 struct inpcb
*inp
= sotoinpcb(so
); /* in6pcb and inpcb are the same */
831 struct ip
*ip
= mtod(m
, struct ip
*);
833 struct ip6_hdr
*ip6
= mtod(m
, struct ip6_hdr
*);
835 int isipv6
= ((flags
& PKT_SCF_IPV6
) != 0) ? 1 : 0;
837 if (!(m
->m_flags
& M_PKTHDR
))
841 * Here is the precedence:
842 * 1) TRAFFIC_MGT_SO_BACKGROUND trumps all
843 * 2) Traffic class passed via ancillary data to sendmsdg(2)
844 * 3) Traffic class socket option last
846 if (in_msc
!= MBUF_SC_UNSPEC
) {
847 if (in_msc
>= MBUF_SC_BE
&& in_msc
<= MBUF_SC_CTL
)
850 VERIFY(SO_VALID_TC(so
->so_traffic_class
));
851 msc
= so_tc2msc(so
->so_traffic_class
);
852 /* Assert because tc must have been valid */
853 VERIFY(MBUF_VALID_SC(msc
));
857 * If TRAFFIC_MGT_SO_BACKGROUND is set, depress the priority.
859 if (soisthrottled(so
) && !IS_MBUF_SC_BACKGROUND(msc
))
863 * Set the traffic class in the mbuf packet header svc field
865 if (sotcdb
& SOTCDB_NO_MTC
)
868 /* Elevate service class if the packet is a pure TCP ACK.
869 * We can do this only when the flow is not a background
870 * flow and the outgoing interface supports
871 * transmit-start model.
873 if (!IS_MBUF_SC_BACKGROUND(msc
) && (flags
& PKT_SCF_TCP_ACK
))
876 (void) m_set_service_class(m
, msc
);
879 * Set the privileged traffic auxiliary flag if applicable, or clear it.
881 if (!(sotcdb
& SOTCDB_NO_PRIVILEGED
) && soisprivilegedtraffic(so
) &&
882 msc
!= MBUF_SC_UNSPEC
)
883 m
->m_pkthdr
.aux_flags
|= MAUXF_PRIO_PRIVILEGED
;
885 m
->m_pkthdr
.aux_flags
&= ~MAUXF_PRIO_PRIVILEGED
;
889 * Quick exit when best effort
891 if (msc
== MBUF_SC_BE
)
895 * The default behavior is for the networking stack to not set the
896 * DSCP code, based on SOTCDB_NO_DSCP being set. If the flag is
897 * cleared, set the DSCP code in IPv4 or IPv6 header only for local
898 * traffic, if it is not already set. <rdar://problem/11277343>
900 if (sotcdb
& SOTCDB_NO_DSCP
)
904 * Test if a IP TOS or IPV6 TCLASS has already been set
905 * on the socket or the raw packet.
907 if (!(sotcdb
& SOTCDB_NO_DSCPTST
)) {
910 if ((so
->so_type
== SOCK_RAW
&&
911 (ip6
->ip6_flow
& htonl(0xff << 20)) != 0) ||
912 (inp
->in6p_outputopts
&&
913 inp
->in6p_outputopts
->ip6po_tclass
!= -1))
917 if ((so
->so_type
== SOCK_RAW
&&
918 (inp
->inp_flags
& INP_HDRINCL
)) ||
919 inp
->inp_ip_tos
!= 0)
924 * Test if destination is local
926 if (!(sotcdb
& SOTCDB_NO_LCLTST
)) {
928 struct rtentry
*rt
= inp
->inp_route
.ro_rt
;
930 if (so
->so_type
== SOCK_STREAM
) {
931 if (intotcpcb(inp
)->t_flags
& TF_LOCAL
)
933 } else if (rt
!= NULL
&&
934 (rt
->rt_gateway
->sa_family
== AF_LINK
||
935 (rt
->rt_ifp
->if_flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
)))) {
936 if (!(rt
->rt_ifp
->if_flags
& IFF_POINTOPOINT
))
940 if (isipv6
&& in6addr_local(&ip6
->ip6_dst
)) {
944 if (inaddr_local(ip
->ip_dst
)) {
953 ip6
->ip6_flow
|= htonl(dscp_code_from_mbuf_tclass(
954 m_get_traffic_class(m
)) << 20);
957 ip
->ip_tos
|= dscp_code_from_mbuf_tclass(
958 m_get_traffic_class(m
)) << 2;
962 * For TCP with background traffic class switch CC algo based on sysctl
964 if (so
->so_type
== SOCK_STREAM
)
965 set_tcp_stream_priority(so
);
967 so_tc_update_stats(m
, so
, msc
);
970 __private_extern__
void
971 so_tc_update_stats(struct mbuf
*m
, struct socket
*so
, mbuf_svc_class_t msc
)
973 mbuf_traffic_class_t mtc
;
976 * Assume socket and mbuf traffic class values are the same
977 * Also assume the socket lock is held. Note that the stats
978 * at the socket layer are reduced down to the legacy traffic
979 * classes; we could/should potentially expand so_tc_stats[].
981 mtc
= MBUF_SC2TC(msc
);
982 VERIFY(mtc
< SO_TC_STATS_MAX
);
983 so
->so_tc_stats
[mtc
].txpackets
+= 1;
984 so
->so_tc_stats
[mtc
].txbytes
+= m
->m_pkthdr
.len
;
987 __private_extern__
void
988 socket_tclass_init(void)
990 tclass_lck_grp_attr
= lck_grp_attr_alloc_init();
991 tclass_lck_grp
= lck_grp_alloc_init("tclass", tclass_lck_grp_attr
);
992 tclass_lck_attr
= lck_attr_alloc_init();
993 lck_mtx_init(tclass_lock
, tclass_lck_grp
, tclass_lck_attr
);
996 __private_extern__ mbuf_svc_class_t
999 mbuf_svc_class_t msc
;
1003 msc
= MBUF_SC_BK_SYS
;
1037 msc
= MBUF_SC_UNSPEC
;
1044 __private_extern__
int
1045 so_svc2tc(mbuf_svc_class_t svc
)
1048 case MBUF_SC_UNSPEC
:
1050 case MBUF_SC_BK_SYS
:
1051 return SO_TC_BK_SYS
;
1076 * LRO is turned on for AV streaming and background classes.
1079 so_set_lro(struct socket
*so
, int optval
)
1081 if ((optval
== SO_TC_BK
) ||
1082 (optval
== SO_TC_BK_SYS
) ||
1083 (optval
== SO_TC_AV
)) {
1084 so
->so_flags
|= SOF_USELRO
;
1086 so
->so_flags
&= ~SOF_USELRO
;