improve IP TOS support for SIP and IAX2 (issue #6355, code from jcollie plus modifica...
authorKevin P. Fleming <kpfleming@digium.com>
Tue, 28 Mar 2006 03:28:52 +0000 (03:28 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Tue, 28 Mar 2006 03:28:52 +0000 (03:28 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@15435 65c4cc65-6c06-0410-ace0-fbb531ad65f3

acl.c
channels/chan_iax2.c
channels/chan_sip.c
channels/iax2-provision.c
configs/iax.conf.sample
configs/iaxprov.conf.sample
configs/sip.conf.sample
doc/ip-tos.txt [new file with mode: 0644]
include/asterisk/acl.h

diff --git a/acl.c b/acl.c
index 2b4e384..a391e57 100644 (file)
--- 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);
index 0078202..054582d 100644 (file)
@@ -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")) {
index c3b7f9e..89b6ab9 100644 (file)
@@ -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));
                        }
                }
        }
index 990c0f0..da43dc4 100644 (file)
@@ -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++;
                }
        }
index 20db97a..55b024c 100644 (file)
@@ -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
index ad13166..1644356 100644 (file)
@@ -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
 ;
index 3a1208e..5a7e483 100644 (file)
@@ -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 (file)
index 0000000..bac457e
--- /dev/null
@@ -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/>.
+
index ad946d5..f9114ce 100644 (file)
@@ -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)
 }