Tüm Ürünler
Search
Belge Merkezi

:Customize RSS for ENIs

Son Güncelleme:Sep 30, 2026

Desteklenen ENI'lerde RSS karma kurallarını ve dolaylı tablo eşleştirmelerini özelleştirerek trafiği CPU çekirdekleri arasında dengeli bir şekilde dağıtın ve tek çekirdek darboğazlarını çözün.

RSS Nedir

Alıcı Tarafı Ölçeklendirme (RSS), ENI donanımını ve sürücüsünü kullanarak paket özelliklerinden (kaynak/hedef IP adresleri ve bağlantı noktaları) bir karma değeri hesaplar ve farklı trafik akışlarını birden fazla RX kuyruğuna eşler. Bağlı CPU çekirdekleri kuyrukları paralel olarak işleyerek yük dengelemesi sağlar ve tek çekirdek gecikmesini azaltır.

Çoklu kuyruğu destekleyen bir ENI her kuyruk için bağımsız RX (alma) ve TX (gönderme) kanalları kullanarak paralel işleme olanak tanır. Bir paket geldiğinde, ENI donanımı bir RSS ilkesi kullanarak farklı veri akışlarını birden fazla RX kuyruğuna dağıtır. Varsayılan olarak, bir ECS örneği için RSS ilkesi Virtual Private Cloud (VPC) içinde sabittir ve örnek içinden görüntülenemez veya değiştirilemez.

Bazı örnek aileleri, ENI'ler için özel RSS özelliğini destekler. Desteklenen bir örnek ailesinde özel RSS özelliğini etkinleştirdikten sonra, ENI trafiği varsayılan özel karma kurallarına göre dağıtır. Ayrıca, gerçek trafik özelliklerine bağlı olarak RSS yapılandırmasını ayarlayabilirsiniz.

Özel RSS'i etkinleştirdikten sonra, çoklu çekirdek performansını en üst düzeye çıkarmak amacıyla DPDK senaryolarında RSS'i yapılandırabilirsiniz.

Nasıl Çalışır

Bir ECS örneği ENI'si için özel RSS şu şekilde çalışır:

  • Karma değeri hesaplama: ENI; 5-tuple (kaynak IP, hedef IP, kaynak bağlantı noktası, hedef bağlantı noktası ve protokol), bir karma anahtarı ve bir karma algoritması kullanarak bir karma değeri hesaplar.

    • Karma anahtarı: Sabit 40 baytlık bir değerdir. ENI sürücüsü başlatma sırasında varsayılan bir karma anahtarı oluşturur. Trafik dağıtımını etkilemek için karma anahtarını ayarlayabilirsiniz.

    • Karma algoritması: Şu anda yalnızca varsayılan toeplitz algoritması desteklenmektedir. Bu ayar değiştirilemez.

    • Karma kuralları: Karma değerlerini hesaplama kuralları trafik türüne göre değişir. ECS ENI RSS için varsayılan karma kuralları aşağıdaki gibidir. Bu kuralları değiştiremezsiniz.

      • IPv4/IPv6 üzerinden TCP ve UDP trafiği: 4-tuple (kaynak IP, hedef IP, kaynak bağlantı noktası ve hedef bağlantı noktası) ve karma anahtarı temel alınarak bir karma değeri hesaplanır.

      • IPv4/IPv6 üzerinden TCP/UDP dışı trafik (ICMP gibi): 2-tuple (kaynak IP ve hedef IP) ve karma anahtarı temel alınarak bir karma değeri hesaplanır.

      • IP olmayan mesajlar (ARP gibi) varsayılan kuyruğa (kuyruk 0) gönderilir ve karma işlemine tabi tutulmaz.

  • Dolaylı tablo eşleştirme: RSS dolaylı tablosu, karma değerlerini hedef alma kuyruklarına eşleyen önceden tanımlanmış bir dizidir. Her öğe (karma kovası) 0, 1 veya 2 gibi bir kuyruk numarası saklar. ENI sürücüsü yüklendiğinde, trafiği eşit şekilde dağıtan bir dolaylı tablo otomatik olarak oluşturulur.

    • Dolaylı tablo uzunluğu: Toplam karma kovası sayısıdır. Değer sabit olarak 128 olarak ayarlanmıştır.

    • Dağıtım modları:

      RSS dolaylı tablosunun dağıtım modu, karma değerlerini belirli alma kuyruklarına eşleyen temel mekanizmadır. Önceden tanımlanmış bir dolaylı tablo kullanılarak, karma hesaplamanın sonucu bir kuyruk indeksine dönüştürülür. Bu sayede, trafik birden fazla çekirdek arasında esnek bir şekilde dağıtılabilir.

      Eşit dağıtım ve ağırlıklı dağıtım gibi farklı dağıtım modları, trafiğin CPU çekirdekleri arasında nasıl dağıtılacağını doğrudan etkiler. Bu durum da sistem aktarım hızını, gecikme süresini, kaynak kullanımını ve hizmet performansını etkiler.

      Senaryonuz için uygun bir dağıtım deseni seçin. Bkz. Dolaylı tablo dağıtım deseni.

    • Dolaylı tablo eşleştirme süreci:

      1. Karma kovası indeksi hesaplama: Index = Hash value % Indirection table length (Örneğin, 88 % 128 → indeks 88). İndeks değerini hesaplamak için RSS hesaplama betiğini kullanabilirsiniz.

      2. Kuyruk numaralarını doldurma: Dağıtım moduna bağlı olarak her karma kovasına kuyruk numaralarını yazın.

        Dolaylı tablo oluşturulduktan sonra, her paketin karma indeksi bir kuyruk numarasıyla eşleşir ve paket ilgili kuyruğa gönderilir.

  • CPU çekirdeği bağlama: Bir kuyruk bir paket aldığında bir kesme tetiklenir. Bağlı CPU çekirdeği kesmeyi işler.

    Red Hat Enterprise Linux dışındaki görüntüler, ağ kesmesi uyumluluğunu varsayılan olarak destekler. Her kuyruk bağımsız bir kesmeyle ilişkilendirilir ve kesme uyumluluğu işlemeyi farklı CPU çekirdeklerine dağıtır. Bkz. Çoklu kuyruğun temel mekanizması.

Bir ENI için Özel RSS'i Etkinleştirme veya Devre Dışı Bırakma

Önemli

ENI'ler için özel RSS özelliği davetli ön izleme aşamasındadır. Bu özelliği kullanmak için bir destek talebi gönderebilirsiniz.

Desteklenen bir örnek türünde özel RSS'i etkinleştirdiğinizde, alınan trafik varsayılan karma kurallarına göre birden fazla alma kuyruğuna dağıtılır. Farklı CPU çekirdekleri kuyrukları paralel olarak işleyerek aktarım hızını artırır ve tek çekirdek yükünü azaltır.

Ön Koşullar

  • Özel RSS aşamalı olarak sunulmaktadır. Aşağıdaki bölgelerde kullanılabilir:


    Bölge Adı


    Bölge Kimliği


    China (Hong Kong)


    cn-hongkong

  • Yalnızca bazı çoklu kuyruk örnek aileleri özel RSS'i destekler; bunlara genel amaçlı örnek ailesi g9i ve bellek optimize edilmiş örnek ailesi r9i dahildir.

    Destek durumunu kontrol etmek için DescribeInstanceTypes API işlemini çağırın. RssSupport=true değeri, özelliğin desteklendiğini gösterir.

  • Alibaba Cloud Linux 3.2104 LTS 64-bit görüntüsü önerilir.

    • Diğer genel görüntüleri kullanıyorsanız, çekirdek sürümü 6,12 veya üzeri olmalıdır.

    • Özel RSS özelliğini bir DPDK uygulamasında kullanıyorsanız, DPDK sürümü 21,11 veya üzeri olmalıdır.

Nasıl Etkinleştirilir veya Devre Dışı Bırakılır

Özel RSS varsayılan olarak devre dışıdır. Bir ENI oluştururken veya ENI oluşturulduktan sonra etkinleştirebilir ya da devre dışı bırakabilirsiniz.

  • CreateNetworkInterface çağrılırken, EnhancedNetwork içindeki EnableRss parametresini true veya false olarak ayarlayın.

    Özel RSS, ENI bir örneğe eklendikten sonra etkili olur.

  • ModifyNetworkInterfaceAttribute işlemini çağırın ve EnhancedNetwork içindeki EnableRss parametresini true veya false olarak ayarlayın. Etkinleştirme veya devre dışı bırakma işleminden sonra, değişiklik ENI yeniden eklendiğinde etkili olur:

  • Özel RSS'in etkin olup olmadığını sorgulamak için Attribute parametresini enhancedNetwork olarak ayarlayıp DescribeNetworkInterfaceAttribute işlemini çağırın. EnableRSS=true değeri etkin olduğunu; false değeri ise devre dışı olduğunu gösterir.

    ENI için RSS değiştirilmemişse, bu işlem EnableRSS parametresini döndürmez; bu da özelliğin etkin olmadığı anlamına gelir.

Bir ENI'nin RSS Yapılandırmasını Görüntüleme

Özel RSS'i etkinleştirdiğinizde, ENI yeniden yüklendiğinde ENI sürücüsü varsayılan mekanizma ve kurallara göre varsayılan bir RSS yapılandırması oluşturur.

Bir Linux örneğine uzaktan oturum açabilir ve birincil ENI'nin RSS yapılandırmasını görüntülemek için ethtool -x eth0 komutunu çalıştırabilirsiniz. İkincil bir ENI için arayüz tanımlayıcısını (eth1, eth2 vb.) değiştirin.

image

  • Karma tablosu (RX akış karma dolaylı tablosu): Karma değerlerinin 64 alma kuyruğuna eşlenme kurallarını tanımlar.

    • Karma tablosundaki her satır, başlangıç indeksiyle belirtilen bir karma değeri aralığını temsil eder. Örneğin, 0 değeri 0-7 arasındaki karma değerlerini; 8 değeri ise 8-15 arasındaki değerleri gösterir.

    • Tablodaki sayılar (0, 1, 2 vb.) karşılık gelen alma kuyruklarının kimliklerini temsil eder. Bu örnekte 64 kuyruk (0-63) bulunmaktadır.

    • Geçerli yapılandırma: Dolaylı tablo 0,1,2,...,63,0,1,2...63 sırasıyla döngüsel olarak doldurulur; bu sayede karma değerleri 64 kuyruğa eşit şekilde dağıtılır ve trafik dengelenir.

  • RSS karma anahtarı: Karma değerini hesaplamak için kullanılan anahtardır. Onaltılık karakterler 40 baytlık bir anahtarı temsil eder.

  • RSS karma işlevi: Karma değerini hesaplama algoritmasını tanımlar.

    • toeplitz: Bu varsayılan algoritmadır ve şu anda etkindir. 5-tuple tabanlı simetrik karma desteği sunar ve genel amaçlı trafik için uygundur.

    • xor/crc32: Bunlar genellikle belirli senaryolarda kullanılan diğer isteğe bağlı algoritmalardır. ECS şu anda yalnızca toeplitz algoritmasını destekler; diğer algoritmalar desteklenmez veya etkin değildir.

  • Karma kuralları: Birincil ENI tarafından alınan trafik için karma alanı yapılandırmasını görüntüleyin.

    ethtool  -n eth0 rx-flow-hash tcp4
    • Sorgulamak istediğiniz protokol türüne göre tcp4 ifadesini udp4, tcp6 veya udp6 ile değiştirebilirsiniz.

    • ECS ENI RSS için varsayılan karma kuralları aşağıdaki gibidir. Bu kuralları değiştiremezsiniz.

      • IPv4/IPv6 üzerinden TCP ve UDP trafiği: 4-tuple (kaynak IP, hedef IP, kaynak bağlantı noktası ve hedef bağlantı noktası) ve karma anahtarı temel alınarak bir karma değeri hesaplanır.

      • IPv4/IPv6 üzerinden TCP/UDP dışı trafik (ICMP gibi): 2-tuple (kaynak IP ve hedef IP) ve karma anahtarı temel alınarak bir karma değeri hesaplanır.

      • IP olmayan mesajlar (ARP gibi) varsayılan kuyruğa (kuyruk 0) gönderilir ve karma işlemine tabi tutulmaz.

    • Örnek olarak tcp4 alındığında, IPv4 TCP trafiği için karma değeri varsayılan olarak 4-tuple (kaynak IP, hedef IP adresi, kaynak bağlantı noktası, hedef bağlantı noktası) ve karma anahtarı temel alınarak hesaplanır:

      image

      Beklenen trafik özellikleri şunlardır:

      • Aynı TCP bağlantısı: Tüm paketler aynı karma değerine sahiptir ve aynı kuyruğa dağıtılır. Bu, paket sıralamasını garanti eder.

      • Farklı TCP bağlantıları: 4-tuple'lar farklıysa, karma değerleri de farklı olur. Trafik farklı kuyruklara dağıtılır. Bu sayede birden fazla CPU çekirdeği farklı bağlantıları paralel olarak işleyebilir ve aktarım hızı artar.

Aşağıdaki ileti döndürülüyorsa, özel RSS etkin değil veya örnek türü bunu desteklemiyor demektir. Örnek türünün desteklendiğini onayladıktan sonra özel RSS'i etkinleştirin.

image

Bir ENI için Özel RSS Yapılandırma

Varsayılan RSS yapılandırması çoğu gereksinimi karşılar. Aşağıdaki durumlarda karma anahtarını veya dolaylı tabloyu ayarlamanız gerekebilir:

  • Dengesiz trafik: Varsayılan karma değerleri belirli trafiği birkaç kuyrukta yoğunlaştırabilir.

  • Performans optimizasyonu: Kuyruk kullanımını iyileştirmek için yüksek UDP oranı gibi trafik özelliklerine dayalı olarak karma kurallarını ayarlayın.

  • Güvenlik gereksinimleri: Saldırganların trafik dağıtımını tahmin etmesini önlemek için özel bir karma anahtarı kullanın.

Önemli
  • Bu örnekte, örnek Alibaba Cloud Linux 3.2104 LTS 64-bit görüntüsüyle yapılandırılmıştır.

  • Bu örnekte birincil ENI eth0 kullanılmaktadır. Karşılık gelen ikincil ENI için RSS'i değiştirmek üzere arayüz tanımlayıcısını eth1 veya eth2 ile değiştirin.

  • RSS yapılandırması trafik özelliklerinizle eşleşmediğinde, dengesiz dağılıma ve çekirdekler arası durum çekişmesine neden olarak performansı etkileyebilir. Gerçek trafik özelliklerine göre ayarlama yapın ve kuyruk dağıtımını gerçek zamanlı olarak gözlemlemek için izleme araçlarını kullanın.

Karma Anahtarını Yapılandırma

Trafik dengesiz dağıtılıyorsa (örneğin, bazı kuyrukların rx_packets değeri diğerlerinden belirgin şekilde yüksekse) veya saldırganların karma değerini tersine mühendislikle analiz ederek trafik modellerini çıkarmasını önlemek için RSS karma anahtarını yeniden oluşturun.

Önemli

Anahtarı değiştirmek, mevcut bağlantıların karma değerlerini değiştirir; bu da geçici paket yeniden sıralanmasına veya yeniden iletimlere neden olabilir. Bu işlemi yoğun saatler dışında gerçekleştirin.

  1. ENI'nin geçerli karma anahtarını görüntüleyin.

    ENI yüklendiğinde, ENI sürücüsü 40 baytlık varsayılan bir karma anahtarı oluşturur.

    ethtool -x eth0

    image

  2. OpenSSL kullanarak yeni bir rastgele anahtar oluşturun.

    openssl rand -hex 40 | fold -w2 | paste -sd: -
  3. Yeni anahtarı ENI'ye uygulayın.

    Önemli

    Bu geçici bir ayardır. Örnek yeniden başlatıldığında veya ENI yeniden eklendiğinde geçerliliğini yitirir. ENI sürücüsü otomatik olarak rastgele bir varsayılan yapılandırmayı başlatır.

    ethtool -X eth0 hkey <hash key>

    <hash key> yerine önceki adımda oluşturduğunuz yeni anahtarı yazın.

  4. Yeni anahtarın etkili olduğunu doğrulayın.

    ethtool -x eth0

    Çıktı, yeni anahtarın etkili olduğunu gösterir:

    image

Dolaylı Tabloyu Yapılandırma

RSS dolaylı tablosunun dağıtım modu, karma değerlerini belirli alma kuyruklarına eşleyen temel mekanizmadır. Önceden tanımlanmış bir dolaylı tablo kullanılarak, karma hesaplamanın sonucu bir kuyruk indeksine dönüştürülür. Bu sayede, trafik birden fazla çekirdek arasında esnek bir şekilde dağıtılabilir.

Eşit dağıtım ve ağırlıklı dağıtım gibi farklı dağıtım modları, trafiğin CPU çekirdekleri arasında nasıl dağıtılacağını doğrudan etkiler. Bu durum da sistem aktarım hızını, gecikme süresini, kaynak kullanımını ve hizmet performansını etkiler.

Senaryonuz için bir dağıtım modu seçin.

Önemli

Aşağıdaki yapılandırmalar geçicidir. Örnek yeniden başlatıldığında veya ENI yeniden eklendiğinde geçerliliğini yitirir. ENI sürücüsü rastgele bir varsayılan yapılandırmayı yeniden başlatır.

  • Eşit dağıtım modu: İlk N kuyruk, karma kovalarını döngüsel olarak doldurur. Genel yüksek eşzamanlılık senaryoları için uygundur.

    ethtool -X eth0 equal <Number of queues N>

    Değer 64 olarak ayarlanırsa, dolaylı tablo 0,1,2,...,63,0,1,2...63, şeklinde döngüsel olarak doldurulur.

    image

  • Ağırlıklı dağıtım: Karma kovalarını ağırlık oranlarına göre tahsis edin. Farklılaştırılmış iş önceliklerine sahip senaryolar (örneğin, kuyruk 0 gerçek zamanlı trafiği işler ve kuyruk 1 arka plan görevlerini işler) veya karışık CPU performansı durumları için uygundur.

    ethtool -X eth0 weight <queue 0 weight> <queue 1 weight> ...

    Aşağıdaki örnekte, kuyruk 0 %60 ve kuyruk 1 %40 alır:

    Not

    Toplam dört kuyruk varsa ancak yalnızca iki kuyruk için ağırlık belirlerseniz, dolaylı tablo yalnızca kuyruk 0 ve kuyruk 1 için eşlemeler oluşturur.

    ethtool -X eth0 weight 6 4

    image

  • Kısmi kuyruk dağıtımı: Belirtilen bir kuyruktan başlayarak, ardışık kuyrukları kullanarak karma kovalarını döngüsel olarak doldurun. Trafiği belirli bir CPU aralığına (örneğin, bir NUMA düğümüne) yönlendirmek için uygundur.

    ethtool -X eth0 start <start queue> equal <number of queues>

    Aşağıdaki örnekte, kuyruk 2'den başlayan 40 kuyruk (kuyruk 2-41) karma kovalarını doldurur:

    ethtool -X eth0 start 2 equal 40

    image

Trafik Dağıtımını Gözlemlemek için watch Kullanma

ENI'de özel RSS'i etkinleştirdikten sonra, farklı özelliklere sahip trafik oluşturmak için hping3 ve kuyruk kesme dağıtımını izlemek için watch kullanarak trafiğin beklendiği gibi birden fazla çekirdeğe dağıtılıp dağıtılmadığını doğrulayın.

Ön Koşullar

Aşağıdaki yapılandırmalara sahip iki ECS örneği satın alın:

  • Gönderen ECS örneği (10.0.0.252): Farklı özelliklere sahip trafik oluşturmak için hping3 yüklenmiş bir örnek.

  • Alıcı ECS örneği: Türü ENI'ler için çoklu kuyruğu destekleyen, ikincil bir ENI eklenmiş (10.0.0.5) ve ikincil ENI eth1'de özel RSS etkinleştirilmiş bir örnek.

    Not
    • Bu örnekte test için dört kuyruk kullanılmaktadır.

    • Birincil ENI'deki SSH oturum açma trafiğinin etkisini ortadan kaldırmak için test amacıyla ikincil ENI eth1'de özel RSS etkinleştirilmiştir.

  • Ağ bağlantısı: İki ECS örneği aynı güvenlik grubundadır ve iç ağ üzerinden birbirleriyle iletişim kurabilir.

Yordam

  1. Alıcı ECS örneğinde oturum açın, ikincil ENI'nin RSS yapılandırmasını kontrol edin ve beklenen trafik dağıtımını onaylayın. Bkz. Bir ENI'nin RSS Yapılandırmasını Görüntüleme.

    image

  2. Gönderen ECS örneğinde oturum açın ve hping3 yükleyin.

    yum install -y hping3
  3. Alıcı ECS örneğinde, kuyruk paket sayılarını gerçek zamanlı olarak izleyin.

    watch -n 1 "ethtool -S eth1 | grep rx[0,1,2,3]_packets"

    Kuyruk numarası yapılandırmasını alıcı ENI'nin gerçek yapılandırmasıyla değiştirin.

  4. Gönderen ECS örneğinde oturum açın ve farklı trafik kalıplarını simüle edin.

    • Senaryo 1: Rastgele hedef bağlantı noktalarıyla alıcı IP adresine yüksek hızda 10.000 SYN paketi gönderin. Bu, trafik karmasının dağıldığını sağlar ve karma dengelemesini doğrular.

      sudo hping3 10.0.0.5 -S -a 10.0.0.252 --rand-dest -p 0 --baseport 10000 -c 10000 -i u100 -I eth0
      • rand-dest: Rastgele hedef bağlantı noktası

      • -p 0: rand-dest ile birlikte kullanılır

      • --baseport 10000: Kaynak bağlantı noktası için başlangıç değeri.

      • -c 10000: 10.000 paket gönder

      • -i u100: Yüksek hızlı gönderim için paketler arasında 100 mikrosaniyelik bir aralık belirtir.

      • -I eth0: Gönderenin ağ arayüzünü belirtmek için rand-dest ile birlikte kullanılır

      Alıcı örneğinde, dört kuyruğun paket sayıları eşit şekilde artmalıdır:

      image

    • Senaryo 2: Sabit kaynak IP adresi ve bağlantı noktasıyla trafik gönderin. Bu, aynı trafiğin aynı kuyruğa eşlenip eşlenmediğini test eder ve karma tutarlılığını doğrular.

      Aşağıdaki komut, kaynak IP'si 10.0.0.252 ve kaynak bağlantı noktası 12345 olarak sabitlenmiş şekilde, hedef 10.0.0.5:80 adresine 10.000 TCP SYN paketi gönderir.

      sudo hping3 10.0.0.5 -S -p 80 -c 10000 -s 12345 -a 10.0.0.252 --keep -i u100
      • Karma indeks değeri RSS betiği kullanılarak hesaplanır. Trafiğin kuyruk 0 tarafından işlenmesi beklenir:

        image

      • Alıcı ECS örneğinde (10.0.0.5) gözlemlenen gerçek sonuç:

        image

  5. Trafik dağıtımı beklentileri karşılamıyorsa (örneğin, bir kuyruğun yükü belirgin şekilde yüksekse), karma anahtarını ayarlayarak veya dolaylı tabloyu yapılandırarak optimizasyon yapın.

DPDK'da RSS'i Yapılandırma ve Kullanma

Data Plane Development Kit (DPDK), kullanıcı modu sürücüleri, sıfır kopyalama ve yoklama modu kullanarak neredeyse hat hızında paket işlemeyi sağlayan açık kaynaklı bir kullanıcı modu veri düzlemi hızlandırma çerçevesidir. Telekom cloud, fintech ve uç bilişim gibi aktarım hızı ve gecikme süresine duyarlı alanlar için uygundur. Bkz. Data Plane Development Kit (DPDK*).

ENI'de özel RSS'i etkinleştirdikten sonra, RSS dağıtımını test etmek ve doğrulamak için DPDK'da testpmd ve l3fwd kullanabilirsiniz.

Bir ECS Örneğinde DPDK'yı Yükleme ve Yapılandırma

Not
  • Özel RSS özelliğini bir DPDK uygulamasında kullanıyorsanız, DPDK sürümü 21,11 veya üzeri olmalıdır.

  • Bu konuda, DPDK sürümü 22.11.3 kurulumunu göstermek için Alibaba Cloud Linux 3.2104 LTS 64-bit görüntüsü çalıştıran ecs.r9i.16xlarge örneği (64 kuyruk) örnek olarak kullanılmıştır.

  • Bu örnekte birincil ENI eth0 kullanılmaktadır. Karşılık gelen ikincil ENI için RSS'i değiştirmek üzere arayüz tanımlayıcısını eth1 veya eth2 ile değiştirin.

Adım 1: DPDK'yı Yükleme

DPDK'yı yüklemek için örnek adımları görüntülemek için tıklayın

  1. Sistemi güncelleyin ve temel araçları yükleyin.

    sudo yum update -y
    sudo yum install -y git wget gcc make kernel-devel-$(uname -r) numactl-devel python3 pciutils
  2. DPDK bağımlılıklarını yükleyin.

    sudo yum install -y libpcap-devel meson ninja-build
  3. Dev sayfaları yapılandırın.

    • DPDK, çekirdek protokol yığınını atlayarak ENI'yi doğrudan işletir. TLB hatalarını azaltmak ve bellek erişim hızını artırmak için 4 KB sayfalar yerine dev sayfaları (genellikle 2 MB) kullanır.

    • Çok sayıda dev sayfası ayırmak, işletim sistemi için kullanılabilir normal belleği azaltır. Bu durum, diğer uygulamaların veya sistem hizmetlerinin başarısız olmasına neden olabilir. Aşırı tahsis ayrıca örnek bağlantısını engelleyebilir.

    • Uygulamanızın bellek ihtiyaçlarına göre gerekli dev sayfası sayısını hesaplayın.

      Dev sayfası sayısı = Uygulama belleği / Sayfa boyutu. Varsayılan sayfa boyutu 2 MB'tır. Örneğin, 16 GB / 2 MB = 8192 sayfa.

    echo "vm.nr_hugepages = 8192" | sudo tee -a /etc/sysctl.conf
    sudo sysctl -p
  4. Dev sayfalar dizinini oluşturun ve bağlayın.

    sudo mkdir -p /dev/hugepages
    sudo mount -t hugetlbfs hugetlbfs /dev/hugepages
  5. DPDK kaynak kodunu indirin. İnternet bağlantısı gereklidir.

    cd ~
    wget https://fast.dpdk.org/rel/dpdk-22.11.3.tar.xz
    tar xf dpdk-22.11.3.tar.xz
    cd dpdk-stable-22.11.3
  6. DPDK'yı derleyin.

    # Initialize the build directory and configure project options, specifying to build the l3fwd Layer 3 forwarding example.
    meson setup -Dexamples=l3fwd build
    cd build
    # Compile.
    ninja
    # Install the compiled files to the system directory.
    sudo ninja install
    # Update the system's shared library cache.
    sudo ldconfig

    Derleme sırasında aşağıdaki şekilde gösterilen missing python module: elftools hatasıyla karşılaşırsanız,

    image

    Python sürümünüzü belirtin, pyelftools yükleyin ve yeniden derleyin:

    sudo /usr/bin/python3.8 -m pip install pyelftools

Adım 2: Çekirdek Modüllerini Yükleme

DPDK, kullanıcı modu cihaz erişimi için UIO veya VFIO gibi çekirdek modülleri gerektirir. VFIO, güvenliği nedeniyle (IOMMU'ya dayanır) tercih edilir; UIO ise hızlı testler için uygundur. Bu örnekte VFIO kullanılmaktadır.

  1. IOMMU'yu etkinleştirin.

    VFIO, güvenli kullanıcı modu cihaz bağlama ve DMA eşlemesi için IOMMU'ya dayanır.

    1. Dosyayı açın.

      sudo vim /etc/default/grub
    2. Ekleme moduna girmek için i tuşuna basın. GRUB_CMDLINE_LINUX parametresine intel_iommu=on ekleyin. Dosyayı kaydedin ve kapatın.

      Değiştirilen yapılandırmaya örnek:

      GRUB_TIMEOUT=1
      GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
      GRUB_DEFAULT=saved
      GRUB_DISABLE_SUBMENU=true
      GRUB_TERMINAL_OUTPUT="console"
      GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet idle=halt biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0.115200n8 noibrs intel_iommu=on"
      GRUB_DISABLE_RECOVERY="true"
    3. Yapılandırmayı uygulayın.

      sudo grub2-mkconfig -o /boot/grub2/grub.cfg
      [test@iZ2ze9h6rn          ~]$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
      Generating grub configuration file ...
      Found linux image: /boot/vmlinuz-4.19.91-27.4.al7.x86_64
      Found initrd image: /boot/initramfs-4.19.91-27.4.al7.x86_64.img
      Found linux image: /boot/vmlinuz-0-rescue-2cea6e3dd20d4251bf6880159559f2c9
      Found initrd image: /boot/initramfs-0-rescue-2cea6e3dd20d4251bf6880159559f2c9.img
      done
    4. Örneği yeniden başlatın ve başladıktan sonra yeniden bağlanın.

      reboot
      Uyarı

      Yeniden başlatma işlemi örneği kısa bir süre durdurur ve örnekte çalışan hizmetleri kesintiye uğratabilir. Örneği yoğun saatler dışında yeniden başlatmanızı öneririz.

  2. VFIO ve VFIO-PCI sürücülerini yükleyin.

    sudo modprobe vfio && \
    sudo modprobe vfio-pci
  3. noiommu_mode özelliğini etkinleştirin.

    sudo bash -c 'echo 1 > /sys/module/vfio/parameters/enable_unsafe_noiommu_mode'

Adım 3: ENI'yi DPDK Sürücüsüne Bağlama

  1. ENI'de özel RSS'i etkinleştirin.

    DPDK'nin devralacağı ENI için özel RSS'in etkin olduğundan ve değişikliğin etkili olması için ENI'nin yeniden eklendiğinden emin olun.

  2. VNC kullanarak bir örneğe bağlanın.

  3. PCI cihaz sürücüsü bağlama durumunu görüntüleyin. Varsayılan olarak, ENI çekirdek tarafından yönetilir.

    dpdk-devbind.py --status

    image

    • 0000:00:05.0 cihazı virtio-pci çekirdek sürücüsü tarafından yönetilir ve eth0 etkindir.

    • Cihaz, DPDK kullanıcı modu devralma işlemi için vfio-pci olarak değiştirilebilir. Önce arayüzü devre dışı bırakın ve çekirdek sürücüsünü ayırın.

  4. eth0'ı devre dışı bırakın.

    sudo ip link set dev eth0 down

    Bu adımı atlarsanız, VFIO'ya bağlama başarısız olur:

    image

  5. Çekirdek sürücüsünün bağını kaldırın ve VFIO'ya bağlayın.

    dpdk-devbind.py -b vfio-pci 0000:00:05.0

    PCI cihaz tanımlayıcısını ENI'niz için sorguladığınız tanımlayıcıyla değiştirin.

    Not

    Çekirdek sürücüsünü yeniden bağlamak için, DPDK uygulamasını sudo pkill dpdk-app ile durdurun ve dpdk-devbind.py -b virtio-pci 0000:00:05.0 komutunu çalıştırın.

  6. PCI cihaz sürücüsü bağlama durumunu tekrar görüntüleyin. ENI artık DPDK tarafından devralınmış olmalıdır.

    Önemli

    ENI, DPDK kullanıcı modu sürücüsü tarafından devralındığında, çekirdek artık onu kontrol etmez. ip a gibi komutlar bilgilerini görüntüleyemez.

    dpdk-devbind.py --status

    image

    0000:00:05.0 cihazı artık vfio-pci ile bağlıdır.

testpmd Kullanarak RSS Yapılandırma

Testpmd, ENI sürücüsü özelliklerini doğrulamak ve veri düzlemi uygulamalarında hata ayıklamak için kullanılan bir DPDK test aracıdır. Bkz. Testpmd Çalışma Zamanı İşlevleri.

Önemli

ENI yapılandırmasındaki değişiklikler (kuyruk sayısı, RSS kuralları, RETA tablosu) yalnızca paket iletimi başlatıldıktan veya yeniden başlatıldıktan sonra etkili olur.

  1. VNC kullanarak bir örneğe bağlanın.

  2. DPDK testpmd paket iletimi test aracını başlatın.

    dpdk-testpmd -a 0000:00:05.0 --socket-mem 1024 -- -i --portmask=0x1 --rxq=64 --txq=64  --forward-mode=rxonly
    • -a 0000:00:05.0: PCI adresi 0000:00:05.0 olan ENI'yi DPDK'ya ekler. PCI adresini bulmak için dpdk-devbind.py --status komutunu çalıştırın.

    • --socket-mem 1024: NUMA düğümü başına 1024 MB dev sayfa belleği önceden tahsis eder.

    • -i: Yapılandırmayı dinamik olarak ayarlamak ve istatistikleri görüntülemek için etkileşimli komut satırı modunu başlatır. Çıkmak için quit girin.

    • --portmask=0x1: Port maskesi 0x1 (ikili 0001) etkinleştirir; yalnızca ilk ENI'yi (PCI adresi 0000:00:05.0) kullanır.

      • portmask değerinin her ikili biti bir porta karşılık gelir (0x1 port 0'ı, 0x3 port 0 ve 1'i etkinleştirir).

      • Yalnızca bir cihaz (0000:00:05.0) eklendiğinden, DPDK port numarası 0'dır.

    • --rxq=64 / --txq=64: Çoklu kuyruk işlemesi için port başına RX ve TX kuyruk sayısını 64 olarak ayarlar. 64 değerini gerçek ENI kuyruk sayısı ile değiştirin.

    • --forward-mode=rxonly: Yalnızca alma modu (paketler alınır ve atılır). ENI alma performansını test etmek veya paket yakalamak için kullanılır.

  3. Etkileşimli moda girin ve geçerli RSS yapılandırmasını sorgulayın.

    • Karma yapılandırma bilgilerini sorgulama: show port info <port_id>

      port_id: Porttur. Bu örnekte port 0'dır.

      Örnek çıktıyı görüntülemek için tıklayın

      image

    • Karma anahtarını sorgulama: show port <port_id> rss-hash key

      image

    • Dolaylı tablo yapılandırmasını sorgulama: show port <port_id> rss reta <size> <mask0, mask1...>

      • size: Sorgulanacak dolaylı tablo girişi sayısıdır. Değer sabit olarak 128 olarak ayarlanmıştır.

      • mask0, mask1: Görüntülenecek karma indeks aralığını filtrelemek için kullanılan ve onaltılık biçimde belirtilen maskelerdir. Örneğin, mask0=0xff değeri, 0 ile 7 arasındaki karma indeksleri için girişlerin görüntülendiğini gösterir.

        Dolaylı tablo boyutu sabit olarak 128'dir. Her biri 64 indeks bloğunu kapsayan iki maske gereklidir. Tüm 128 indeks-kuyruk eşleştirmelerini döndürmek için show port 0 rss reta 128 (0xffffffffffffffff,0xffffffffffffffff) komutunu çalıştırın:

        Örnek çıktıyı görüntülemek için tıklayın

        image

  4. Gereksinimlerinize göre RSS'i yapılandırın.

    • Yeni bir karma anahtarı yapılandırın.

      OpenSSL ile yeni bir rastgele anahtar oluşturun.

      port config <port_id> rss-hash-key (ipv4|ipv4-frag|\
                        ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|\
                        ipv6|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|\
                        ipv6-other|l2-payload|ipv6-ex|ipv6-tcp-ex|\
                        ipv6-udp-ex <string of hex digits \
                        (variable length, NIC dependent)>)

      IPv4 üzerinden TCP için, port config 0 rss-hash-key ipv4 6D5A56DA255B0EC24167253D43A38FB0D0CA2BCBAE7B30B477CB2DA38030F20C6A42B73BBEAC01FC komutunu çalıştırarak karma anahtarını yapılandırın ve doğrulayın:

      image

    • Karma değerlerini belirtilen kuyruklara eşlemek için RSS dolaylı tablosunu yapılandırın.

      port config all rss reta <hash,queue>,<hash,queue>..

      Gerçek kuyruk sayısına göre yapılandırın:

      • hash: Karma indeksi. Aralık, dolaylı tablo boyutuna bağlıdır (örneğin, 64 giriş için 0-63).

      • queue: Hedef alma kuyruğu numarası.

l3fwd'de RSS Uygulama

Bir DPDK uygulamasında RSS'i etkinleştirmek için, kodunuzda karma anahtarı ve dolaylı tablo yapılandırmasını uygulayın. Aşağıda L3FWD örnek olarak kullanılmıştır.

L3FWD (Katman 3 Yönlendirme), sıfır kopyalama ve Yoklama Modu Sürücüleri (PMD'ler) kullanarak yüksek performanslı IP tabanlı paket yönlendirmeyi gösteren bir DPDK örnek uygulamasıdır.

  1. DPDK'daki L3FWD kaynak kodunu (examples/l3fwd/main.c) değiştirin.

    • L3FWD örnek kodunda static struct rte_eth_conf port_conf port başlatma bölümünü değiştirin.

      Kod değişikliğini görüntülemek için tıklayın

      #define RSS_HASH_KEY_LENGTH 	40
      #define RSS_RETA_SIZE 			128
      
      static uint8_t hash_key[RSS_HASH_KEY_LENGTH] = {
          0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
          0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
          0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
          0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
      };
      
      static struct rte_eth_conf port_conf = {
      	.rxmode = {
      		.mq_mode = RTE_ETH_MQ_RX_RSS,
      		.offloads = RTE_ETH_RX_OFFLOAD_UDP_CKSUM | RTE_ETH_RX_OFFLOAD_TCP_CKSUM,
      	},
      	.rx_adv_conf = {
      		.rss_conf = {
      			.rss_key = hash_key,
      			.rss_hf = RTE_ETH_RSS_IP,
      			.rss_key_len = RSS_HASH_KEY_LENGTH,
      		},
      	},
      	.txmode = {
      		.mq_mode = RTE_ETH_MQ_TX_NONE,
      	},
      };
    • Karma dolaylı tablosunu ve karma anahtarını yapılandırmak için işlevler ekleyin.

      Eklenen kodu görüntülemek için tıklayın

      /**
       * @brief Configure the RSS RETA (Redirection Table Array) for a given port.
       * 
       * @param port_id The ID of the port to configure.
       */
      
      void configure_rss_reta(uint16_t port_id) {
          struct rte_eth_rss_reta_entry64 reta_conf[RSS_RETA_SIZE / RTE_ETH_RETA_GROUP_SIZE];
          unsigned int i;
          uint16_t reta_size;
      	uint16_t nb_queues;
      	struct rte_eth_dev_info dev_info;
      
      	if (port_id >= RTE_MAX_ETHPORTS) {
              printf("port_id %d exceed max eth ports\n", port_id);
              return;
          }
      
          if (rte_eth_dev_info_get(port_id, &dev_info) != 0) {
      		printf("Failed to get device info for port %d\n", port_id);
      		return;
      	}
      
          reta_size = dev_info.reta_size;
          if (reta_size == 0) {
              printf("Device does not support RSS RETA configuration.\n");
              return;
          }
      
      	nb_queues = dev_info.nb_rx_queues;
      	if (nb_queues == 0) {
      		printf("port %d RX queues = 0\n", port_id);
      		return;
      	}
      
          // Initialize RETA table
          memset(reta_conf, 0, sizeof(reta_conf));
          for (i = 0; i < reta_size; i++) {
              reta_conf[i / RTE_ETH_RETA_GROUP_SIZE].reta[i % RTE_ETH_RETA_GROUP_SIZE] = (uint16_t)(i % nb_queues);
          }
      
          // Configure RETA table mask
          for (i = 0; i < reta_size; i += RTE_ETH_RETA_GROUP_SIZE) {
              reta_conf[i / RTE_ETH_RETA_GROUP_SIZE].mask = UINT64_MAX;
          }
      
      	// Update RSS RETA table to device
      	if (rte_eth_dev_rss_reta_update(port_id, reta_conf, reta_size) != 0) {
      		printf("Failed to update RSS RETA table for port %u\n", port_id);
      		return;
      	}
      }
      
      /**
       * @brief Configure the RSS hash key for a given port.
       * 
       * @param port_id The ID of the port to configure.
       */
      void configure_rss_hash_key(uint16_t port_id) {
          struct rte_eth_rss_conf rss_conf;
      
      	if (port_id >= RTE_MAX_ETHPORTS) {
              printf("port_id %d exceed max eth ports\n", port_id);
              return;
          }
      
          memset(&rss_conf, 0, sizeof(rss_conf));
          rss_conf.rss_key = hash_key;
          rss_conf.rss_key_len = sizeof(hash_key);
          
          // Update RSS hash key to device
          if (rte_eth_dev_rss_hash_update(port_id, &rss_conf) != 0) {
              printf("Failed to update RSS hash key for port %u\n", port_id);
      		return;
          }
      }
    • rte_eth_dev_start sonrasında yeni yapılandırma işlevlerini çağırın.

      main içindeki çağrı kodunu görüntülemek için tıklayın

      @@ -1472,12 +1576,15 @@ main(int argc, char **argv)
                      /* Start device */
      		ret = rte_eth_dev_start(portid);
      		if (ret < 0)
      			rte_exit(EXIT_FAILURE,
      				"rte_eth_dev_start: err=%d, port=%d\n",
      				ret, portid);
      				
      		configure_rss_reta(portid);
      		configure_rss_hash_key(portid);
  2. Kaynak kodunu değiştirdikten sonra L3FWD'yi yeniden derleyin.

    cd ~/dpdk-stable-22.11.3/
    rm -rf build
    # Initialize the build directory and configure project options, specifying to build the l3fwd Layer 3 forwarding example.
    meson setup -Dexamples=l3fwd build
    cd build
    # Compile.
    ninja
    # Install the compiled files to the system directory.
    sudo ninja install
    # Update the system's shared library cache.
    sudo ldconfig
  3. Port-kuyruk-çekirdek bağlamalarını belirtin ve L3FWD'yi başlatın.

    cd ~/dpdk-stable-22.11.3/build/examples
    ./dpdk-l3fwd --legacy-mem -a 0000:00:05.0 --socket-mem 1024 -- -p 0x1 --config="(PORT_ID, QUEUE_ID, LCORE_ID), (PORT_ID, QUEUE_ID, LCORE_ID), ..." --parse-ptype
    • --config: Her üçlü şunları belirtir:

      • PORT_ID: Port kimliği (0'dan başlar).

      • QUEUE_ID: Alma kuyruğu kimliği (0'dan başlar).

      • LCORE_ID: Mantıksal çekirdek kimliği (0'dan başlar).

    • Aşağıdaki örnekte iki çekirdek ve iki kuyruk kullanılmaktadır:

      ./dpdk-l3fwd --legacy-mem -a 0000:00:05.0 --socket-mem 1024 -- -p 0x1 --config="(0.0.0),(0.1.1)"  --parse-ptype
      • İlk üçlü (0,0,0): Mantıksal çekirdek 0 (lcore0), port 0'ın kuyruk 0'ını işler.

      • İkinci üçlü (0,1,1): Mantıksal çekirdek 1 (lcore1), port 0'ın kuyruk 1'ini işler.

      image

Hash İndeksini Hesaplamak için RSS Betiğini Kullanma

4-tuple ve karma anahtarı verildiğinde, bir paketin hangi alma kuyruğuna eşlendiğini hesaplamak için bu Python betiğini kullanın. Sonuç, belirli akışları belirtilen kuyruklara yönlendirmek için dolaylı tablo yapılandırmasına rehberlik eder.

** ali_ecs_rss_calc.py ** betik içeriğini görüntülemek için tıklayın

#!/usr/bin/python

import sys
import argparse
import re
import ipaddress

prog_name = sys.argv[0]
USAGE_EXAMPLE = """
Usage example:
    Calculate the Toeplitz hash of a packet sent from 1.2.3.4 to 1.2.3.5 with a source and destination
    port of 7000:

    - The hash key argument is required because the virtio-net driver creates a random hash key for all your NICs.

    $ {prog_name} -t 1.2.3.4 -T 7000 -r 1.2.3.5 -R 7000 -k 77:d1:c9:34:a4:c9:bd:87:6e:35:dd:17:b2:e3:23:9e:39:6d:8a:93:2a:95:b4:72:3a:b3:7f:56:8e:de:b6:01:97:af:3b:2f:3a:70:e7:04
    
    - If you want to calculate the RSS value of a packet whose protocol is not TCP or UDP, do not specify
      the source and destination ports. The script will calculate the hash value based on only the IP addresses.
      
    $ {prog_name} -t 1.2.3.4 -r 1.2.3.5 -k 77:d1:c9:34:a4:c9:bd:87:6e:35:dd:17:b2:e3:23:9e:39:6d:8a:93:2a:95:b4:72:3a:b3:7f:56:8e:de:b6:01:97:af:3b:2f:3a:70:e7:04
    
    - Use "--ipv6" to calculate the RSS value for IPv6 packets.
    
    $ {prog_name} -t 2001:250:250:250:250:250:250:1 -T 7000 -r 2001:250:250:250:250:250:250:2 -R 7000 -k 77:d1:c9:34:a4:c9:bd:87:6e:35:dd:17:b2:e3:23:9e:39:6d:8a:93:2a:95:b4:72:3a:b3:7f:56:8e:de:b6:01:97:af:3b:2f:3a:70:e7:04 --ipv6

    Note: Linux kernel 5.9 or later is required for hash function and key configuration support.
    
    Also, Linux kernels older than ANCK 5.10-018 had a bug where the default hash key shown by ethtool was not 
    the same as the one used by the device before any RSS configuration was manually changed. The script will print the
    correct hash value in this case if you do not specify the hash key during calculation.
""".format(prog_name = prog_name)

# The default key on instances for old alinux kernel(< ANCK 5.10-018) should be as below, not the one you get from "ethtool -x <nic_name>".
RSS_DEFAULT_KEY = [
	0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
	0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,
	0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
	0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,
	0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA,
]
# The default key on instances for new alinux kernel(>= ANCK 5.10-018) is randomly generated.

TOEPLITZ_KEY_SIZE = 128
BITS_IN_BYTE = 8

def circular_shift_key_one_left(key):
    """Performs a cyclic left shift of the entire key.
    To cyclically shift all 40 bytes, the function
    shifts bits between adjacent bytes one at a time."""

    l = len(key)
    return [ ((key[i] << 1) & 0xff) | ((key[(i + 1) % l] & 0x80) >> 7) for i in range(0, l) ]

def or_32msb_bits_of_key(key):
    return (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3]

def calculate_hash(rx_ip, rx_port, tx_ip, tx_port, initial_value, key):
    """Calculates the Toeplitz hash based on the provided parameters.
    Note: This implementation is specific to ENA and may not be
    compatible with the standard Toeplitz implementation."""

    hash_result = initial_value
    input_bytes = list()
    input_bytes += tx_ip + rx_ip + tx_port + rx_port

    for input_byte in input_bytes:
        for i in range(BITS_IN_BYTE):
            # is the (8 - i -1) bit set
            if (input_byte & (1 << (BITS_IN_BYTE - i - 1))):
                hash_result ^= or_32msb_bits_of_key(key)

            key = circular_shift_key_one_left(key)

    return hash_result

def ipv4_addr_type(str):
    """An argparse type function that transforms an
    IPv4 string into a list of integers."""
    if not re.match(r"^([0-9]{1,3}\.){3}[0-9]{1,3}$", str):
        raise argparse.ArgumentTypeError("The IP address must be in the format 1.2.3.4.")

    return [int(octet) for octet in str.split('.')]

def ipv6_addr_type(str):
    """An argparse type function that transforms an
    IPv6 string into a list of integers."""
    
    try:
        ip_str = ipaddress.IPv6Address(unicode(str))
    except ValueError as e:
        raise argparse.ArgumentTypeError("Invalid IPv6 address format: %s" % e)
    
    parts = ip_str.exploded.split(':')
    try:
        bytes_list = [int(part, 16) for part in parts]
        bytes_list = [(byte >> 8, byte & 0xff) for byte in bytes_list]
    except ValueError as e:
        raise argparse.ArgumentTypeError("Invalid IPv6 address format: %s" % e)
    
    return [item for sublist in bytes_list for item in sublist]

def toeplitz_key_type(str):
    """An argparse type function that transforms a
    Toeplitz key string into a list of hexadecimal values."""
    if not re.match(r"^([0-9a-zA-Z]{1,2}:){39}[0-9a-zA-Z]{1,2}$", str):
        raise argparse.ArgumentTypeError("The Toeplitz key format is invalid. It must be 40 hexadecimal values delimited by colons.")

    return [int(key_elem, 16) for key_elem in str.split(':')]

def main():

    parser = argparse.ArgumentParser(description='virtio-net Toeplitz hash calculator',
                                     formatter_class=argparse.RawDescriptionHelpFormatter,
                                     epilog=USAGE_EXAMPLE)

    parser.add_argument('-r', '--rx-ip', help='Receiving side IP', dest='rx_ip', nargs='?',
                        required=True, type=str)
    parser.add_argument('-R', '--rx-port', help='Receiving side port', dest='rx_port', nargs='?', type=int)
    parser.add_argument('-t', '--tx-ip', help='Transmitting side IP', dest='tx_ip', nargs='?', 
                        required=True, type=str)
    parser.add_argument('-T', '--tx-port', help='Transmitting side port', dest='tx_port', nargs='?', type=int)
    parser.add_argument('-k', '--toeplitz-key',
                        help='The Toeplitz key (only on instances that support changing it)',
                        dest='toeplitz_key', nargs='?', required=True, type=toeplitz_key_type)
    parser.add_argument('-i', '--ipv6',  action='store_true', help='Use IPv6 address type for IP arguments')

    args = parser.parse_args()

    if args.ipv6:
        rx_ip   = ipv6_addr_type(args.rx_ip)
        tx_ip   = ipv6_addr_type(args.tx_ip)
    else:
        rx_ip   = ipv4_addr_type(args.rx_ip)
        tx_ip   = ipv4_addr_type(args.tx_ip)
    
    if args.rx_port and args.tx_port:
        # "break" port number into two byte representation
        rx_port = [(args.rx_port & 0xff00) >> 8, args.rx_port & 0x00ff]
        tx_port = [(args.tx_port & 0xff00) >> 8, args.tx_port & 0x00ff]
    else:
        rx_port = tx_port = []
    
    key = args.toeplitz_key

    # calculate the hash with an initial value of 0
    hash = calculate_hash(rx_ip, rx_port, tx_ip, tx_port, 0, key)
    rss_table_entry_128 = hash % 128
    rss_table_entry_256 = hash % 256

    if args.ipv6:
        print("Sending traffic from [{}]:{} to [{}]:{}".format(args.tx_ip, args.tx_port, args.rx_ip, args.rx_port))
    else:
        print("Sending traffic from {}:{} to {}:{}".format(args.tx_ip, args.tx_port, args.rx_ip, args.rx_port))
    print("""The hash is calculated over the following fields:
    Source IP address
    Destination IP address""")
    if args.rx_port and args.tx_port:
        print("""    Source port
    Destination port""")
    print("Should result in the hash for all drivers:".ljust(50) + "{}".format(hex(hash)))
    print("RSS table entry (total length 128):".ljust(50) + "{}".format(rss_table_entry_128))
    print("RSS table entry (total length 256):".ljust(50) + "{}".format(rss_table_entry_256))
    return

if __name__ == '__main__':
    main()

Betik kullanımını görüntülemek için tıklayın

Betik kullanımını görüntüleyin: python ali_ecs_rss_calc.py -h.

image

Aşağıdaki örnekte, 64 kuyruğa sahip bir ENI'nin RSS yapılandırması kullanılmaktadır:

image

Aşağıdaki 5-tuple bilgilerini kullanarak betikle RSS karma değerini hesaplayın (değerleri ihtiyaca göre değiştirin).

  • Hedef IP adresi (-r): RSS yapılandırılmış alıcı örneğinin ENI'sinin IP adresi olan 10.0.0.1.

  • Kaynak IP adresi (-t): Gönderenin ENI'sinin IP adresi olan 10.0.0.251.

  • Hedef bağlantı noktası (-R): 26000

  • Kaynak bağlantı noktası (-T): 18042

  • Karma anahtarı: RSS dolaylı tablo yapılandırmasından edinin.

python ali_ecs_rss_calc.py -r 10.0.0.1 -t 10.0.0.251 -R 26000 -T 18042 -k 69:e8:7c:56:bf:03:9f:63:d7:c5:e5:96:b3:00:36:93:02:8c:d2:8f:cc:a9:00:65:fd:c8:94:71:5f:fd:c8:de:7a:30:a9:73:b3:33:0c:c6

Betik, toeplitz algoritmasını kullanarak karmayı hesaplar. Aşağıdaki sonuçta, sistem 128 uzunluğunda bir dolaylı tablo kullanmaktadır. 117 karma indeksi, paketin 117 indeksindeki kuyruğa eşlendiği anlamına gelir.

image

Dolaylı tabloyu görüntüleyin: 117 indeksi kuyruk 53'e eşlenir, bu nedenle paketler kuyruk 53 tarafından işlenir.

image