Developers Club geek daily blog

1 year, 6 months ago
It would seem the things which are taken out in heading, are rather trivial and described in a set of places of a wide area network, but it only at first sight. Having tested the most often meeting councils I found several "reefs", blocks and even rocky educations.

But all this words, keep to the point.
Rather widespread situation — Asterisk in LKS, behind MikroTik router.
To select a server traffic where PBX is set, the administrator cuts off part of the canal of provider selecting it only for specific IP.
Or other implementation when the necessary traffic is determined not only by the IP address PBX, but also by the size of packets and the protocol.
Tried — works. It is possible to forget? Here not.

What if the administrator wants to merge something from the Internet being in a server konsolka, or on the contrary to send somewhere to the Internet a large number of traffic? Correctly — it is prioritized on MikroTik as well as a useful traffic from PBX that as a result will lead to problems with IP telephony.

The solution is old as IPv4 here — to mark a traffic on the server with Asterisk generated only by it and so that MikroTik could "see", otmatchit it (forgive for so rough anglicism) and to prioritize only it.

The following item we have a reservation of channels from two Internet service providers.
I think that the script from wiki — wiki.mikrotik.com/wiki/Failover_Scripting is familiar to each system administrator using MikroTik routers in the economy
It all is good, but as well as in the previous situation there is a row "but".
To the most powerful of them the name "Connection tracking" also consists it here in what:
when our main ISP desires to have a rest from works just, traffic switches to reserve.

All are seemingly happy, YouTube works, yap too, but how many we would not shout ekspekto potronum
sip reload

and in despair did not try to apply magic of the higher orders
core restart now

SIP registration do not rise.

And the matter is that in the Connection tracking mechanism records from a "old" (main) Internet channel remained to hang and they need to be deleted then registration will successfully rise and calls will begin to pass.

If it is interesting to you how to prove Mikrotik'U who after all a camel, and just as to automate in a script reset of "old" connections, then to you directly under kat.


Part 1. Correct prioritizing of VoIP of a traffic


From very garrulous introduction we will pass to practical part.
How to mark a traffic that this tag was recognized by MikroTik?
The answer is simple — DSCP!
OK and what into the account of a traffic of the specific demon, in this Asterisk couples?
And here without problems, the sir (madam) — iptables - uid-owner!

On the server with PBX we learn what user id from our Asterisk (an asterisk — it)
grep -i asterisk /etc/passwd|cut -d: -f3
1001


Also we will add the rule for the indication of DSCP value necessary to us (for a traffic of VoIP it is accepted to specify CS5, or, in the number format — 40)
the comment from ksg222
Would like to pay attention that "color" with usually voice traffic two DSCP values: CS5 (CS3 in case of Cisco) for signaling and EF for a RTP traffic. Certainly in your example it is not critical as you have in a configuration a main issue - it is to select a voice traffic among the others. Will not be all the same farther on the prioritizing Internet across the field of DSCP.

tools.ietf.org/html/rfc4594#section-2.3

www.cisco.com/c/en/us/td/docs/solutions/Enterprise/WAN_and_MAN/QoS_SRND/QoS-SRND-Book/QoSIntro.html#pgfId-46256


iptables -I OUTPUT 1 -t mangle -m owner --uid-owner 1001 -j DSCP --set-dscp 40

* for inquisitive — at the end of article I will be links where it is possible to learn from what I took it


Behind this on the server with IP automatic telephone exchange we will finish and we will pass to setup of a router.
I took this material as a basis — voxlink.ru/kb/voip-devices-configuration/mikrotik-voip-traffic-configuration
I will not begin to Repostit, there everything is well painted, I will show only listings.
Table MANGLE of a fayervoll:
/ip f m exp
# nov/26/2015 17:09:20 by RouterOS 6.21.1
# software id = 5QIF-MH9A
#
/ip firewall mangle
add action=mark-packet chain=forward new-packet-mark=def_out src-address=192.168.5.0/24
add action=mark-packet chain=forward new-packet-mark=def_out src-address=192.168.6.0/24
add action=mark-packet chain=forward dst-address=192.168.5.0/24 new-packet-mark=def_in
add action=mark-packet chain=forward dst-address=192.168.6.0/24 new-packet-mark=def_in
add action=mark-packet chain=forward dscp=40 new-packet-mark=voip_out src-address=192.168.7.10
add action=mark-packet chain=forward dscp=40 dst-address=192.168.7.10 new-packet-mark=voip_in

As well as it is described in the introduction — a match the necessary traffic on IP and across the field of DSCP.

And queues:
/queue tree export 
# nov/26/2015 17:09:27 by RouterOS 6.21.1
# software id = 5QIF-MH9A
#
/queue tree
add max-limit=30M name=in parent=global
add max-limit=28M name=def-in packet-mark=def_in parent=in
add limit-at=1M max-limit=2M name=voip-in packet-mark=voip_in parent=in priority=1
add max-limit=30M name=out parent=global
add max-limit=28M name=def-out packet-mark=def_out parent=out
add limit-at=1M max-limit=2M name=voip-out packet-mark=voip_out parent=out priority=1

By the way, the router already has to prioritize traffic with the great value of DSCP, but I after all separated for it a band in 2mb/page.

Part 2. Failover'a script


Let's begin from the very beginning, I will tell as I configured links of providers and routing.
There are two ISP, one is connected on ethernet, the second for PPPoE.
For descriptive reasons I will give listings. Ethernet connection:
[f@777777] > ip addr pr where interface=ether7
Flags: X - disabled, I - invalid, D - dynamic 
 #   ADDRESS            NETWORK         INTERFACE                                                                                         
 0   46.11.6.78/30    46.11.6.76    ether7       

PPPoE:
[f@777777] > int pppoe-cl pr 
Flags: X - disabled, R - running 
 0  R name="rtk" max-mtu=auto max-mru=auto mrru=disabled interface=ether8 user="f" password="w" profile=default 
      keepalive-timeout=60 service-name="" ac-name="" add-default-route=no dial-on-demand=no use-peer-dns=yes 
      allow=pap,chap,mschap1,mschap2 

notice — I do not add a route by default at an interface raising, it will be added manually, statically

routing setup goes the following stage
[f@777777] > ip r p d t
 0 A S  comment=RTK_TABLE dst-address=0.0.0.0/0 gateway=rtk gateway-status=rtk reachable distance=1 scope=30 target-scope=10 routing-mark=RTK_mark 
 1 A S  comment=GoodLine_TABLE dst-address=0.0.0.0/0 gateway=46.18.6.77 gateway-status=46.18.6.77 reachable via  ether7 distance=1 scope=30 target-scope=10 routing-mark=GoodLine_mark 
 2 A S  comment=MAIN_TABLE dst-address=0.0.0.0/0 gateway=46.18.6.77 gateway-status=46.18.6.77 reachable via  ether7 distance=1 scope=30 target-scope=10 
 3   S  comment=MAIN_TABLE dst-address=0.0.0.0/0 gateway=rtk gateway-status=rtk reachable distance=2 scope=30 target-scope=10 
 4 ADC  dst-address=10.155.177.1/32 pref-src=10.155.177.13 gateway=pptp-out1 gateway-status=pptp-out1 reachable distance=0 scope=10 
 5   S  dst-address=10.155.177.1/32 gateway=pptp-out1 gateway-status=pptp-out1 reachable distance=1 scope=30 target-scope=10 
 6 ADC  dst-address=46.18.6.76/30 pref-src=46.18.6.78 gateway=ether7 gateway-status=ether7 reachable distance=0 scope=10 
 7 ADC  dst-address=172.16.79.1/32 pref-src=172.16.79.251 gateway=l2tp-out1 gateway-status=l2tp-out1 reachable distance=0 scope=10 
 8 ADC  dst-address=192.168.77.0/24 pref-src=192.168.77.1 gateway=bridge-local gateway-status=bridge-local reachable distance=0 scope=10 
 9 A S  comment=thecall dst-address=192.168.254.0/24 gateway=172.16.79.1 gateway-status=172.16.79.1 reachable via  l2tp-out1 distance=1 scope=30 target-scope=10 
10 ADC  dst-address=213.22.11.99/32 pref-src=217.11.15.125 gateway=rtk gateway-status=rtk reachable distance=0 scope=10 

there is a lot of superfluous, we are interested only 0,1,2,3
Are 2 and 3 routes by default, 2 with a metrics (distance) "1" and is active at the moment and 3 with a metrics "2", at the moment it is not used

0 and 1 are necessary in order that the marshtutizator could answer from the same interface to which the request came, i.e. is not dependent on what now the route is by default active
the same logic is served and governed 0,1 of the following listing of rules of routing:
[f@777777] > ip r ru pr  
Flags: X - disabled, I - inactive 
 0   src-address=217.11.15.125/32 action=lookup table=RTK_mark 

 1   src-address=46.18.6.78/30 action=lookup table=GoodLine_mark 

 2   dst-address=192.168.77.0/24 action=lookup table=main

the rule 2 is necessary for devices of a local area network for MikroTik.

All this is called the capacious words "Policy based routing" and in end of the opus I will give several useful links for understanding of operation of these mechanisms rules.
* yes, I implemented the minimum, but is what is necessary for me

With aperitif we finished, will be engaged in a main course.
Listing of a script is packed under a spoiler since it is too big.
Hidden text
# ------------------- header -------------------
# Script by Tomas Kirnak, version 1.0.7
# If you use this script, or edit and
# re-use it, please keep the header intact.
#
# For more information and details about
# this script please visit the wiki page at
# http://wiki.mikrotik.com/wiki/Failover_Scripting
# ------------------- header -------------------

#------------------- header_1 ------------------
# FessAectan has made some changes: 
# - add ISPs link state checking -
# - add clearing connection tracking states for selected IP - 
# ------------------ header_1 ------------------

# ------------- start editing here -------------
# Edit the variables below to suit your needs

# Please fill the WAN interface names
:local InterfaceISP1 ether7
:local InterfaceISP2 rtk

# Please fill the gateway  IPs (or interface names in case of PPP)
:local GatewayISP1 46.18.6.77
:local GatewayISP2 rtk

# Please fill the ping check host - currently: resolver1.opendns.com
:local PingTarget 21.7.2.77

# Please fill how many ping failures are allowed before fail-over happends
:local FailTreshold 1

# Define the distance increase of a route when it fails
:local DistanceIncrease 2

# Editing the script after this point may break it
# -------------- stop editing here --------------

# Declare the global variables
:global PingFailCountISP1
:global PingFailCountISP2
:global InterfaceFailISP1
:global InterfaceFailISP2

# This inicializes the PingFailCount variables, in case this is the 1st time the script has ran
:if ([:typeof $PingFailCountISP1] = "nothing") do={:set PingFailCountISP1 0}
:if ([:typeof $PingFailCountISP2] = "nothing") do={:set PingFailCountISP2 0}

# IntercaceFail variables. First time initialization.
:if ([:typeof $InterfaceFailISP1] = "nothing") do={:set InterfaceFailISP1 0}
:if ([:typeof $InterfaceFailISP2] = "nothing") do={:set InterfaceFailISP2 0}

# This variable will be used to keep results of individual ping attempts
:local PingResult

# Your PBX IP
:local PBXIP 192.168.77.10

# Check ISP1

:if ([/interface get value-name=running $InterfaceISP1])  do={
:set PingResult [ping $PingTarget count=3 interface=$InterfaceISP1]

:if ($PingResult = 0) do={
    :if ($PingFailCountISP1 < ($FailTreshold)) do={
        :set PingFailCountISP1 ($PingFailCountISP1 + 1)}
            
    :if ($PingFailCountISP1 = $FailTreshold) do={
        :log warning "ISP1 has a problem en route to $PingTarget - increasing distance of routes."
        :foreach i in=[/ip route find gateway=$GatewayISP1 &&static &&comment=MAIN_TABLE] do=\
            {/ip route set $i distance=([/ip route get $i distance] + $DistanceIncrease)}
        :log warning "Route distance increase finished."
        /ip firewall connection { remove [find src-address~"$PBXIP"] }
    }
}
} else={
        :if ($InterfaceFailISP1 = 0) do={
        :set InterfaceFailISP1 1 
        :log warning "ISP1 intarface link is down - clear all connections from $PBXIP"
        /ip firewall connection { remove [find src-address~"$PBXIP"] }
}
}

:if ([/interface get value-name=running $InterfaceISP1])  do={
        :if ($InterfaceFailISP1 = 1) do={
        :set InterfaceFailISP1 0
        :log warning "ISP1 intarface link is up - clear all connections from $PBXIP"
        /ip firewall connection { remove [find src-address~"$PBXIP"] }
}
}

:if ($PingResult > 0) do={
    :if ($PingFailCountISP1 > 0) do={
        :set PingFailCountISP1 ($PingFailCountISP1 - 1)
            
    :if ($PingFailCountISP1 = ($FailTreshold -1)) do={
        :log warning "ISP1 can reach $PingTarget again - bringing back original distance of routes."
        :foreach i in=[/ip route find gateway=$GatewayISP1 &&static  &&comment=MAIN_TABLE] do=\
            {/ip route set $i distance=([/ip route get $i distance] - $DistanceIncrease)}
        :log warning "Route distance decrease finished."
        /ip firewall connection { remove [find src-address~"$PBXIP"] }
    }
    }
}

# Check ISP2

:if ([/interface  get value-name=running $InterfaceISP2]) do={

:set PingResult [ping $PingTarget count=3 interface=$InterfaceISP2]

:if ($PingResult = 0) do={
    :if ($PingFailCountISP2 < ($FailTreshold)) do={
        :set PingFailCountISP2 ($PingFailCountISP2 + 1)}
            
    :if ($PingFailCountISP2 = $FailTreshold) do={
        :log warning "ISP2 has a problem en route to $PingTarget - increasing distance of routes."
        :foreach i in=[/ip route find gateway=$GatewayISP2 &&static  &&comment=MAIN_TABLE] do=\
            {/ip route set $i distance=([/ip route get $i distance] + $DistanceIncrease)}
        :log warning "Route distance increase finished."
        /ip firewall connection { remove [find src-address~"$PBXIP"] }
    }
}
} else={
       :if ($InterfaceFailISP2 = 0) do={
       :set InterfaceFailISP2 1
       :log warning "ISP2 interface link is down - clear all connections from $PBXIP"
        /ip firewall connection { remove [find src-address~"$PBXIP"] }
}
}

:if ([/interface get value-name=running $InterfaceISP2]) do={
        :if ($InterfaceFailISP2 = 1) do={
        :set InterfaceFailISP2 0
        :log warning "ISP2 intarface link is up - clear all connections from $PBXIP"
        /ip firewall connection { remove [find src-address~"$PBXIP"] }
}
}

:if ($PingResult > 0) do={
    :if ($PingFailCountISP2 > 0) do={
        :set PingFailCountISP2 ($PingFailCountISP2 - 1)
            
    :if ($PingFailCountISP2 = ($FailTreshold -1)) do={
        :log warning "ISP2 can reach $PingTarget again - bringing back original distance of routes."
        :foreach i in=[/ip route find gateway=$GatewayISP2 &&static  &&comment=MAIN_TABLE] do=\
            {/ip route set $i distance=([/ip route get $i distance] - $DistanceIncrease)}
        :log warning "Route distance decrease finished."
        /ip firewall connection { remove [find src-address~"$PBXIP"] }
    }
    }
}



With the description of variables everything is clear, further briefly logic:
1. We check whether there is a link on the interface (whether there is PPPoE connection)
2. Is — we check availability of $PingTarget
2a. No — we delete all connections with src-address of our PBX. Active is a route with a metrics "2" that SIP registration old connections rose it is necessary to clean.
3. to $PingTarget it is available — we go to check ISP2
3a. to $PingTarget it is not available — we reduce a route metrics through ISP1 on 2 and we delete old connection from "Connection tracking"

Why I added check of a status of the interface?
If on port there is no link, then there is no sense to send a ping.
Or, in a case with PPP interfaces (as at me), the ping will not pass and will be broken logic of a script at all.
[f@777777] <SAFE> interface pppoe-cl di 0
[f@777777] <SAFE> 
[f@777777] <SAFE> 
[f@777777] <SAFE> 
[f@777777] <SAFE> 
[f@777777] <SAFE> :if ([/ping 8.8.8.8 interface=rtk count=3]>0) do={:put "Yes sir"}
  SEQ HOST                                     SIZE TTL TIME  STATUS                                                                                                                                             
<!-- тут команда тупо виснет и ничего не происходит - интерфейса то нет -->

[f@777777] <SAFE> interface pppoe-cl en 0                                            
[f@777777] <SAFE> :if ([/ping 8.8.8.8 interface=rtk count=3]>0) do={:put "Yes sir"}
  SEQ HOST                                     SIZE TTL TIME  STATUS                                                                                                                                             
    0 8.8.8.8                                                 timeout                                                                                                                                            
    1 8.8.8.8                                                 timeout                                                                                                                                            
    2 8.8.8.8                                    56 254 52ms 
    sent=3 received=1 packet-loss=66% min-rtt=52ms avg-rtt=52ms max-rtt=52ms 

Yes sir



Things are easy, to add a task in a sheduler of a router.
[f@777777] > sys sch exp
# nov/26/2015 17:37:29 by RouterOS 6.30
# software id = LY7Z-747B
#
/system scheduler
add interval=30s name=check_ISPs on-event=check_gateways policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=nov/20/2015 start-time=05:37:37

And here finished, we will pass to a dessert — to the used resources.

Part 3. The conclusion, the used resources


If there is a wish to esteem about DSCP, I advise to use these links:
1. cisco
2. ru.wikipedia
3. msdn.microsoft
4. microsin

About that as packets go to MikroTik as Policy routing is configured:
1. wiki Manual:Packet_Flow
2. wiki Policy_Base_Routing
3. nixman Policy_Base_Routing
4. blog.butchevans Policy_Base_Routing

Couple useful though I think all known, manuals on Iptables:
1. ru.wikibooks.org/wiki/Iptables
2. opennet iptables guid

Behind this I take the leave, thanks to those who read up.
I will be immensely glad if I am useful, in it and an essence.
All of good luck, all!

This article is a translation of the original post at habrahabr.ru/post/271747/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus