Tuesday, 24 April 2012

Traffic Shaping vs. Traffic Policing


Traffic Shaping  vs. Traffic Policing
==========================

Why Traffic Policing and Traffic shaping are required?

In order to maintain QOS (quality of service) in network, these are required.  QOS means service provider agreed upon certain level of service to the customer.To achieve QOS, the service provider needs to manage the Traffic across the network.

Traffic shaping and Policing are required for managing the Traffic that exceeds the specific rate.

Traffic Shaping?

“Traffic shaping” just does the Rate Limiting. In other words, it delays traffic (some or all datagrams) to bring them into compliance with a desired traffic profile.
  
Traffic Shaping just delays the traffic by buffering, it stores the traffic in queues. Traffic shaping will not drop the packets.

Generally service providers often force the customer to adhere to a specific policy of service (or committed rate).This policy is referred to as the Service Level Agreement (SLA) between the customer and service provider. 
  
Shaping is usually implemented on the customer side, and will buffer traffic that exceeds the service provider’s committed rate.Buffering traffic will often create delay and jitter, which can negatively impact sensitive traffic types. Shaping also requires sufficient memory to queue buffered traffic.
  
Here router receives a traffic more than 128kbs date rate, then router needs to shape the traffic  to meet the end device traffic rate.Suppose if router receives 160 kbps of inbound traffic , but  outbound line rate is 128 kbps, in this case the router has to shape the traffic to compliance with the end router rate.
       
          

 Shaping can only occur on outbound traffic on an interface.

Configuring Traffic Shaping

Shaping is usually implemented on the customer side, and will buffer traffic that exceeds the provider’s committed rate.Shaping will thus slow the traffic rate and siphon out traffic in compliance with the provider’s SLA.

Cisco IOS devices support multiple methods of traffic shaping:

Generic Traffic Shaping (GTS) – implements shaping on a per Interface basis using the traffic-shape command.

Class-Based Shaping – implements shaping on a per-class basis using the shape command within a MQC policy-map.

Distributed Traffic Shaping (DTS) – offloads traffic shaping from the router processor to Versatile Interface Processors (VIPs).DTS is only available on high-end Cisco platforms.

Frame Relay Traffic Shaping (FRTS) – implements Frame-Relay specific shaping mechanisms, such as BECN or FECN. FRTS is only
available on a Frame-Relay interface or subinterface, and is covered extensively in the Frame-Relay guide.

To configure basic Generic Traffic Shaping (GTS):
Router(config)# interface serial0/0
Router(config-if)# traffic-shape rate 256000 64000 64000
The traffic-shape rate command is followed by three values, representing:
• The committed information rate (CIR)
• The normal burst rate (Bc)
• The excess burst rate (Be)

What is Traffic Policing?

Think of traffic policing as a bouncer guarding the door to a nightclub.
When the club is full, he denies entry and turns patrons away. This is similar to how policing works.

Packets are limited to a certain bandwidth, preventing the circuit from becoming congested.  Any traffic exceeding the specified rate limit is discarded.

Policing is usually implemented on the provider side, and will either drop or re-mark traffic that exceeds the provider’s committed rate. 

TCP traffic that is dropped will be forced to resend, which may result in TCP global synchronization or starvation issues. Policing can be implemented for both inbound and outbound traffic on an interface.

Transfer Rate – The Token Bucket System
Cisco describes the regulation of a transfer rate as a token bucket system, which is comprised of three parts:

Committed Information Rate (CIR) – specifies the traffic rate dictated by the SLA, measured in bits per second (bps).

Burst Rate (Bc) – specifies the amount of traffic to be sent within a given time interval, measured in bits.

Time Interval (Tc) – identifies the time interval for each burst, measured in seconds or sometimes milliseconds.

The CIR is calculated using the formula:
CIR (bps) = Bc (bits) / Tc (seconds)

With a token bucket system, the bucket is filled with tokens, and each token represents one byte. Thus, to transmit a 50-byte packet, the bucket must  contain a minimum of 50 tokens. Tokens are consumed as traffic is  transferred, and the bucket is refilled with tokens at the speed of the CIR. If the bucket is full, then excess tokens will spill out and are wasted.

The capacity of the bucket is defined by the burst rate. If the data (in bytes) to be transmitted is less than the number of tokens currently in the bucket, then the traffic is conforming to the policy and is (usually) forwarded.

If the data (in bytes) to be transmitted is more than the number of tokens currently in the bucket, then the traffic is exceeding the policy. This excess  traffic can be shaped (buffered) or policed (dropped or re-marked), depending on the configured policy.

The above describes a One Token Bucket system. Some SLA policies allow for bursts that are higher than the normal burst rate (Bc), during periods of non-congestion. This is referred to as the excess burst (Be) rate.

The excess burst rate is an optional configuration option, and is defined as a Two Token Bucket system. Excess tokens are not wasted, but are instead placed in an excess bucket. The capacity of this bucket is defined by the excess burst rate. Traffic that exceeds the normal token bucket can borrow tokens from the excess bucket – but will usually be dropped first during congestion. Traffic that exceeds the excess bucket is violating the policy.

Wednesday, 18 April 2012

Operating System FAQS

What is Re-entrant Function?

The term "re-entrant" means that it is safe to "re-enter" the function while it is already executed, typically in a concurrent environment.

In other words, when two tasks can execute the function at the same time without interfering with each other, then the function is re-entrant.

A function is not re-entrant when the execution by one task has an impact on the influence of another task. This typically is the case when a global state or data is used.

A function that uses only local variables and arguments is typically re-entrant.

Basic guidelines:
  • Do not access mutable global or function-static variables.
  • Do not self-modify code.
  • Do not invoke another function that is itself non-reentrant.
For example, the following function is not reentrant, because the observed value of the summation depends on when and where the function is interrupted (or, in the case of multithreading, how two or more threads race into the function):

1
2
3
4
5
6
static int sum = 0;

int increment(int i) {
  sum += i;
  return sum;
}

We can make this function reentrant by making the sum not a global variable and instead requiring the caller to maintain it:

1
2
3
int increment(int sum, int i) {
    return sum + i;
}
 



Returning data
Many non-reentrant functions return a pointer to static data. This can be avoided in the following ways:
  • Returning dynamically allocated data. In this case, it will be the caller's responsibility to free the storage. The benefit is that the interface does not need to be modified. However, backward compatibility is not ensured; existing single-threaded programs using the modified functions without changes would not free the storage, leading to memory leaks.
  • Using caller-provided storage. This method is recommended, although the interface must be modified.
For example, a strtoupper function, converting a string to uppercase, could be implemented as in the following code fragment:
/* non-reentrant function */
char *strtoupper(char *string)
{
        static char buffer[MAX_STRING_SIZE];
        int index;

        for (index = 0; string[index]; index++)
                buffer[index] = toupper(string[index]);
        buffer[index] = 0

        return buffer;
}

A better solution consists of modifying the interface. The caller must provide the storage for both input and output strings, as in the following code fragment:
/* reentrant function (a better solution) */
char *strtoupper_r(char *in_str, char *out_str)
{
        int index;

        for (index = 0; in_str[index]; index++)
        out_str[index] = toupper(in_str[index]);
        out_str[index] = 0

        return out_str;
}
The non-reentrant standard C library subroutines were made reentrant using caller-provided storage.
 
Making a function threadsafe
In multithreaded programs, all functions called by multiple threads must be threadsafe. However, a workaround exists for using thread-unsafe subroutines in multithreaded programs. Non-reentrant functions usually are thread-unsafe, but making them reentrant often makes them threadsafe, too.

Locking shared resources
Functions that use static data or any other shared resources, such as files or terminals, must serialize the access to these resources by locks in order to be threadsafe. For example, the following function is thread-unsafe: 
 
/* thread-unsafe function */
int increment_counter()
{
        static int counter = 0;

        counter++;
        return counter;
}
 
To be threadsafe, the static variable counter must be protected by a static lock, as in the following example:
/* pseudo-code threadsafe function */
int increment_counter();
{
        static int counter = 0;
        static lock_type counter_lock = LOCK_INITIALIZER;

        pthread_mutex_lock(counter_lock);
        counter++;
        pthread_mutex_unlock(counter_lock);
        return counter;
}

 

Writing reentrant and threadsafe code

In single-threaded processes, only one flow of control exists. The code executed by these processes thus need not be reentrant or threadsafe. In multithreaded programs, the same functions and the same resources may be accessed concurrently by several flows of control.

To protect resource integrity, code written for multithreaded programs must be reentrant and threadsafe.

Reentrance and thread safety are both related to the way that functions handle resources. Reentrance and thread safety are separate concepts: a function can be either reentrant, threadsafe, both, or neither.



Example 1: not thread-safe, not reentrant

/* As this function uses a non-const global variable without
   any precaution, it is neither reentrant nor thread-safe. */

int t;

void swap(int *x, int *y)
{
    t = *x;
    *x = *y;
    *y = t;
}

Example 2: thread-safe, not reentrant

/* We use a thread local variable: the function is now
   thread-safe but still not reentrant (within the
   same thread). */

__thread int t;

void swap(int *x, int *y)
{
    t = *x;
    *x = *y;
    *y = t;
}

Example 3: not thread-safe, reentrant

/* We save the global state in a local variable and we restore
   it at the end of the function.  The function is now reentrant
   but it is not thread safe. */

int t;

void swap(int *x, int *y)
{
    int s;
    s = t;
    t = *x;
    *x = *y;
    *y = t;
    t = s;
}

Example 4: thread-safe, reentrant

/* We use a local variable: the function is now
   thread-safe and reentrant, we have ascended to
   higher plane of existence.  */

void swap(int *x, int *y)
{
    int t;
    t = *x;
    *x = *y;
    *y = t;
}



What is Priority Inversion problem?

Before discussing about priority inversion problem, I would like to emphasize when this problem occur in  Real time operating system.

A real time system running with priority based scheduler,  if two tasks share the same resources( such as memory buffer) ,obviously one of the task have a HIGH priority.  The higher-priority task expects to be run as soon as it is ready.

However, if the lower-priority task is using their shared resource when the higher-priority task becomes ready to run,the higher-priority task must wait for the lower-priority task to finish with it. We say that the higher-priority task is pending on the resource.

The real trouble arises at run-time, when a medium-priority task preempts a lower-priority task using a shared resource on which the higher-priority task is pending.

If the higher-priority task is otherwise ready to run, but a medium-priority task is currently running instead, a priority inversion is said to occur.















Low-priority Task L and high-priority Task H share a resource.
Shortly after Task L takes the resource, Task H becomes ready to run.
However, Task H must wait for Task L to finish with the resource, so it pends. Before Task L finishes with the resource,Task M becomes ready to run, preempting Task L. 
While Task M (and perhaps additional intermediate-priority tasks) runs,
Task H, the highest-priority task in the system, remains in a pending state.

How to solve this problem?
The solution is Priority inheritance
The first is called priority inheritance. This technique mandates that a lower-priority task inherit the priority of any higher-priority task pending on a resource they share.
This priority change should take place as soon as the high-priority task begins to pend; it should end when the resource is released. This requires help from the operating system.