Podsumowanie ostatnich miesięcy

Bardziej spostrzegawczy którzy tutaj zaglądają pewnie zauważyli, że od kilku miesięcy nie pojawił się na tym blogu żaden wpis – śpieszę więc z wyjaśnieniami.

Na nme.pl, poza podstawowym blogiem, znajduje się jeszcze odrębna kategoria z własnym kanałem RSS – zawierająca wpisy w języku angielskim. Trochę głupio to wyglądało, że widoczna była jedynie pusta kategoria – dlatego trafiło tam kilka wpisów. Z bloga zniknęły linki do mojego minibloga i niedawno założonego mikrobloga. Uznałem, że nie są tu potrzebne – jedynie zaciemniają wizerunek bloga, który miał być z założenia techniczny.

Od mniej więcej miesiąca pracuje sobie nad nowym projektem w Django. Na chwilę obecną aktualny jego stan można zobaczyć na stronie urevs.com. Informacje na temat postępów prac opisuje na blogu pod adresem blog.urevs.com. Projekt w obecnej postaci wydaje się być jeszcze nie zaczęty, ale zawiera już wiele funkcjonalności:

  • możliwość zakładania kont które będą identyfikatorami OpenID (czyli OpenID Provider), podczas zakładania kont wykorzystana została reCAPTCHA
  • Aby zalogować się w serwisie nie trzeba mieć założonego lokalnie konta – można zalogować się poprzez m.in:
  • Serwis obsługuje https, lokalizację językową (obecnie dostępne są języki polski i angielski) i mój bootstrap do rozwijania aplikacji JavaScript i jego rozszerzenie – do generowania CSS’ów.

W międzyczasie muszę się jeszcze zabrać do roboty i dokończyć odświeżoną wersję mojego portalu do zarządzania siecią, którą już kończę przenosić na Django. Zabrałbym się pewnie prędzej, gdyby nie kompletny brak motywacji… W końcu trwa lato… i nie chce się tyle czasu siedzieć nad mądrymi projektami :)

Django application development

Most developers work on their startups far away from the daylight – they keep it in complete secret till the end. I’ve decided to do something new – I have started a project which is available to preview during the whole development. It is available at urevs.com. I also share all the project info on dedicated blog: blog.urevs.com.

This project consists currently of authentication framework and a lot of backend solutions. Site allows users to login using OpenID’s, Google, Twitter, Facebook or Yahoo Accounts. Full details are available here – social bootstrap engine for Django.

I’d be very glad to hear from You, about every suggestion You have.

Ubuntu: which package a file belongs to?

Some of us dont know this command, so:

nme@werewolf ~ $ dpkg -S /usr/bin/ffmpeg
ffmpeg: /usr/bin/ffmpeg

nme@werewolf ~ $

or

nme@werewolf ~ $ dpkg -S `which gcc`
gcc: /usr/bin/gcc

nme@werewolf ~ $

or

nme@werewolf ~ $ dpkg -S *bash
xz-utils: /usr/share/doc/xz-utils/extra/7z2lzma/7z2lzma.bash
bash: /usr/share/menu/bash
util-linux: /usr/share/doc/util-linux/examples/getopt-test.bash
util-linux: /usr/share/doc/util-linux/examples/getopt-parse.bash
bash: /bin/bash
apparmor: /etc/apparmor.d/abstractions/bash
bash: /bin/rbash
bash-completion, bash: /usr/share/doc/bash
global: /usr/bin/globash

nme@werewolf ~ $

You know smarter way? Add Your comment!

IPv4 CIDR to netmask in Python

I needed small function to validate IPv4 netmasks, havent found one, so I wrote my own. I’ve decided to use IPv4 CIDR notation to get corresponding netmasks. Here is the code:

def ipv4_cidr_to_netmask(bits):

    """ Convert CIDR bits to netmask """

    netmask = ''
    for i in range(4):
        if i:
            netmask += '.'
        if bits >= 8:
            netmask += '%d' % (2**8-1)
            bits -= 8
        else:
            netmask += '%d' % (256-2**(8-bits))
            bits = 0
    return netmask

Example usage is presented below. They also show how lambda mappings are useful in regular, daily use.

List all possible netmasks:

for netmask in map(lambda x: ipv4_cidr_to_netmask(x), range(0,33)):
    print netmask

0.0.0.0
128.0.0.0
192.0.0.0
224.0.0.0
240.0.0.0
248.0.0.0
252.0.0.0
254.0.0.0
255.0.0.0
255.128.0.0
255.192.0.0
255.224.0.0
255.240.0.0
255.248.0.0
255.252.0.0
255.254.0.0
255.255.0.0
255.255.128.0
255.255.192.0
255.255.224.0
255.255.240.0
255.255.248.0
255.255.252.0
255.255.254.0
255.255.255.0
255.255.255.128
255.255.255.192
255.255.255.224
255.255.255.240
255.255.255.248
255.255.255.252
255.255.255.254
255.255.255.255

Get netmask for /24:

print ipv4_cidr_to_netmask(24)

255.255.255.0

Is 255.255.254.0 valid IPv4 netmask?

print "255.255.254.0" in map(lambda x: ipv4_cidr_to_netmask(x), range(0,33))

True

Reverse search – get CIDR for 255.255.192.0 netmask

print map(lambda x: ipv4_cidr_to_netmask(x), range(0,33)).index('255.255.254.0')

23

As usual – enjoy :)

Simple WordPress plugin debugging

I’d like to present simplest way I know to debug WordPress plugins. It is a method I was using developing plugin to cloak URL‘s described earlier.

Below You can find the most minimalistic example plugin code possible – all it does is log REQUEST_URI to our debug file located at wp-content/plugins/debug. Row by row. Dirty and simple – and the most important – it does not require us to switch our WordPress to debug mode.

Plugin consists of three parts – plugin description header, debugging function and hook to main function which is executed right before page is rendered.

< ?php

/*
Plugin Name: test
Plugin URI:
Description:
Version:
Author:
Author URI:
*/

?>
< ?php

function debug($msg)
{
        $fp = fopen('wp-content/plugins/debug', 'a');
        fwrite($fp, $msg."\n");
        fclose($fp);
}

function main()
{
        debug($_SERVER['REQUEST_URI']);
}

add_action('init', 'main');

?>

Of course the most important part of the code is debug function which stores results we need to verify to our debug file.

jQuery-UI themeselect widget published

I’ve recently published jQuery-UI themeselect widget allowing users to add friendly looking, themable dropdown to instant theme switch.

In oppose to standard jQuery-UI themeswitcher, this one looks exacly like the rest of the theme.

My ui-themeselect has been published on New BSD License making it freely available and the code is hosted at Google Code. If You are familiar with Mercurial, you can clone the repository using command below:

hg clone https://ui-themeselect.googlecode.com/hg/ ui-themeselect

I have ripped the code out from my own Django / Google App Engine applications development Javascript bootstrap, because I think that someone else might consider it useful.

As an example how can it look inside jQuery-UI themed interface, take a look at this screenshot taken from one of my apps:

Enjoy! :)

WordPress plugin to redirect or cloak URL’s

After few unsuccessful searches for free WordPress plugin that would allow me to cloak URL’s on my blog – I decided to write my own. It was not really hard. I’m publishing it on GPLv3 license.

Plugin is really simple – full code consists of 75 lines of code. It does not contain database support, hits counting nor wp-admin interface. If some of You will like to extend it including those features – please do it and inform me – I will be first betatester :)

Plugin assumes that You already accomplished redirecting URL’s to WordPress subsystem that You would like to be handled by WordPress in a different way.

There are three possible kinds of URL threating:

  • Permanent redirect – typical HTTP 301 redirect
  • Temporary redirect – typical HTTP 302 redirect
  • Local cloak – it works only on Your blog web page (thats why it is called local) – it will hide real destination URL leaving it cloaked

How does it work?

The core of the plugin source is pasted below. Maybe some of You will consider it as interesting :) The most unfortunate part of the plugin is need to use /wp-admin/plugins.php Edit plugin feature to manually change URL’s. Those are listed inside $redirect variable.

define('PERMANENT_REDIRECT',301);
define('TEMPORARY_REDIRECT',302);
define('LOCAL_CLOAK',1);

$redirects = array(
  # source match         TYPE                           destination url
  # /u
  "^/u$" =>              array(TEMPORARY_REDIRECT,      "/u/"),
  "^/u/(.*)$" =>         array(LOCAL_CLOAK,             "/category/u/$1"),
}

function url_cloaker()
{
    global $redirects;
    $src_url = $_SERVER['REQUEST_URI'];
    foreach ($redirects as $src => $dst) {
        $src = str_replace('/','\/',$src);
        if (preg_match('/'.$src.'/',$src_url)) {
            #__d('Matched: '.$src);
            $dst_url = preg_replace('/'.$src.'/', $dst[1], $src_url);
            switch ($dst[0]) {
                case PERMANENT_REDIRECT:
                    wp_redirect($dst_url, PERMANENT_REDIRECT);
                    exit;
                case TEMPORARY_REDIRECT:
                    wp_redirect($dst_url, TEMPORARY_REDIRECT);
                    exit;
                case LOCAL_CLOAK:
                    $_SERVER['REQUEST_URI'] = $dst_url;
                    break;
            }
        }
    }
}

add_action('init', 'url_cloaker');

Plugin use actions hooking framework inside WordPress to make sure it is fired before page is shown.

The code above seems to be unreadable for You? Get this PHP book, because PHP is very simple language to learn and it offers a lot of new possibilities for those who know how to use it.

The plugin is available here for download.

Wygodny storage z użyciem memcache w Django

Czasami zachodzi konieczność napisania na szybko aplikacji w Django która standardowo coś tam trzyma w bazie danych, coś przetwarza i wyświetla. Jeśli aplikacja ma być prosta, a w bazie mają być trzymane proste struktury danych, to czy napewno musimy tyle czasu poświęcać na dopracowanie modeli? Jasne, że nie.

Poniższy kod oferuje nam możliwość trzymania dowolnych danych w postaci klucz-wartość w bazie danych. Dodatkowo – owe dane mogą mieć dowolną postać – może być to tekst, tablica asocjacyjna czy wartość typu Boolean.

Ponadto – biblioteczka ta opiera się o opisaną w poprzednim wpisie obsługę memcache’u w Django – co sprawia, że do póki nie zmienimy wartości danych, a ich obecność w cache’u nie zdąży wygasnąć – nie będziemy w ogóle obciążać naszej bazy danych. Osobiście wykorzystuję ten kod do trzymania ustawień aplikacji. Niektóre ustawienia są typu boolean, inne to stringi, jeszcze inne – tabele. Rozwiązanie sprawdza się świetnie.

Właściwy kod

Modele – models.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2009 nme.pl
# Dual licensed under MIT and GPL.

from django.db import models

class Vars (models.Model):

    key = models.CharField(max_length=50)
    value = models.TextField()

Proste prawda? Nie zapomnijcie wydać komendy django-admin syncdb która utworzy odpowiednią tabelę w bazie. Teraz czas na właściwą bibliotekę – vars.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2009 nme.pl
# Dual licensed under MIT and GPL.

""" Simple variables (key-value) handling with memcache """

import pickle,base64

import memcache,models

from settings import conf

class __Vars:

    def get (self,key,default=None):

        """ get Vars variable value """

        if memcache.enabled:
            value = memcache.get('va-%s' % key)
            if value != None:
                return pickle.loads(base64.b64decode(str(value)))
        settings = models.Vars.objects.filter(key=key)
        if settings:
            value = settings[0].value
            if value:
                return pickle.loads(base64.b64decode(str(value)))
            else:
                return default
        else:
            return default

    def __getitem__ (self,msg):

        return self.get(key)

    def set (self,key,value):

        """ set Vars variable value """

        value = base64.b64encode(pickle.dumps(value))
        if memcache.enabled:
            memcache.set('va-%s' % key,value)
        settings = models.Vars.objects.filter(key=key)
        if settings:
            setting = settings[0]
            setting.value = value
            setting.save()
        else:
            models.Vars(key=key,value=value).save()

    def has_key (self,key):

        """ return True or False if Vars variable exists """

        settings = models.Vars.objects.filter(key=key)
        if settings:
            return True
        else:
            return False

    def delete (self,key):

        """ deletes given key from Vars and memcache """

        if memcache.enabled:
            memcache.delete('va-%s' % key)
        settings = models.Vars.objects.filter(key=key)
        for i in settings:
            i.delete()

variables = __Vars()

Przykładowe użycie

Zastosowanie biblioteki z poziomu django-admin shell:

In [1]: from vars import variables

In [2]: if not variables.has_key('test'):
   ...:     variables.set('test','tekst')
   ...:
   ...:     

In [3]: print variables.get('test')
tekst

In [4]: variables.set('test',{'asd':1,'data':['struct','ure']})

In [5]: variables.get('test')['data'][1]
Out[5]: 'ure'

In [6]: variables.delete('test')

In [7]: variables.get('test')

In [8]: variables.has_key('test')
Out[8]: False

Jak to działa?

Składowanie dowolnego typu danych w rekordzie bazy zrealizowane jest w oparciu o dwie standardowe biblioteki pythonowe – picklebase64. Pierwsza z nich oferuje zakodowanie dowolnej struktury danych do stringa, druga natomiast – zastosowanie notacji base64 – przez co zabezpieczamy się przed ewentualnymi problemami z obsługą znaków z którymi nasz bazodanowy backend mógłby mieć ewentualnie problemy. Innymi słowy – rozwiązanie przedstawione powyżej gwarantuje nam pełną przenośność danych.

Zachęcam gorąco do korzystania :)

Memcache w Django: krok ku lepszej skalowalności

Podczas tworzenia aplikacji webowych, warto w miarę wcześnie pomyśleć o skali z jaką nasze rozwiązanie będzie miało się w przyszłości zmierzyć. Niezależnie od tego czy owa aplikacja ma pracować w jednym przedsiębiorstwie, czy próbuje zainstnieć szerzej, w sieci – w każdym przypadku może się okazać, że odniesie sukces. To z kolei sprawi, że ilość jej użytkowników urośnie… Firma może się rozwinąć, przejąć konkurencję, aplikacja webowa może się okazać takim strzałem w dziesiątkę jak nie tak dawno temu Nasza-Klasa – nigdy nie wiadomo :) W momencie gdy miałaby go odnieść, nie będzie już zbyt wiele czasu na przebudowę kodu, a napewno nie będzie go na jego całkowitą reorganizację.

Jeśli rozwiązanie jest skryptem uruchamianym od święta – może to być zwykły skrypt CGI. Jeśli jednak miałby być uruchamiany częściej – wartałoby już pomyśleć o mod_php czy mod_python… Albo jeszcze lepiej – fastcgi, a w przypadku pythona – wsgi. Kiedy użycie aplikacji rośnie nadal – frontend mnożymy na kolejne węzły stawiając przed nimi balancera robiącego za reverse proxy. A w backendzie klastrujemy… ale co na styku macierz, klaster? Ilość zapytań do bazy rośnie, io waity zaczynają rosnąć i robi się nieciekawie… Da się to rozwiązać?

Jak to robi Google

Google od jakiegoś czasu pokazuje nam jak powinny być tworzone intensywnie wykorzystywane aplikacje webowe i na jak zorganizowanym backendzie powinny pracować, aby skalowały się najefektywniej. Myślę, że warto z tej wiedzy skorzystać zanim io waity zaczną spędzać nam sen z powiek.

Miałem okazję napisać sobie kilka małych aplikacji które pracują w chmurze na platformie Google – tzw. Google App Engine (w skrócie GAE). Warto było poświęcić trochę czasu aby to rozwiązanie poznać. Łatwiej było mi dzięki temu można zrozumieć między innymi dlaczego poszczególne serwery Google nie są potężnymi serwerami rackowymi z bardzo silnymi procesorami, ale raczej „lżejszymi” serwerkami, ale za to wypełnionymi po brzegi koścmi pamięci.

Dlaczego takie lżejsze maszyny? Poza oszczędnością energii i pieniędzy są one wystarczające do obsługi pythonowych frameworków, w przeciwieństwie do tych PHP’owych.

Google skupia się na Javie i Pythonie, gdzie prawie pewne jest to, że ich rozproszony Datastore – system bazodanowy, został stworzony w oparciu o język Python. Język ten znany jest m.in z wydajności, szczególnie, jeśli osoba która go używa stosuje się do najbardziej podstawowych zasad jak nie allokowanie ogromnej ilości pamięci itp. Dlaczego więc w serwerach Google tyle pamięci? Odpowiedzią jest memcache.

Google chwali się tym, że stworzyli sobie własną implementację cache, inspirowaną oprogramowaniem memcached i zachęca, aby developerzy aplikacji App Engine’owych również korzystali z memcache’a.

Na czym polega memcache

Uproszczony graf przedstawiający działanie memcache’u:

Koncepcja działania jest prosta – zamiast odwoływać się bezpośrednio do bazy danych, odwołujemy się do memcache’a – jeśli trafiliśmy na dane (hit), wykorzystujemy je, jeśli nie (miss), dopiero wtedy odwołujemy się do bazy, jednocześnie zapisując pobrane z bazy dane w naszym cache’u. Dzięki temu prostemu zabiegowi, nasza strona, która podczas każdego odwołania do niej potrzebuje jakichś danych z bazy, jest w stanie funkcjonować praktycznie w ogóle jej o nic nie odpytując – wszystko co potrzebne będzie trzymać w pamięci podręcznej.

Zastosowanie i dokumentacja

Aby wykorzystać memcache w Google App Engine, polecam zapoznanie się z dokumentacją na stronach Google.

A co jeśli chcielibyśmy wykorzystać memcache w Django? Naturalnie – nic nie stoi na przeszkodzie – Django posiada coś takiego jak cache framework, który na dodatek jest bardzo dobrze udokumentowany.

Django samo z siebie jest przystosowane do wykorzystania cache’u przy obsłudze widoków czy template’ów, ale również oferuje dostęp niskopoziomowy – niemalże analogiczny do tego z Google App Engine… Niemalże, bo jakoś wersja Google bardziej przypadła mi do gustu. Dlatego przygotowałem sobie prosty interfejs, który wydaje mi się być odrobinę bardziej logiczny. Kod oczywiście załączam. Mam nadzieję, że komuś się przyda.

Konfiguracja systemu, projektu Django oraz moja niskopoziomowa obsługa

Zakładając, że pracujemy na systemie GNU Debian/Ubuntu oraz Django jest już w systemie jakąś drogą zainstalowane (osobiście w tym akurat przypadku polecam instalację z oryginalnych źródeł nad paczką Django z dystrybucji), doinstalowujemy obługę memcached, włączamy ją i restartujemy demona memcached:

sudo -i
aptitude install memcached python-memcache
sed -i 's/no/yes/' /etc/default/memcached
service memcached restart
exit

teraz w naszym projekcie Django włączamy obsługę cache:

w pliku settings.py:

CACHE_BACKEND = 'memcached://127.0.0.1:11211/'

jeśli chcemy wykorzystać moją małą biblioteczkę poniżej, do settings.py musimy dodać też konfigurację memcache:

class conf:
    class memcache:
        disabled = False
        timeout = 600

Moja niskopoziomowa obsługa memcache.py:

#!/usr/bin/python
# -*- coding: utf-8 -*-

""" cache low-level backend based on memcached """

from django.core.cache import cache

from settings import conf

def get(key, default=None, timeout=conf.memcache.timeout):

    """ returns value for given key from cache, and refreshes it
    in memcache with automatic conversion from unicode
    to str - fix to:
    __import__() argument 1 must be string without null bytes, not str """

    value = cache.get(key, default)

    if value is not default:
        cache.set(key, value, timeout)

    if type(value) is unicode:
        value = str(value)

    return value

def set(key, value, timeout=conf.memcache.timeout):

    """ sets a value for given key in cache """

    cache.set(key, value, timeout)

def delete(key):

    """ remove given key from cache """

    cache.delete(key)

# in the name of syntatic sugar ;) 

disabled = bool(conf.memcache.disabled)
enabled = not disabled

A przykład zastosowania pojawi się jutro albo pojutrze – w nowym wpisie.

How to add IMQ patch to Ubuntu 10.04 Lucid Lynx

Those of you, who are having problems adding IMQ support to recent Ubuntu/Debian release, might consider this blog entry useful :)

I will not discuss what IMQ is and wheater is it good or bad – I will describe how to prepare kernel, iptables packages and how to deploy them to our Debian/Ubuntu system including taking care of making them immune to accidential system upgrade packages replacement.

Kernel package with IMQ support

Before we start – we need few packages that will might be required:

sudo aptitude install fakeroot build-essential kernel-package ncurses-dev

Now we are ready to start: first, we need our current kernel with distro patches. For desktop instance I would use -generic instead of -server:

apt-get source linux-image-2.6.32-22-server

Now, we download imq patch, apply it and compile kernel:

wget http://linuximq.net/patchs/linux-2.6.32-imq-test2.diff

cd linux-2.6.32/

patch -p1 < ../linux-2.6.32-imq-test2.diff

fakeroot time make-kpkg --initrd --append_to_version=imq linux-image

During the compilation process, make-kpkg script will discover unanswered features that we need to check as modules:

  "IMQ" target support (NETFILTER_XT_TARGET_IMQ) [N/m/?] (NEW) m

  IMQ (intermediate queueing device) support (IMQ) [M/y/?] (NEW) M

    IMQ behavior (PRE/POSTROUTING)

      1. IMQ AA (IMQ_BEHAVIOR_AA) (NEW)

    > 2. IMQ AB (IMQ_BEHAVIOR_AB) (NEW)

      3. IMQ BA (IMQ_BEHAVIOR_BA) (NEW)

      4. IMQ BB (IMQ_BEHAVIOR_BB) (NEW)

    choice[1-4?]: 2

    Number of IMQ devices (IMQ_NUM_DEVS) [16] (NEW)

Finally... in parent directory we will find:

linux-image-2.6.32.11+drm33.2imq_2.6.32.11+drm33.2imq-10.00.Custom_i386.deb

If everything went fine and our package is present - we can clean up compiled object files that will not be required anymore, recovering few GB of hard disk space:

./debian/rules clean

in case You forget to generate initrd file, it always might be generated by hand:

sudo -i

cd /boot/

mkinitramfs-kpkg -o initrd.img-2.6.32.11+drm33.2imq 2.6.32.11+drm33.2imq

update-grub

Iptables package with IMQ support

First, the patch - there is no iptables-1.4.4 imq patch available on linuximq.net I'm afraid. I have used iptables-1.4.6-imq patch and fixed it to compile with iptables-1.4.4.

Original patch can be found here.

Changes:

diff -Naurw iptables-1.4.6-imq.diff iptables-1.4.4-imq.diff
--- iptables-1.4.6-imq.diff	2010-01-27 11:53:22.000000000 +0100
+++ iptables-1.4.4-imq.diff	2010-05-08 13:18:21.000000000 +0200
@@ -43,7 +43,7 @@
 +
 +	switch(c) {
 +	case '1':
-+		if (xtables_check_inverse(optarg, &invert, NULL, 0, argv))
++		if (xtables_check_inverse(optarg, &invert, 0, argv))
 +			xtables_error(PARAMETER_PROBLEM,
 +				   "Unexpected `!' after --todev");
 +		mr->todev=atoi(optarg);

Ready to use patch can be downloaded from here using command below:

wget http://nme.pl/pub/patches/iptables-1.4.4-imq.diff

Ok, now since we got patch ready, we can download iptables sources and compile our deb package:

apt-get source iptables
cd iptables-1.4.4

cp ../iptables-1.4.4-imq.diff debian/patch/1009-iptables-1.4.4-imq.diff
echo "1009-iptables-1.4.4-imq.diff" >>debian/patch/series

patch -p0 < ../iptables-1.4.4-imq.diff

dpkg-buildpackage -rfakeroot -uc -b

In case You are recompiling for some reason, one of the distro patches might fail - in this case edit debian/patches/series using Your favourite editor and comment out the following patch:

0902-docs-version-reference.diff    ->    #0902-docs-version-reference.diff

Operation above might be archived by in place edition of debian/patch/series using command below:

sed -i 's/^0902/#0902/' debian/patch/series

When compilation ends, You should get two packages in parent directory: iptables and iptables-dev.

Installation & freezing our changes

Now we can install our packages:

dpkg -i *.deb

It will install following packages:

iptables_1.4.4-2ubuntu2_i386.deb
linux-image-2.6.32.11+drm33.2imq_2.6.32.11+drm33.2imq-10.00.Custom_i386.deb
iptables-dev_1.4.4-2ubuntu2_i386.deb

You might also consider holding packages to be sure that they will not be replaced during standard regular-basis upgrade:

aptitude hold linux-image iptables iptables-dev

IMQ development, status and replacement discussion

It is not true that recent IMQ patches are not stable as I have read on some web pages. Since Jussi joined the IMQ team, problems I have had with 2.6.18-24 kernels have gone to past.

Kernel 2.6.28.9 with iptables 1.4.0 works perfectly stable taking care of huge loads of network traffic. I think that current patch described above will work the same (im making before-production tests currently and it seems to work fine).

On the other hand - IFB - which is meant as replacement for IMQ - as for me - it does not offer the same functionality for bridge environment I need... Of course - I might be mistaken. Thats why - if anyone of You have replaced IMQ with IFB for bridge devices with ingress and egress traffic shaping - I'm very interested in the solution.

Następnya strona »