1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/atomic.h> 31 #include <netinet/in.h> 32 #include <netinet/ip6.h> 33 #include <inet/common.h> 34 #include <inet/ip.h> 35 #include <inet/ip6.h> 36 #include <ipp/dscpmk/dscpmk_impl.h> 37 38 /* Module to mark the ToS/DS field for a given packet */ 39 40 /* Debug level */ 41 int dscpmk_debug = 0; 42 43 /* 44 * Given a packet, this routine marks the ToS or DSCP for IPv4 and IPv6 resp. 45 * using the configured dscp_map. 46 * Note that this module does not change the ECN bits. 47 */ 48 int 49 dscpmk_process(mblk_t **mpp, dscpmk_data_t *dscpmk_data, ip_proc_t proc) 50 { 51 ipha_t *ipha; 52 ip6_t *ip6_hdr; 53 boolean_t is_v4; 54 uint8_t dscp, new_dscp; 55 mblk_t *mp; 56 57 ASSERT((mpp != NULL) && (*mpp != NULL)); 58 mp = *mpp; 59 60 /* 61 * The action module will receive an M_DATA or an M_CTL followed 62 * by an M_DATA. In the latter case skip the M_CTL. 63 */ 64 if (mp->b_datap->db_type != M_DATA) { 65 if ((mp->b_cont != NULL) && 66 (mp->b_cont->b_datap->db_type == M_DATA)) { 67 mp = mp->b_cont; 68 } else { 69 dscpmk0dbg(("dscpmk_process: no data\n")); 70 atomic_add_64(&dscpmk_data->epackets, 1); 71 return (EINVAL); 72 } 73 } 74 75 /* Pull-up needed? */ 76 if ((mp->b_wptr - mp->b_rptr) < IP_SIMPLE_HDR_LENGTH) { 77 if (!pullupmsg(mp, IP_SIMPLE_HDR_LENGTH)) { 78 dscpmk0dbg(("dscpmk_process: pullup failed\n")); 79 atomic_add_64(&dscpmk_data->epackets, 1); 80 return (EINVAL); 81 } 82 } 83 ipha = (ipha_t *)mp->b_rptr; 84 85 /* Update global stats */ 86 atomic_add_64(&dscpmk_data->npackets, 1); 87 88 /* 89 * This should only be called for outgoing packets. For inbound packets 90 * proceed with the next action. 91 */ 92 if ((proc == IPP_LOCAL_IN) || (proc == IPP_FWD_IN)) { 93 dscpmk2dbg(("dscpmk_process: cannot mark incoming packets\n")); 94 atomic_add_64(&dscpmk_data->ipackets, 1); 95 return (0); 96 } 97 98 /* Figure out the ToS or the Traffic Class from the message */ 99 if (IPH_HDR_VERSION(ipha) == IPV4_VERSION) { 100 dscp = ipha->ipha_type_of_service; 101 is_v4 = B_TRUE; 102 } else { 103 ip6_hdr = (ip6_t *)mp->b_rptr; 104 dscp = __IPV6_TCLASS_FROM_FLOW(ip6_hdr->ip6_vcf); 105 is_v4 = B_FALSE; 106 } 107 108 /* 109 * Select the new dscp from the dscp_map after ignoring the 110 * ECN/CU from dscp (hence dscp >> 2). new_dscp will be the 111 * 6-bit DSCP value. 112 */ 113 new_dscp = dscpmk_data->dscp_map[dscp >> 2]; 114 115 /* Update stats for this new_dscp */ 116 atomic_add_64(&dscpmk_data->dscp_stats[new_dscp].npackets, 1); 117 118 /* 119 * if new_dscp is same as the original, update stats and 120 * return. 121 */ 122 if (new_dscp == (dscp >> 2)) { 123 atomic_add_64(&dscpmk_data->unchanged, 1); 124 return (0); 125 } 126 127 /* Get back the ECN/CU value from the original dscp */ 128 new_dscp = (new_dscp << 2) | (dscp & 0x3); 129 130 atomic_add_64(&dscpmk_data->changed, 1); 131 /* 132 * IPv4 : ToS structure -- RFC 791 133 * 134 * 0 1 2 3 4 5 6 7 135 * +---+---+---+---+---+---+---+---+ 136 * | IP Precd | D | T | R | 0 | 0 | 137 * | | | | | | | 138 * +---+---+---+---+---+---+---+---+ 139 * 140 * For Backward Compatability the diff serv DSCP will be mapped 141 * to the 3-bits Precedence field. DTR is not supported. Thus, 142 * the following Class Seletor CodePoints are reserved from this 143 * purpose : xxx000; where x is 0 or 1 (note the last 2 bits are 144 * 00) -- see RFC 2474. 145 */ 146 147 if (is_v4) { 148 ipha->ipha_type_of_service = new_dscp; 149 ipha->ipha_hdr_checksum = 0; 150 ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 151 } 152 153 /* 154 * IPv6 : DSCP field structure is as given -- RFC 2474 155 * 156 * 0 1 2 3 4 5 6 7 157 * +---+---+---+---+---+---+---+---+ 158 * | DSCP | CU | 159 * | | | 160 * +---+---+---+---+---+---+---+---+ 161 * 162 * CU -- Currently Unused 163 */ 164 165 /* 166 * the 32 bit vcf consists of version (4 bits), Traffic class (8 bits) 167 * and flow id (20 bits). Need to take care of Big/Little-Endianess. 168 */ 169 else { 170 #ifdef _BIG_ENDIAN 171 ip6_hdr->ip6_vcf = (ip6_hdr->ip6_vcf & TCLASS_MASK) | 172 (new_dscp << 20); 173 #else 174 ip6_hdr->ip6_vcf = (ip6_hdr->ip6_vcf & TCLASS_MASK) | 175 ((new_dscp >> 4) | ((new_dscp << 12) & 0xF000)); 176 #endif 177 } 178 179 return (0); 180 } 181