diff --git a/acl.c b/acl.c index 2b4e384715b50f527aa6d48ac2ac7809359b6f89..a391e5743829bf6871fe9e0063fa5c7ca0bf316e 100644 --- a/acl.c +++ b/acl.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 1999 - 2005, Digium, Inc. + * Copyright (C) 1999 - 2006, Digium, Inc. * * Mark Spencer <markster@digium.com> * @@ -252,12 +252,55 @@ int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *se return 0; } -int ast_str2tos(const char *value, int *tos) +struct dscp_codepoint { + char *name; + unsigned int space; +}; + +/* IANA registered DSCP codepoints */ + +static const struct dscp_codepoint dscp_pool1[] = { + { "CS0", 0x00 }, + { "CS1", 0x08 }, + { "CS2", 0x10 }, + { "CS3", 0x18 }, + { "CS4", 0x20 }, + { "CS5", 0x28 }, + { "CS6", 0x30 }, + { "CS7", 0x38 }, + { "AF11", 0x0A }, + { "AF12", 0x0C }, + { "AF13", 0x0E }, + { "AF21", 0x12 }, + { "AF22", 0x14 }, + { "AF23", 0x16 }, + { "AF31", 0x1A }, + { "AF32", 0x1C }, + { "AF33", 0x1E }, + { "AF41", 0x22 }, + { "AF42", 0x24 }, + { "AF43", 0x26 }, + { "EF", 0x2E }, +}; + +int ast_str2tos(const char *value, unsigned int *tos) { int fval; - if (sscanf(value, "%i", &fval) == 1) - *tos = fval & 0xff; - else if (!strcasecmp(value, "lowdelay")) + unsigned int x; + + if (sscanf(value, "%i", &fval) == 1) { + *tos = fval & 0xFF; + return 0; + } + + for (x = 0; x < sizeof(dscp_pool1) / sizeof(dscp_pool1[0]); x++) { + if (!strcasecmp(value, dscp_pool1[x].name)) { + *tos = dscp_pool1[x].space << 2; + return 0; + } + } + + if (!strcasecmp(value, "lowdelay")) *tos = IPTOS_LOWDELAY; else if (!strcasecmp(value, "throughput")) *tos = IPTOS_THROUGHPUT; @@ -269,9 +312,37 @@ int ast_str2tos(const char *value, int *tos) *tos = 0; else return -1; + + ast_log(LOG_WARNING, "tos value %s is deprecated. See doc/iptos.txt for more information.", value); + return 0; } +const char *ast_tos2str(unsigned int tos) +{ + unsigned int x; + + switch (tos) { + case 0: + return "none"; + case IPTOS_LOWDELAY: + return "lowdelay"; + case IPTOS_THROUGHPUT: + return "throughput"; + case IPTOS_RELIABILITY: + return "reliability"; + case IPTOS_MINCOST: + return "mincost"; + default: + for (x = 0; x < sizeof(dscp_pool1) / sizeof(dscp_pool1[0]); x++) { + if (dscp_pool1[x].space == (tos >> 2)) + return dscp_pool1[x].name; + } + } + + return "unknown"; +} + int ast_get_ip(struct sockaddr_in *sin, const char *value) { return ast_get_ip_or_srv(sin, value, NULL); diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 0078202fa4465683605236c577bbe2422c1488a4..054582d95c501e3eb3522c49819e9797caf8a63c 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -9040,7 +9040,7 @@ static int set_config(char *config_file, int reload) tosval = ast_variable_retrieve(cfg, "general", "tos"); if (tosval) { if (ast_str2tos(tosval, &tos)) - ast_log(LOG_WARNING, "Invalid tos value, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n"); + ast_log(LOG_WARNING, "Invalid tos value, see doc/iptos.txt for more information.\n"); } while(v) { if (!strcasecmp(v->name, "bindport")){ @@ -9190,7 +9190,7 @@ static int set_config(char *config_file, int reload) ast_context_create(NULL, regcontext, "IAX2"); } else if (!strcasecmp(v->name, "tos")) { if (ast_str2tos(v->value, &tos)) - ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno); + ast_log(LOG_WARNING, "Invalid tos value at line %d, see doc/iptos.txt for more information.'\n", v->lineno); } else if (!strcasecmp(v->name, "accountcode")) { ast_copy_string(accountcode, v->value, sizeof(accountcode)); } else if (!strcasecmp(v->name, "amaflags")) { diff --git a/channels/chan_sip.c b/channels/chan_sip.c index c3b7f9e2cf35a87124375f165c6f125a9503912f..89b6ab9ac68550f5d70c71a215450a5f2afcf47a 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -364,7 +364,9 @@ static const struct cfsip_options { #define DEFAULT_ALLOWGUEST TRUE #define DEFAULT_SRVLOOKUP FALSE /*!< Recommended setting is ON */ #define DEFAULT_COMPACTHEADERS FALSE -#define DEFAULT_TOS FALSE +#define DEFAULT_TOS_SIP 0 /*!< Call signalling packets should be marked as DSCP CS3, but the default is 0 to be compatible with previous versions. */ +#define DEFAULT_TOS_AUDIO 0 /*!< Audio packets should be marked as DSCP EF (Expedited Forwarding), but the default is 0 to be compatible with previous versions. */ +#define DEFAULT_TOS_VIDEO 0 /*!< Video packets should be marked as DSCP AF41, but the default is 0 to be compatible with previous versions. */ #define DEFAULT_ALLOW_EXT_DOM TRUE #define DEFAULT_REALM "asterisk" #define DEFAULT_NOTIFYRINGING TRUE @@ -408,7 +410,9 @@ static int global_allowguest; /*!< allow unauthenticated users/peers to connect static int global_allowsubscribe; /*!< Flag for disabling ALL subscriptions, this is FALSE only if all peers are FALSE the global setting is in globals_flag_page2 */ static int global_mwitime; /*!< Time between MWI checks for peers */ -static int global_tos; /*!< IP Type of service */ +static int global_tos_sip; /*!< IP type of service for SIP packets */ +static int global_tos_audio; /*!< IP type of service for audio RTP packets */ +static int global_tos_video; /*!< IP type of service for video RTP packets */ static int compactheaders; /*!< send compact sip headers */ static int recordhistory; /*!< Record SIP history. Off by default */ static int dumphistory; /*!< Dump history to verbose before destroying SIP dialog */ @@ -3274,9 +3278,9 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si free(p); return NULL; } - ast_rtp_settos(p->rtp, global_tos); + ast_rtp_settos(p->rtp, global_tos_audio); if (p->vrtp) - ast_rtp_settos(p->vrtp, global_tos); + ast_rtp_settos(p->vrtp, global_tos_video); p->rtptimeout = global_rtptimeout; p->rtpholdtimeout = global_rtpholdtimeout; p->rtpkeepalive = global_rtpkeepalive; @@ -8449,7 +8453,9 @@ static int sip_show_settings(int fd, int argc, char *argv[]) ast_cli(fd, " From: Domain: %s\n", default_fromdomain); ast_cli(fd, " Record SIP history: %s\n", recordhistory ? "On" : "Off"); ast_cli(fd, " Call Events: %s\n", global_callevents ? "On" : "Off"); - ast_cli(fd, " IP ToS: 0x%x\n", global_tos); + ast_cli(fd, " IP ToS SIP: %s\n", ast_tos2str(global_tos_sip)); + ast_cli(fd, " IP ToS RTP audio: %s\n", ast_tos2str(global_tos_audio)); + ast_cli(fd, " IP ToS RTP video: %s\n", ast_tos2str(global_tos_video)); #ifdef OSP_SUPPORT ast_cli(fd, " OSP Support: Yes\n"); #else @@ -12559,6 +12565,7 @@ static int reload_config(enum channelreloadreason reason) int auto_sip_domains = FALSE; struct sockaddr_in old_bindaddr = bindaddr; int registry_count = 0, peer_count = 0, user_count = 0; + int temp_tos = 0; struct ast_flags debugflag = {0}; cfg = ast_config_load(config); @@ -12585,7 +12592,9 @@ static int reload_config(enum channelreloadreason reason) outboundproxyip.sin_family = AF_INET; /* Type of address: IPv4 */ ourport = DEFAULT_SIP_PORT; srvlookup = DEFAULT_SRVLOOKUP; - global_tos = DEFAULT_TOS; + global_tos_sip = DEFAULT_TOS_SIP; + global_tos_audio = DEFAULT_TOS_AUDIO; + global_tos_video = DEFAULT_TOS_VIDEO; externhost[0] = '\0'; /* External host name (for behind NAT DynDNS support) */ externexpire = 0; /* Expiration for DNS re-issuing */ externrefresh = 10; @@ -12808,8 +12817,22 @@ static int reload_config(enum channelreloadreason reason) if (sip_register(v->value, v->lineno) == 0) registry_count++; } else if (!strcasecmp(v->name, "tos")) { - if (ast_str2tos(v->value, &global_tos)) - ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno); + if (!ast_str2tos(v->value, &temp_tos)) { + global_tos_sip = temp_tos; + global_tos_audio = temp_tos; + global_tos_video = temp_tos; + ast_log(LOG_WARNING, "tos value at line %d is deprecated. See doc/iptos.txt for more information.", v->lineno); + } else + ast_log(LOG_WARNING, "Invalid tos value at line %d, See doc/iptos.txt for more information.\n", v->lineno); + } else if (!strcasecmp(v->name, "tos_sip")) { + if (ast_str2tos(v->value, &global_tos_sip)) + ast_log(LOG_WARNING, "Invalid tos_sip value at line %d, recommended value is 'cs3'. See doc/iptos.txt.\n", v->lineno); + } else if (!strcasecmp(v->name, "tos_audio")) { + if (ast_str2tos(v->value, &global_tos_audio)) + ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, recommended value is 'ef'. See doc/iptos.txt.\n", v->lineno); + } else if (!strcasecmp(v->name, "tos_video")) { + if (ast_str2tos(v->value, &global_tos_video)) + ast_log(LOG_WARNING, "Invalid tos_video value at line %d, recommended value is 'af41'. See doc/iptos.txt.\n", v->lineno); } else if (!strcasecmp(v->name, "bindport")) { if (sscanf(v->value, "%d", &ourport) == 1) { bindaddr.sin_port = htons(ourport); @@ -12922,10 +12945,10 @@ static int reload_config(enum channelreloadreason reason) if (option_verbose > 1) { ast_verbose(VERBOSE_PREFIX_2 "SIP Listening on %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port)); - ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", global_tos); + ast_verbose(VERBOSE_PREFIX_2 "Using SIP TOS: %s\n", ast_tos2str(global_tos_sip)); } - if (setsockopt(sipsock, IPPROTO_IP, IP_TOS, &global_tos, sizeof(global_tos))) - ast_log(LOG_WARNING, "Unable to set TOS to %d\n", global_tos); + if (setsockopt(sipsock, IPPROTO_IP, IP_TOS, &global_tos_sip, sizeof(global_tos_sip))) + ast_log(LOG_WARNING, "Unable to set SIP TOS to %s\n", ast_tos2str(global_tos_sip)); } } } diff --git a/channels/iax2-provision.c b/channels/iax2-provision.c index 990c0f0022261d8bbb42df1586bdba5e27ee29ef..da43dc4e6b51e309297515f6c35dd599bbe714aa 100644 --- a/channels/iax2-provision.c +++ b/channels/iax2-provision.c @@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/md5.h" #include "asterisk/astdb.h" #include "asterisk/utils.h" +#include "asterisk/acl.h" #include "iax2.h" #include "iax2-provision.h" #include "iax2-parser.h" @@ -328,20 +329,8 @@ static int iax_template_parse(struct iax_template *cur, struct ast_config *cfg, } else ast_log(LOG_WARNING, "Ignoring invalid codec '%s' for '%s' at line %d\n", v->value, s, v->lineno); } else if (!strcasecmp(v->name, "tos")) { - if (sscanf(v->value, "%d", &x) == 1) - cur->tos = x & 0xff; - else if (!strcasecmp(v->value, "lowdelay")) - cur->tos = IPTOS_LOWDELAY; - else if (!strcasecmp(v->value, "throughput")) - cur->tos = IPTOS_THROUGHPUT; - else if (!strcasecmp(v->value, "reliability")) - cur->tos = IPTOS_RELIABILITY; - else if (!strcasecmp(v->value, "mincost")) - cur->tos = IPTOS_MINCOST; - else if (!strcasecmp(v->value, "none")) - cur->tos = 0; - else - ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno); + if (ast_str2tos(v->value, &cur->tos)) + ast_log(LOG_WARNING, "Invalid tos value at line %d, see doc/iptos.txt for more information.\n", v->lineno); } else if (!strcasecmp(v->name, "user")) { strncpy(cur->user, v->value, sizeof(cur->user) - 1); if (strcmp(cur->user, v->value)) @@ -453,7 +442,7 @@ static int iax_show_provisioning(int fd, int argc, char *argv[]) ast_cli(fd, "Alternate: %s\n", iax_server(iabuf, sizeof(iabuf), cur->altserver)); ast_cli(fd, "Flags: %s\n", iax_provflags2str(iabuf, sizeof(iabuf), cur->flags)); ast_cli(fd, "Format: %s\n", ast_getformatname(cur->format)); - ast_cli(fd, "TOS: %d\n", cur->tos); + ast_cli(fd, "TOS: 0x%x\n", cur->tos); found++; } } diff --git a/configs/iax.conf.sample b/configs/iax.conf.sample index 20db97ad2306e3f6255370b8f6ea193f7143bdfd..55b024c69ce7a05a787759a8a76ecd6070797ae8 100644 --- a/configs/iax.conf.sample +++ b/configs/iax.conf.sample @@ -207,15 +207,8 @@ forcejitterbuffer=no ; ;authdebug=no ; -; Finally, you can set values for your TOS bits to help improve -; performance. Valid values are: -; lowdelay -- Minimize delay -; throughput -- Maximize throughput -; reliability -- Maximize reliability -; mincost -- Minimize cost -; none -- No flags -; -tos=lowdelay +; See doc/README.tos for a description of the tos parameters. +;tos=ef ; ; If regcontext is specified, Asterisk will dynamically create and destroy ; a NoOp priority 1 extension for a given peer who registers or unregisters diff --git a/configs/iaxprov.conf.sample b/configs/iaxprov.conf.sample index ad13166ed003de34d9a31ed0e38669072e624478..1644356d0f462ea2ae413056a388b140007d8dd0 100644 --- a/configs/iaxprov.conf.sample +++ b/configs/iaxprov.conf.sample @@ -53,10 +53,8 @@ codec=ulaw ; flags=register,heartbeat ; -; tos is the requested type of service setting and may be one a number or -; 'lowdelay','throughput','reliability','mincost' or 'none' -; -tos=lowdelay +; See doc/README.tos for a description of this parameter. +;tos=ef ; ; Example iaxy provisioning ; diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index 3a1208eadeb699998d06a9282992d522ac9a549a..5a7e483ed301d946e19ecd78b69f3038ef6cb2ed 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -58,8 +58,12 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ;pedantic=yes ; Enable slow, pedantic checking for Pingtel ; and multiline formatted headers for strict ; SIP compatibility (defaults to "no") -;tos=184 ; Set IP QoS to either a keyword or numeric val -;tos=lowdelay ; lowdelay,throughput,reliability,mincost,none + +; See doc/README.tos for a description of these parameters. +;tos_sip=cs3 ; Sets TOS for SIP packets. +;tos_audio=ef ; Sets TOS for RTP audio packets. +;tos_video=af41 ; Sets TOS for RTP video packets. + ;maxexpiry=3600 ; Max length of incoming registrations/subscriptions we allow (seconds) ;minexpiry=60 ; Minimum length of registrations/subscriptions (default 60) ;defaultexpiry=120 ; Default length of incoming/outoing registration diff --git a/doc/ip-tos.txt b/doc/ip-tos.txt new file mode 100644 index 0000000000000000000000000000000000000000..bac457e333dbb1067740b5403d17565a2b93913b --- /dev/null +++ b/doc/ip-tos.txt @@ -0,0 +1,63 @@ +IP Type of Service settings for VoIP channels +--------------------------------------------- + +Asterisk can set the Type of Service (TOS) byte on outgoing IP packets +for various protocols. The TOS byte is used by the network to provide +some level of Quality of Service (QoS) even if the network is +congested with other traffic. For more information on Quality of +Service for VoIP networks see the "Enterprise QoS Solution Reference +Network Design Guide" version 3.3 from Cisco at: + +<http://www.cisco.com/application/pdf/en/us/guest/netsol/ns432/c649/ccmigration_09186a008049b062.pdf> + +In sip.conf, there are three parameters that control the TOS settings: +tos_sip, tos_audio, and tos_video. tos_sip controls what TOS SIP call +signalling packets are set to. tos_audio controls what TOS RTP audio +packets are set to. tos_video controls what TOS RTP video packets are +set to. There is a "tos" parameter that is supported for backwards +compatibility. The tos parameter should be avoided in sip.conf +because it sets all three tos settings in sip.conf to the same value. + +In iax.conf, there is a tos parameter that sets the global default TOS +for IAX packets generated by chan_iax2. Since IAX connections combine +signalling, audio, and video into one UDP stream, it is not possible +to set the TOS separately for the different types of traffic. + +In iaxprov.conf, there is a tos parameter that tells the IAXy what TOS +to set on packets it generates. As with the parameter in iax.conf, +IAX packets generated by an IAXy cannot have different TOS settings +based upon the type of packet. However different IAXy devices can +have different TOS settings. + +The allowable values for any of the tos* parameters are: + +be (best effort), cs1, af11, af12, af13, cs2, af21, af22, af23, cs3, +af31, af32, af33, cs4, af41, af42, af42, ef (expedited forwarding), +lowdelay, throughput, reliability, mincost, none + +The tos* parameters also take numeric values. + +The lowdelay, throughput, reliability, mincost, and none values are +deprecated because they set the IP TOS using the outdated "IP +prececence" model as defined in RFC 791 and RFC 1349. + +=========================================== +Configuation Parameter Recommended +File Setting +------------------------------------------- +sip.conf tos_sip cs3 +sip.conf tos_audio ef +sip.conf tos_video af41 +------------------------------------------- +iax.conf tos ef +------------------------------------------- +iaxprov.conf tos ef +=========================================== + +To get the most out of setting the TOS on packets generated by +Asterisk, you will need to ensure that your network handles packets +with a TOS properly. For Cisco devices, see the previously mentioned +"Enterprise QoS Solution Reference Network Design Guide". For Linux +systems see the "Linux Advanced Routing & Traffic Control HOWTO" at +<http://www.lartc.org/>. + diff --git a/include/asterisk/acl.h b/include/asterisk/acl.h index ad946d57eb68407e2a027683a8a2077c12bbab25..f9114ce11a6345fe66a1f58460f2e7ec39fbed55 100644 --- a/include/asterisk/acl.h +++ b/include/asterisk/acl.h @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 1999 - 2005, Digium, Inc. + * Copyright (C) 1999 - 2006, Digium, Inc. * * Mark Spencer <markster@digium.com> * @@ -38,16 +38,17 @@ extern "C" { struct ast_ha; -extern void ast_free_ha(struct ast_ha *ha); -extern struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path); -extern int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin); -extern int ast_get_ip(struct sockaddr_in *sin, const char *value); -extern int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service); -extern int ast_ouraddrfor(struct in_addr *them, struct in_addr *us); -extern int ast_lookup_iface(char *iface, struct in_addr *address); -extern struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original); -extern int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr); -extern int ast_str2tos(const char *value, int *tos); +void ast_free_ha(struct ast_ha *ha); +struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path); +int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin); +int ast_get_ip(struct sockaddr_in *sin, const char *value); +int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service); +int ast_ouraddrfor(struct in_addr *them, struct in_addr *us); +int ast_lookup_iface(char *iface, struct in_addr *address); +struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original); +int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr); +int ast_str2tos(const char *value, unsigned int *tos); +const char *ast_tos2str(unsigned int tos); #if defined(__cplusplus) || defined(c_plusplus) }