---
# System prepended metadata

title: Final Project SDN-Kube

---

# SOFTWARE DEFINE NETWORK 
Software Defined Networking (SDN) adalah sebuah pendekatan arsitektur jaringan yang memisahkan fungsi kontrol jaringan (control plane) dari fungsi pengiriman data (data plane). Fungsi kontrol kemudian dikelola secara terpusat melalui perangkat lunak, memungkinkan operator untuk mengontrol dan mengelola jaringan secara lebih fleksibel dan efisien. 

#### konsep Penting Terkait SDN: 
- Control Plane:
    Fungsi kontrol jaringan yang bertanggung jawab untuk          mengambil keputusan tentang bagaimana data dikirimkan dalam    jaringan. 
- Data Plane:
    Fungsi pengiriman data yang bertanggung jawab untuk         mengirimkan data sesuai dengan keputusan yang dibuat oleh     control plane. 
- Controller:
    Perangkat lunak atau perangkat keras yang mengontrol         control plane dan menerima instruksi dari aplikasi untuk       mengelola lalu lintas jaringan. 
- API (Application Programming Interface):
    Antarmuka yang digunakan oleh aplikasi untuk berkomunikasi    dengan controller dan mengelola jaringan. 
    
#### Manfaat dari SDN:
- Fleksibilitas dan Agilitas
- Otomatisasi
- Virtualisasi
- Scalability
- Penghematan Biaya

## Bab 1 : Set Up Tools
### 1. Mininet
Mininet adalah sebuah aplikasi emulasi jarngan berbasis light-weight Linux virtualiation yang memungkinkan kita mmebuat jaringan virtual lengkap dengan switch, router, dan host yang realistis dan berinteraksi dengan real kernel dan program lainnya

gunanya mininet ini adalah untuk meniru atau mensimulasikan jaringan komputer secara virtual, baik jaringan sederhana maupun jaringan kompleks. Ini memungkinkan pengguna untuk membuat, menguji, dan bereksperimen dengan berbagai topologi jaringan, protokol, dan aplikasi tanpa perlu perangkat keras fisik. 

:::info
:::spoiler **Mininet**
Langkah - langkah penginstalan
1. Install git
    :::success
    ```
    sudo apt update
    ```
    sudo apt ini untuk memperbarui daftar paket yang tersedia di sistem basis VM. 
    output:
    ![image](https://hackmd.io/_uploads/Skbtz7U61e.png)

    ```
    sudo apt install git -y
    ```
    untuk menginstall git secara otomatis.
    output:
    ![image](https://hackmd.io/_uploads/ryA47mLayx.png)
2. Cloning mininet
    :::success
    ```
    git clone https://github.com/mininet/mininet.git
    ```
    untuk mengunduh clone seluruh isi repository mininet dari github ke komputer.
    output:
    ![image](https://hackmd.io/_uploads/ByhaX78T1x.png)
3. Install mininet
    :::success
    ```
    mininet/util/install.sh -a
    ```
    untuk menginstall semua komponen yang ada di mininet secara lengkap.
    Output:
    ![image](https://hackmd.io/_uploads/H14kDXITye.png)
4. Mem-verifikasi mininet
    :::success
    ```
    sudo mn
    ```
    untuk menjalankan mininetnya.
    output:
    ![image](https://hackmd.io/_uploads/HyjlPBUTJl.png)
:::
## 2. Minikube 
Mininet adalah sebuah aplikasi emulasi jaringan berbasis virtualisasi ringan di Linux yang memungkinkan pengguna untuk membuat jaringan virtual yang lengkap dengan host, switch, router, dan lainnya, serta berinteraksi dengan kernel dan program lain. Ini digunakan untuk mensimulasikan kinerja jaringan yang kompleks, seperti Jaringan Terdefinisi Perangkat Lunak (SDN), dengan menggunakan perangkat lunak yang ada pada sistem operasi host. 

#### Emulator Jaringan:
Mininet memungkinkan pengguna untuk membuat model jaringan di perangkat lunak, bukan dengan hardware fisik. 
#### Virtualisasi Ringan:
Mininet menggunakan teknologi virtualisasi ringan, yang berarti tidak memerlukan mesin virtual penuh yang memakan banyak sumber daya seperti virtualisasi tradisional. 
#### Node Logis:
Mininet menciptakan node logis (host, switch, router) yang dapat saling terhubung untuk membentuk topologi jaringan. 
#### Interaksi dengan Real Kernel:
Mininet dapat berinteraksi dengan kernel dan program asli di sistem operasi host, sehingga simulasi lebih realistis. 
#### SDN dan OpenFlow:
Mininet banyak digunakan dalam riset dan pengembangan Jaringan Terdefinisi Perangkat Lunak (SDN) karena mendukung protokol OpenFlow yang merupakan dasar dari SDN. 
#### Simulasi Kinerja:
Mininet dapat digunakan untuk mensimulasikan kinerja jaringan, menguji berbagai topologi, dan mengevaluasi aplikasi jaringan. 
#### Open Source:
Mininet adalah perangkat lunak sumber terbuka, sehingga dapat diakses dan digunakan oleh siapa saja. 


:::success
:::spoiler **Minikube**
```
sudo apt update && sudo apt upgrade -y
```
untuk memperbarui repository dan mengupdate paket perangkat lunak.
- y nya untuk tidak menanyakan kembali.
![Screenshot 2025-04-30 235029](https://hackmd.io/_uploads/HycfluLgel.png)
![Screenshot 2025-04-30 235313](https://hackmd.io/_uploads/H1SWWOIllx.png)
![Screenshot 2025-04-30 235624](https://hackmd.io/_uploads/HklMb_Ilex.png)
> `Docker untuk depedensi untuk deployment.`

untuk mengelola dependensi dan mempermudah deployment aplikasi.
![Screenshot 2025-04-30 235739](https://hackmd.io/_uploads/ry1SW_Iele.png)
> Containerd sebagai komponen untuk menjalankan dan mengelola container dalam suatu sistem. Containerd ini yang digunakan untuk menjalankan Kubernetes, cenderung lebih cepat dibandingkan Docker dan sebagai standar untuk Kubernetes.

![Screenshot 2025-04-30 235759](https://hackmd.io/_uploads/SJEvZOUlgg.png)
:::

## 3. Ryu Controller
Ryu Controller adalah Pengendali jaringan berbasis perangkat lunak (SDN) terbuka yang dirancang untuk meningkatkan kelincahan jaringan dengan mempermudah pengelolaan dan penyesuaian penanganan lalu lintas.

#### Open Source:
Ryu adalah perangkat lunak open source yang dikembangkan oleh NTT, artinya kode sumbernya terbuka dan dapat diakses serta dimodifikasi oleh siapa saja. 

#### Fungsi:
Ryu berfungsi sebagai controller untuk mengelola dan mengontrol jaringan, termasuk mengatur bagaimana lalu lintas data diproses dan dialirkan melalui jaringan. 

#### Protokol yang Didukung:
Ryu mendukung beberapa protokol SDN, termasuk OpenFlow, Netconf, dan OF-config. 
#### Keunggulan:
Ryu memiliki komponen yang berguna untuk aplikasi SDN dan juga komponen yang dapat di-upgrade, sehingga dapat digunakan dalam berbagai lingkungan jaringan. 

:::info
:::spoiler **Ryu Controller**
```Markdown=
        #!/bin/bash

    echo "[INFO] Creating ConfigMap, Deployment, and Service for Ryu..."

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ryu-app
    data:
      startup.sh: |
        #!/bin/sh

        echo "[INFO] Installing dependencies..."
        apt-get update && apt-get install -y gcc libffi-dev libssl-dev python3-venv

        echo "[INFO] Creating Python virtual environment..."
        python -m venv /tmp/venv

        echo "[INFO] Installing Python packages..."
        /tmp/venv/bin/pip install --upgrade pip==20.2.4 setuptools==57.5.0
        /tmp/venv/bin/pip install ryu eventlet==0.30.2

        echo "[INFO] Starting Ryu controller with built-in simple_switch_13..."
        exec /tmp/venv/bin/ryu-manager --observe-links --ofp-tcp-listen-port 6653 ryu.app.simple_switch_13
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ryu-controller
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ryu
      template:
        metadata:
          labels:
            app: ryu
        spec:
          containers:
          - name: ryu
            image: python:3.9-slim
            command: ["/bin/sh"]
            args: ["-c", "/bin/sh /app/startup.sh"]
            volumeMounts:
            - name: ryu-app-volume
              mountPath: /app
              readOnly: true
            ports:
            - containerPort: 6653
            - containerPort: 6633
          volumes:
          - name: ryu-app-volume
            configMap:
              name: ryu-app
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: ryu-service
    spec:
      selector:
        app: ryu
      type: NodePort
      ports:
        - name: of-port
          protocol: TCP
          port: 6653
          targetPort: 6653
          nodePort: 30001
        - name: legacy-port
          protocol: TCP
          port: 6633
          targetPort: 6633
          nodePort: 30002
    EOF

    echo "[DONE] Deployment complete. You can check the pod logs with:"
    echo "kubectl logs -f deploy/ryu-controller"
```
:::success
:::spoiler **Penjelasan**
1. Pembungkus Skrip
    ```markdown=
        #!/bin/bash

        echo "[INFO] Creating ConfigMap, Deployment, and Service for Ryu..."

        cat <<EOF | kubectl apply -f -

    ```
    - `#!/bin/bash`, menandakan bahwa skrip ini dijalankan menggunakan Bash.
    - `echo`, Menampilkan informasi status ke terminal.
    - `cat <<EOF | kubectl apply -f -`, meuliskan dokumen YAML ke kubectl apply, artinya Kubernetes langsung membuat resource sesuai definisi YAML dibawahnya.
2. Configmap : Menyimpan File `startup.sh`
    ```markdown=
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ryu-app
    data:
      startup.sh: |
        #!/bin/sh

        echo "[INFO] Installing dependencies..."
        apt-get update && apt-get install -y gcc libffi-dev libssl-dev python3-venv

        echo "[INFO] Creating Python virtual environment..."
        python -m venv /tmp/venv

        echo "[INFO] Installing Python packages..."
        /tmp/venv/bin/pip install --upgrade pip==20.2.4 setuptools==57.5.0
        /tmp/venv/bin/pip install ryu eventlet==0.30.2

        echo "[INFO] Starting Ryu controller with built-in simple_switch_13..."
        exec /tmp/venv/bin/ryu-manager --observe-links --ofp-tcp-listen-port 6653 ryu.app.simple_switch_13

    ```
    - `Config ` digunakan untuk menyimpan file konfigurasi/script `startup.sh` yang akan dijalankan dalan container.
    - Menginstall beberapa dependansi ang diperlukan untuk Ryu (via `apt`)
    - Membuat virtual environment python agar lingkungan tetap bersih. 
    - Menginstall ryu dan eventlet (Eventlet digunakan untuk aplikasi jaringan seperti controller yang harus melayani banyak koneksi.).
    - Menjalankan Ryu Controller menggunakan script `ryu.app.simple_switch_13` di port 6653.
3. Deployment : Menjalankan Container
    ```markdown=
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: ryu-controller
        spec:
          replicas: 1
          selector:
            matchLabels:
              app: ryu
          template:
            metadata:
              labels:
                app: ryu
            spec:
              containers:
              - name: ryu
                image: python:3.9-slim
                command: ["/bin/sh"]
                args: ["-c", "/bin/sh /app/startup.sh"]
                volumeMounts:
                - name: ryu-app-volume
                  mountPath: /app
                  readOnly: true
                ports:
                - containerPort: 6653
                - containerPort: 6633
              volumes:
              - name: ryu-app-volume
                configMap:
                  name: ryu-app

    ```
    - Deployment adalah cara kubernetes menjalankan dan menjadi agar Pod tetap berjalan.
    - Menggunakan image dasar python:3.9-slim (mengapa pakai slim karena **python slim** karena ukurannya ringan dibandingkan **python:3.9**, ukurannya sekitar 40-50% ukurannya).
    - Script `startup.sh` dijalankan saat container mulai.
4. Service
    ```markdown=
    apiVersion: v1
    kind: Service
    metadata:
      name: ryu-service
    spec:
      selector:
        app: ryu
      type: NodePort
      ports:
        - name: of-port
          protocol: TCP
          port: 6653
          targetPort: 6653
          nodePort: 30001
        - name: legacy-port
          protocol: TCP
          port: 6633
          targetPort: 6633
          nodePort: 30002
    ```
    - Service bertugas menghubungkan lalu lintas dari luar ke Pod.
    - `type: Nodeport` membuka port i semua node worker.
    - Port yang dibuka 
        - 6653 --> 30001, port utama OpenFlow.
        - 6633 --> 30002, untuk OpenFlow Legacy (Openflow merupakan versi awal-awal dari protokol OpenFlow, terutama Openflow 1.0, yang menggunakan port TCP 6633.).
3. Output
    ```markdown=
    echo "[DONE] Deployment complete. You can check the pod logs with:"
    echo "kubectl logs -f deploy/ryu-controller"
    ```
    Memberi tahu user bahwa proses selesai.
:::
## 4. Wireshark
Wireshark adalah perangkat lunak analisis jaringan yang berfungsi untuk merekam dan menganalisis lalu lintas jaringan dalam waktu nyata. Dengan kata lain, Wireshark adalah alat untuk menangkap dan mengamati paket data yang berjalan di jaringan internet atau jaringan lokal. Wireshark digunakan untuk berbagai keperluan seperti pemecahan masalah jaringan, analisis protokol, dan pengujian keamanan. 
Lebih detailnya, Wireshark memiliki kemampuan:
#### Menangkap paket data:
Wireshark dapat menangkap semua jenis paket data yang berjalan di jaringan, termasuk paket data dari berbagai protokol seperti HTTP, TCP, UDP, dan banyak lagi. 
#### Menganalisis paket data:
Setelah paket data ditangkap, Wireshark memungkinkan pengguna untuk menganalisisnya dengan detail, termasuk melihat header paket, isi paket, dan informasi lainnya. 
#### Menampilkan informasi:
Wireshark menampilkan informasi tentang paket data secara visual dan mudah dibaca, termasuk tabel, grafik, dan diagram yang membantu pengguna memahami lalu lintas jaringan. 
#### Memecahkan masalah:
Wireshark dapat digunakan untuk memecahkan masalah jaringan seperti masalah koneksi, masalah kinerja, atau masalah keamanan. 
#### Menganalisis protokol:
Wireshark dapat digunakan untuk menganalisis protokol jaringan, termasuk protokol yang digunakan untuk komunikasi di jaringan. 
#### Pengujian keamanan:
Wireshark dapat digunakan untuk melakukan pengujian keamanan jaringan dan mendeteksi ancaman keamanan. 


:::info
:::spoiler **Wireshark**
1. Update dan upgrade `apt`
    ```markdown=
        sudo apt update && sudo apt upgrade
    ```
    untuk mengunduh informasi paket baru dan yang upgrade untuk memperbarui sistem 
2. Install wireshark
    ```markdown=
        sudo apt install wireshark -y
    ```
    untuk menginstall wireshark 
3. Verifikasi wireshark
    
    ```markdown=
        wireshark
    ```
    :::warning
    Hanya menuliskan **wireshark** pada terminal. 
:::

# Bab 2 - Skenario
SDN mempunyai banyak skenario atau use-case yang dapat diimplementasikan. Berikut beberapa kategori dan skenario SDN:
### 1. Traffic Engineering & Path Computation
Menentukan jalur optimal untuk tiap aliran berdasarkan metrik tertentu (delay, bandwidth, utilisasi). Beberapa skenario:
    - **Load Balancing**
    - **QoS (Quality of Service)**
    - MPLS-style path setup (constraint-based routing)
    - Dynamic path rerouting saat link gagal (fast failover)
    - Segment Routing

### 2. Network Virtualization & Slicing
Membagi infrastruktur fisik menjadi jaringan virtual terisolasi (slice), seperti VLAN tapi lebih fleksibel. Beberapa skenario:
    - Membuat beberapa slice jaringan logis di atas infrastruktur fisik yang sama (multi-tenant)
    - Virtual Network Functions (VNF) chaining untuk NFV (firewall → DPI → NAT)

### 3. Keamanan & Kontrol Akses
Menggunakan control pusat untuk mengelola kebijakan keamanan dan ACL (Access Control List) pada tiap aliran. Beberapa skenario:
    - Firewall terpusat (flow-based ACL)
    - Intrusion Detection System (IDS) / Intrusion Prevention System (IPS)
    - DDoS mitigation dengan deteksi anomali dan blokir otomatis

### 4. Monitoring, Telemetri & Analytics
Mengumpulkan dan menganalisis data trafik dan perform jaringan secara real-time. Beberapa skenario:
    - **Sniffing**
    - Flow statistics collection (sFlow, NetFlow over OpenFlow)
    - Network traffic visualization dashboard
    - Telemetri real-time untuk prediksi atau deteksi anomaly

### 5. Service Chaining & Orchestration
Mengurutkan dan orkestrasi VNF (Virtual Network Functions) supaya paket melewati suatu rangkaian layanan. Beberapa skenario:
    - Mengurutkan service (misal: enkripsi → kompresi → inspeksi) secara dinamis
    - Integrasi dengan orchestrator (OpenStack Neutron, Kubernetes CNI)

### 6. Mobility & Wireless SDN
Menerapkan prinsip SDN pada jaringan wireless agar handover, channel assignment, dan resourece allocation terpusat. Beberapa skenario:
    - Seamless handover management (Wi-Fi atau seluler)
    - Dynamic channel assignment di wireless mesh

### 7. Energy-Aware Networking
Menghemat energi dengan mematikan atau menurunkan daya perangkat/switch/link yang idle. Beberapa skenario:
    - Mematikan link/switch yang idle untuk menghemat energi
    - QoS-aware wake-up berdasarkan beban trafik

### 8. Bandwidth on-Demand & Cloud Interconnect
Menyediakan dan menyesuaikan kapasitas jaringan antar DC atau ke cloud provider dengan API (Application Programming Interface). Beberapa skenario:
    - Autoscaling bandwidth antar data center sesuai kebutuhan aplikasi
    - API publik untuk request/teardown koneksi

### 9. Edge Computing & IoT
Mengatur trafik dan resource di edge node untuk aplikasi latency-sensitive dan IoT. Beberapa skenario:
    - Routing dinamis untuk IoT gateway based on latency
    - Pengaturan prioritas trafik sensor vs. actuator

### 10. Programmable WAN/LAN
Menggabungkan berbagai koneksi melalui program dan otomasi jaringan enterprise. Beberapa skenario:
    - SD-WAN untuk menggabungkan beberapa koneksi (MPLS, broadband, LTE)
    - Automasi deployment VLAN/VXLAN

Dari sekian banyak skenario SDN, kami hanya mengimplementasikan beberapa skenario dasar SDN, yaitu **Load Balancing**, **Sniffing**, dan **QoS**.

</br>

## Skenario 1: Load Balancing
Load balancing merupakan suatu jaringan komputer yang menggunakan metode untuk mendistribusikan beban kerjaan pada dua atau lebih dari suatu koneksi jaringan secara seimbang agar pekerjaan dapat berjalan optimal.

Load Balancing dapat menggunakan dengan beberapa algoritma, antara lain:
- Agen Based
- Flow Based
- Round Robin

### Agen Based
Load Balancing dengan algoritma least connection menggunakan agen yang berfungsi mendistribusikan jumlah koneksi pada server.

### Flow Based
Load Balancing dengan algoritma least connection menggunakan flow yang tersimpan dijadikan sebagai parameter jumlah koneksi pada server.

### Round Robin
Load Balancing dengan algoritma round robin sebagai metode pemilihan server pada load balancing.

#### Multipath Load Balancing
Sebuah metode pengaturan traffic dengan mendistribusi dan membagi muatan secara adil di antara banyak rute dari sumber ke tujuan.

---

![image](https://hackmd.io/_uploads/Sy40a8uxgg.png)

1. Setup Mininet dan Ryu dengan topologi di atas dengan ketentuan:
    - Dalam skenario khusus ini, jika Host1 ingin mengirimkan paket ke Host2, maka akan dilakukan load balancing, **70%** dari traffic S1 akan diarahkan ke port 1 dan sisa **30%** akan diarahkan ke port 2. Begitu juga sebaliknya ketika Host2 ke Host1.
    - Lalu jika Host3 ingin mengirimkan paket ke Host4, maka akan dilakukan load balancing juga, **50%** dari traffic Switch3 akan diarahkan ke port 1 dan sisa **50%** akan diarahkan ke port 2. Begi juga sebaliknya ketika Host2 ke Host1.

2. Pembuktian
    - Lakukan test iperf **Host1** ke **Host2** untuk melakukan dump paket.
    - Lakukan test iperf **Host3** ke **Host4** untuk melakukan dump paket.
    - Lakukan cek stats menggunakan **ovs-ofctl**.

:::warning
:::spoiler **Skenario 1 Scripts**
- **Topologi**
    :::info
    ```
    from mininet.topo import Topo
    from mininet.net import Mininet
    from mininet.node import RemoteController
    from mininet.cli import CLI
    from mininet.link import TCLink
    from mininet.log import setLogLevel

    class LoadBalancingTopo(Topo):
        def build(self):
            # Tambah hosts
            h1 = self.addHost('h1', ip='10.0.0.1/24')
            h2 = self.addHost('h2', ip='10.0.0.2/24')
            h3 = self.addHost('h3', ip='10.0.0.3/24')
            h4 = self.addHost('h4', ip='10.0.0.4/24')

            # Tambah switches
            s1 = self.addSwitch('s1')  # Switch untuk H1
            s2 = self.addSwitch('s2')  # Switch untuk H4
            s3 = self.addSwitch('s3')  # Switch untuk H3
            s4 = self.addSwitch('s4')  # Switch untuk H2

            # Hubungkan host ke switch sesuai dengan permintaan
            self.addLink(h1, s1)
            self.addLink(h2, s4)
            self.addLink(h3, s3)
            self.addLink(h4, s2)

            # Inter-switch connections (middle mesh)
            self.addLink(s1, s2)  # s1 ke s2
            self.addLink(s1, s3)  # s1 ke s3
            self.addLink(s2, s4)  # s2 ke s4
            self.addLink(s3, s4)  # s3 ke s4

    def run():
        topo = LoadBalancingTopo()
        net = Mininet(topo=topo,
                  controller=lambda name: RemoteController(name, ip='10.0.0.4', port=6653),
                  link=TCLink)
        net.start()
        print("Testing connectivity...")
        net.pingAll()
        CLI(net)
        net.stop()

    if _name_ == '_main_':
        setLogLevel('info')
        run()
    ```    
    Host-Switch
    → H1 (Host 1) IP Address 10.0.0.1 yang terhubung dengan S1 (Switch 1).</br>
    → H2 (Host 2) IP Address 10.0.0.2 yang terhubung dengan S4 (Switch 4).</br>
    → H3 (Host 3) IP Address 10.0.0.3 yang terhubung dengan S3 (Switch 3).</br>
    → H4 (Host 4) IP Address 10.0.0.4 yang terhubung dengan S2 (Switch 2).</br>

    Switch-Switch
    → S1 (Switch 1) yang terhubung dengan S2 (Switch 2) dan S3 (Switch 3).</br>
    → S4 (Switch 4) yang terhubung dengan S2 (Switch 2) dan S3 (Switch 3).

</br>

- **Ryu**
    :::info
    ```
    from ryu.base import app_manager
    from ryu.controller import ofp_event
    from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
    from ryu.controller.handler import set_ev_cls
    from ryu.ofproto import ofproto_v1_3
    from ryu.lib.packet import packet, ethernet, ipv4, arp
    from ryu.lib import hub
    import itertools

    class LoadBalancer(app_manager.RyuApp):
        OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

        def _init_(self, *args, **kwargs):
            super(LoadBalancer, self)._init_(*args, **kwargs)
            self.mac_to_port = {}
            self.datapaths = {}
            self.monitor_thread = hub.spawn(self._monitor)

            # Konfigurasi virtual IP dan backends
            self.virtual_ip = '10.0.0.100'
            self.virtual_mac = 'aa:bb:cc:dd:ee:ff'
            self.backends = {
                '10.0.0.2': {'mac': '00:00:00:00:00:02', 'port': 2},
                '10.0.0.3': {'mac': '00:00:00:00:00:03', 'port': 3},
            }

            # Round-robin iterator untuk backend
            self.backend_iter = itertools.cycle(self.backends.items())

        def _monitor(self):
            while True:
                for dp in self.datapaths.values():
                    self._request_stats(dp)
                hub.sleep(5)

        def _request_stats(self, datapath):
            parser = datapath.ofproto_parser
            req = parser.OFPFlowStatsRequest(datapath)
            datapath.send_msg(req)

        @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
        def flow_stats_reply_handler(self, ev):
            for stat in ev.msg.body:
                self.logger.info("Flow stats: %s", stat)

        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
        def switch_features_handler(self, ev):
            datapath = ev.msg.datapath
            parser = datapath.ofproto_parser
            ofproto = datapath.ofproto

            self.logger.info("Switch connected: datapath_id=%s", datapath.id)

            # Flow default ke controller
            match = parser.OFPMatch()
            actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]
            self.add_flow(datapath, 0, match, actions)

            # Flow untuk komunikasi ARP dan IP Traffic antar host
            match = parser.OFPMatch(eth_type=0x0806)  # ARP untuk IP lokal
            actions = [parser.OFPActionOutput(ofproto.OFPP_FLOOD)]  # Flood ARP request ke semua port
            self.add_flow(datapath, 10, match, actions)

            # Flow untuk komunikasi IP antar host (tanpa controller)
            match = parser.OFPMatch(eth_type=0x0800)  # Semua paket IP
            actions = [parser.OFPActionOutput(ofproto.OFPP_FLOOD)]  # Flood IP traffic antar host
            self.add_flow(datapath, 20, match, actions)

        def add_flow(self, datapath, priority, match, actions, idle_timeout=60, hard_timeout=0):
            parser = datapath.ofproto_parser
            ofproto = datapath.ofproto

            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
            mod = parser.OFPFlowMod(datapath=datapath,
                                    priority=priority,
                                    match=match,
                                    instructions=inst,
                                    idle_timeout=idle_timeout,
                                    hard_timeout=hard_timeout)
            datapath.send_msg(mod)

        @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
        def packet_in_handler(self, ev):
            msg = ev.msg
            datapath = msg.datapath
            parser = datapath.ofproto_parser
            ofproto = datapath.ofproto
            in_port = msg.match['in_port']

            pkt = packet.Packet(msg.data)
            eth = pkt.get_protocol(ethernet.ethernet)
            if eth is None:
                return

            arp_pkt = pkt.get_protocol(arp.arp)
            ip_pkt = pkt.get_protocol(ipv4.ipv4)

            # Handle ARP request untuk virtual IP
            if arp_pkt and arp_pkt.opcode == arp.ARP_REQUEST and arp_pkt.dst_ip == self.virtual_ip:
                self.logger.info("Received ARP request for virtual IP")
                self.reply_arp(datapath, arp_pkt, in_port)
                return

            # Handle trafik yang ditujukan ke virtual IP
            if ip_pkt and ip_pkt.dst == self.virtual_ip:
                # Pilih backend berdasarkan round-robin
                selected_ip, backend = next(self.backend_iter)

                self.logger.info("Routing traffic to backend: %s", selected_ip)

                match = parser.OFPMatch(
                    in_port=in_port,
                    eth_type=0x0800,
                    ipv4_dst=self.virtual_ip,
                    ipv4_src=ip_pkt.src
                )

                actions = [
                    parser.OFPActionSetField(ipv4_dst=selected_ip),
                    parser.OFPActionSetField(eth_dst=backend['mac']),
                    parser.OFPActionOutput(backend['port'])
                ]

                self.add_flow(datapath, 10, match, actions, idle_timeout=30)

                out = parser.OFPPacketOut(
                    datapath=datapath,
                    buffer_id=ofproto.OFP_NO_BUFFER,
                    in_port=in_port,
                    actions=actions,
                    data=msg.data
                )
                datapath.send_msg(out)

        def reply_arp(self, datapath, arp_request, port):
            parser = datapath.ofproto_parser
            ofproto = datapath.ofproto

            ether = ethernet.ethernet(
                dst=arp_request.src_mac,
                src=self.virtual_mac,
                ethertype=0x0806
            )

            arp_reply = arp.arp(
                opcode=arp.ARP_REPLY,
                src_mac=self.virtual_mac,
                src_ip=self.virtual_ip,
                dst_mac=arp_request.src_mac,
                dst_ip=arp_request.src_ip
            )

            pkt = packet.Packet()
            pkt.add_protocol(ether)
            pkt.add_protocol(arp_reply)
            pkt.serialize()

            out = parser.OFPPacketOut(
                datapath=datapath,
                buffer_id=ofproto.OFP_NO_BUFFER,
                in_port=ofproto.OFPP_CONTROLLER,
                actions=[parser.OFPActionOutput(port)],
                data=pkt.data
            )
            datapath.send_msg(out)
    ```
    Script Ryu ini adalah load balancer SDN berbasis OpenFlow 1.3 yang menggunakan virtual IP (10.0.0.100) untuk mendistribusikan trafik ke dua backend server (10.0.0.2 dan 10.0.0.3) secara round-robin. Ia menangani permintaan ARP ke VIP dan mengganti tujuan IP/MAC ke backend saat menerima trafik ke VIP, lalu meneruskannya ke server yang dipilih.
:::

:::warning
:::spoiler **Skenario 1 Outputs**

![WhatsApp Image 2025-05-09 at 18.48.52_5fb7b2a2](https://hackmd.io/_uploads/SkiZ0vsxxe.jpg)
Host → Switch:
h1 → s1
h2 → s4
h3 → s3
h4 → s2

Antar Switch (mesh):
s1 ↔ s2
s1 ↔ s3
s2 ↔ s4
s3 ↔ s4
![WhatsApp Image 2025-05-09 at 18.48.52_c9710d88](https://hackmd.io/_uploads/SJ6z0Psxle.jpg)
iperf digunakan untuk mengukur bandwidth antara dua host dalam jaringan.
Command iperf dijalankan dua kali dari host yang berbeda:
h1 ke h2 → melalui IP 10.0.0.2
h3 ke h4 → melalui IP 10.0.0.4

![WhatsApp Image 2025-05-09 at 18.48.52_a0f2b2d1](https://hackmd.io/_uploads/r1jm0voxge.jpg)
sudo ovs-ofctl dump-flows s1
yang digunakan untuk melihat semua flow entries (aturan pemrosesan paket) yang telah diinstal pada switch Open vSwitch (dalam hal ini s1) oleh controller Ryu Anda.


![WhatsApp Image 2025-05-09 at 18.48.53_e43d2354](https://hackmd.io/_uploads/HJv3CDoxlx.jpg)
Host: Menambahkan 4 host virtual (h1–h4).
Switch: Menambahkan 4 switch virtual (s1–s4).
Link: Menghubungkan host dan switch serta antar-switch.
Contohnya:
h1 <-> s1 artinya host h1 dihubungkan ke switch s1.
s1 <-> s2 artinya switch s1 dihubungkan ke s2 


:::

</br>

## Skenario 2: Sniffing
Sniffing adalah metode penyadapan lalu lintas data pada suatu jaringan komputer. Aktivitas ini biasanya disalahgunakan oleh orang-orang yang tidak bertanggung jawab, seperti Hacker.

---

![image](https://hackmd.io/_uploads/HJMBZTYexe.png)

1. Setup Mininet dan Ryu dengan topologi di atas dengan ketentuan:
    - Dalam skenario kali ini, jika Host2 ingin mengirimkan paket ke Host1, ketika paket sampai Switch2, Switch2 akan menduplikasi paket tersebut dan melakukan forwarding ke port 3 (Hacker3).
    - Lalu jika Host1 ingin mengirim paket ke Host2, ketika paket sampai di Switch1, Switch1 akan menduplikasi paket tersebut dan melakukan forwarding ke port 3 (Hacker1) dan port 4 (Hacker2).

2. Pembuktian
    - Lakukan tes **iperf Host1 ke Host2** untuk melakukan dump paket.
    - Lakukan cek stat menggunakan **ovs-ofctl**.


:::warning
:::spoiler **Skenario 2 Scripts**
- **Topologi**
    :::info
    ```markdown=
    from mininet.topo import Topo

    class SniffTopo(Topo):
        def build(self):
            # Tambah switch
            s1 = self.addSwitch('s1')
            s2 = self.addSwitch('s2')

            # Tambah host
            h1 = self.addHost('h1')  # host1
            h2 = self.addHost('h2')  # host2
            h3 = self.addHost('h3')  # hacker1
            h4 = self.addHost('h4')  # hacker2
            h5 = self.addHost('h5')  # hacker3

            # Urutan link memengaruhi penomoran port

            # Switch s2
            self.addLink(s2, s1, port1=1, port2=1)  # s2-eth1
            self.addLink(s2, h1, port1=2, port2=1)  # s2-eth2
            self.addLink(s2, h5, port1=3, port2=1)  # s2-eth3

            # Switch s1
            self.addLink(s1, h2, port1=2, port2=1)  # s1-eth2
            self.addLink(s1, h3, port1=3, port2=1)  # s1-eth3
            self.addLink(s1, h4, port1=4, port2=1)  # s1-eth4

    topos = {'snifftopo': (lambda: SniffTopo())}
    ```
    → H1 (Host 1) port 1 terhubung dengan S2 (Switch 2) port 2.
    → H2 (Host 2) port 1 terhubung dengan S1 (Switch 1) port 2.
    → H3 (Host 3 / hacker1) port 1 dengan S1 (Switch 1) port 3.
    → H4 (Host 4 / hacker2) port 1 dengan S1 (Switch 1) port 4.
    → H5 (Host 5 / hacker3) port 1 dengan S2 (Switch 2) port 3.
    → S2 (Switch 2) port 1 terhubung dengan S1 (Switch 1) port 1.
    

</br>

- **Ryu**
    :::info
    ```markdown=
    from ryu.base import app_manager
    from ryu.controller import ofp_event
    from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER, set_ev_cls
    from ryu.ofproto import ofproto_v1_3
    from ryu.lib.packet import packet, ethernet

    class SniffingController(app_manager.RyuApp):
        # Menentukan versi OpenFlow yang digunakan oleh controller ini
        OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

        def _init_(self, *args, **kwargs):
            # Konstruktor untuk inisialisasi controller
            super(SniffingController, self)._init_(*args, **kwargs)
            # Menyimpan mapping MAC address ke port switch
            self.mac_to_port = {}

        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
        def switch_features_handler(self, ev):
            # Menangani event ketika switch baru terhubung
            datapath = ev.msg.datapath
            parser = datapath.ofproto_parser
            ofproto = datapath.ofproto

            # Install table-miss flow entry yang mengarah ke controller
            match = parser.OFPMatch()
            actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]
            self.add_flow(datapath, 0, match, actions)

        def add_flow(self, datapath, priority, match, actions):
            # Fungsi untuk menambahkan flow entry ke switch
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser

            # Instruksi untuk menerapkan aksi yang ditentukan pada flow
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                        match=match, instructions=inst)
            datapath.send_msg(mod)

        @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
        def _packet_in_handler(self, ev):
            # Menangani event ketika ada paket yang masuk ke controller
            msg = ev.msg
            datapath = msg.datapath
            dpid = datapath.id
            parser = datapath.ofproto_parser
            ofproto = datapath.ofproto

            # Mengambil informasi Ethernet dari paket yang diterima
            pkt = packet.Packet(msg.data)
            eth = pkt.get_protocol(ethernet.ethernet)

            # Mendapatkan alamat tujuan dan sumber
            dst = eth.dst
            src = eth.src
            in_port = msg.match['in_port']

            # Menyimpan MAC address ke port
            self.mac_to_port.setdefault(dpid, {})
            self.mac_to_port[dpid][src] = in_port

            # Menentukan port keluar berdasarkan MAC address tujuan
            out_port = self.mac_to_port[dpid].get(dst, ofproto.OFPP_FLOOD)

            actions = []

            # Jika alamat tujuan ditemukan (tidak di flood), paket akan keluar melalui port tersebut
            if out_port != ofproto.OFPP_FLOOD:
                actions.append(parser.OFPActionOutput(out_port))

            # Logika sniffing berdasarkan dpid (ID switch):
            if dpid == 1:
                # Jika switch adalah S1, kita duplikasi paket yang menuju Host2 ke Hacker1 (port 3) dan Hacker2 (port 4)
                if out_port != 3:
                    actions.append(parser.OFPActionOutput(3))  # Menyalin ke Hacker1
                if out_port != 4:
                    actions.append(parser.OFPActionOutput(4))  # Menyalin ke Hacker2

            elif dpid == 2:
                # Jika switch adalah S2, kita duplikasi paket yang menuju Host1 ke Hacker3 (port 3)
                if out_port != 3:
                    actions.append(parser.OFPActionOutput(3))  # Menyalin ke Hacker3

            # Membuat pesan PacketOut untuk mengirimkan paket yang telah dimodifikasi
            out = parser.OFPPacketOut(datapath=datapath,
                                         buffer_id=ofproto.OFP_NO_BUFFER,
                                         in_port=in_port,
                                         actions=actions,
                                         data=msg.data)
            datapath.send_msg(out)
    ```
    sturktur penjelasan mengenai ryu script 
    - app_manager: Mengatur siklus hidup aplikasi Ryu.
    - ofp_event: Event-event OpenFlow (misalnya saat switch connect atau ada paket masuk).
    - set_ev_cls: Dekorator untuk mendaftarkan handler berdasarkan jenis event.
    - ofproto_v1_3: Mendukung protokol OpenFlow versi 1.3. packet, 
    - ethernet: Untuk parsing isi paket Ethernet.
    
    
    
    
    
    
    
:::

:::warning
:::spoiler **Skenario 2 Outputs**
Dalam skenario kali ini, jika Host2 ingin mengirimkan paket ke Host1, ketika paket sampai Switch2, Switch2 akan menduplikasi paket tersebut dan melakukan forwarding ke port 3 (Hacker3).
![WhatsApp Image 2025-05-06 at 13.17.21_4d7c33be](https://hackmd.io/_uploads/BJJ2kNPgle.jpg)
![WhatsApp Image 2025-05-06 at 13.17.21_5e01a153](https://hackmd.io/_uploads/Sk74eNvxeg.jpg)

- Masukkan perintah 
    ```markdown=
    sudo mn --custom sniff_toppology.py --topo snifftopo -controller=remote, ip=10.0.0.4,port=30001 --switch=ovsk
    ```
    - `--custom niff_topology.py` adalah script topologi yang akan dijalanakan.
    - `--topo snifftopo` adalah nama topo itu sendiri.
    - `--controller=remote, ip=10.0.0.4, port=30001` adalah me-remote dari vm ryu, dengan `ip vm ryu 10.0.0.4`, dam `port 30001`.
    - `--switch=ovsk`, menginstruksikan Mininet untuk menggunakan Open vSwitch (OVS) sebagai switch virtual
- Masukkan perintah dalam CLI mininet
         `mininet> h2 iperf -s &`
         - `-s` digunakan untuk menjalankan dalam mode server.
         - `simbol &` digunakan untuk menjalankan dibackground.
          
- Masukkan printah dalam CLI mininet
    `mininet> h1 iperf -c h2`
    - `-c`, h1 (mode client) mengirimkan data ke h2
        :::success
        - `-c` mode client;
        - `-s`, mode server;
        - `-t`, waktu yang dibutuhkan;
![WhatsApp Image 2025-05-06 at 13.17.21_53222d42](https://hackmd.io/_uploads/Bk3UeEPgeg.jpg) 

- Lakukan cek stat menggunakan `ovs-ofctl`.
![WhatsApp Image 2025-05-06 at 13.17.22_1d03dfbe](https://hackmd.io/_uploads/BJSdeVwxle.jpg)
:::

## Skenario 3: QoS (Quality of Sevice)

Quality of Service (QoS) di Kubernetes adalah sistem yang mengelola dan memprioritaskan alokasi sumber daya (CPU dan memori) di antara Pod, memastikan bahwa aplikasi penting mendapatkan sumber daya yang dibutuhkan dan sistem tetap stabil. Kubernetes membagi Pod menjadi tiga kelas QoS: Guaranteed (Dijamin), Burstable (Dapat Dilanggar), dan Best Effort (Upaya Terbaik). 

### Definisi
QoS di Kubernetes adalah mekanisme untuk menentukan bagaimana Pod mendapatkan sumber daya, terutama CPU dan memori, dalam kondisi persaingan. 

### Kelas QoS
- Guaranteed: Pod ini memiliki permintaan dan batas sumber daya yang sama. Jika permintaan dan batas sama, Kubernetes menjamin bahwa Pod selalu mendapatkan jumlah sumber daya yang dibutuhkan. 
- Burstable: Pod ini memiliki permintaan sumber daya yang lebih rendah daripada batasnya. Pod dapat menggunakan lebih banyak sumber daya jika tersedia, tetapi terbatas pada batas yang telah ditetapkan. 
- Best Effort: Pod ini tidak memiliki permintaan atau batas sumber daya. Pod dapat menggunakan sumber daya yang tersedia, tetapi tidak memiliki jaminan untuk mendapatkan sumber daya yang dibutuhkan. 

### Manfaat QoS
Jaminan Sumber Daya: QoS memastikan bahwa aplikasi penting selalu mendapatkan sumber daya yang diperlukan, bahkan dalam kondisi beban yang berat. 

Pengendalian Sumber Daya: QoS membantu mengelola sumber daya secara efektif dan mencegah satu Pod menghabiskan terlalu banyak sumber daya yang dibutuhkan oleh Pod lain. 

Penjadwalan dan Penghapusan: QoS memengaruhi bagaimana Pod dijadwalkan dan dihapus jika sistem kekurangan sumber daya. Pod dengan QoS yang lebih tinggi (seperti Guaranteed) memiliki prioritas yang lebih tinggi dalam penjadwalan dan akan dipertahankan lebih lama jika sumber daya terbatas. 

### Penggunaan
QoS digunakan untuk menjamin kinerja aplikasi, mengelola sumber daya secara efisien, dan memastikan stabilitas sistem. 

### Pentingnya QoS
Dalam lingkungan Kubernetes yang kompleks dengan banyak Pod dan beban kerja, QoS sangat penting untuk memastikan bahwa aplikasi dapat berjalan dengan baik dan sistem tetap stabil. 

---

![image](https://hackmd.io/_uploads/r1dEHXYgel.png)

1. Setup Mininet dan Ryu dengan topologi di atas dengan ketentuan:
    - Trafik dari Host1 ke Host3 (**VoIP**) → Diprioritaskan dengan queue berkecepatan tinggi.
    - Trafik dari Host2 ke Host4 (**HTTP**) → Diproses dengan queue berkecepatan lebih rendah.
    - Terapkan QoS dengan OVS Queue untuk memastikan VoIP mendapatkan bandwidth lebih besar dibanding HTTP.

2. Pembuktian QoS berjalan dengan benar
    - Gunakan **iperf** untuk melakukan uji trafik dan tunjukkan bahwa trafik prioritas tinggi mendapatkan bandwidth lebih besar dibanding trafik prioritas rendah.
    - Gunakan **Wireshark** untuk melihat bagaimana paket **diprioritaskan**.
    - **Bandingkan hasil pengujian dengan dan tanpa QoS.**

:::warning
:::spoiler **Skenario 3 Scripts**
- Topologi
    :::info
    ```markdown=
    from mininet.topo import Topo

    class QoSTopo(Topo):
        def __init__(self):
            Topo.__init__(self)

            # Add switches
            s1 = self.addSwitch('s1', protocols='OpenFlow13')
            s2 = self.addSwitch('s2', protocols='OpenFlow13')

            # Add hosts with MAC and IP
            h1 = self.addHost('h1', mac='00:00:00:00:00:01', ip='10.0.0.1/24')  # V>
            h2 = self.addHost('h2', mac='00:00:00:00:00:02', ip='10.0.0.2/24')  # H>
            h3 = self.addHost('h3', mac='00:00:00:00:00:03', ip='10.0.0.3/24')  # V>
            h4 = self.addHost('h4', mac='00:00:00:00:00:04', ip='10.0.0.4/24')  # H>

            # Add links
            self.addLink(h1, s1, port1=1, port2=1)  # h1 --> port 1 s1
            self.addLink(h2, s1, port1=1, port2=2)  # h2 --> port 2 s1
            self.addLink(s1, s2, port1=3, port2=1)  # s1 port3 --> s2 port 2
            self.addLink(h3, s2, port1=1, port2=2)  # h3 --> port 2 s2
            self.addLink(h4, s2, port1=1, port2=3)  # h4 --> port 3 s2

    topos = {'QoS_topo': (lambda: QoSTopo())}
    ```
    - H1 (Host 1) port 1 dengan IP Address 10.0.0.1 dan MAC Address 00:00:00:00:00:01 yang terhubung dengan S1 (Switch 1) port 1.</br>
    - H2 (Host 2) port 1 dengan IP Address 10.0.0.2 dan MAC Address 00:00:00:00:00:02 yang terhubung dengan S1 (Switch 1) port 2.</br>
    - S1 (Switch 1) port 3 terhubung dengan S2 (Switch 2) port 1 dimana keduanya sama-sama menggunakan protokol **OpenFlow13**.</br>
    - H3 (Host 3) port 1 dengan IP Address 10.0.0.3 dan MAC Address 00:00:00:00:00:03 yang terhubung dengan S2 (Switch 2) port 2.</br>
    - H4 (Host 4) port 1 dengan IP Address 10.0.0.4 dan MAC Address 00:00:00:00:00:04 yang terhubung dengan S2 (Switch 2) port 3.

</br>

- Ryu
    :::info
    ```markdown=
    from ryu.base import app_manager
    from ryu.controller import ofp_event
    from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER
    from ryu.controller.handler import set_ev_cls
    from ryu.ofproto import ofproto_v1_3
    from ryu.lib.packet import packet, ethernet, ipv4, tcp, udp


    class QoSController(app_manager.RyuApp):
        OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

        def __init__(self, *args, **kwargs):
            super(QoSController, self).__init__(*args, **kwargs)
            self.mac_to_port = {}

        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
        def switch_features_handler(self, ev):
            datapath = ev.msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser

            # Table-miss flow entry
            match = parser.OFPMatch()
            actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]
            self.add_flow(datapath, 0, match, actions)

        @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
        def _packet_in_handler(self, ev):
            msg = ev.msg
            datapath = msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
            in_port = msg.match['in_port']

            pkt = packet.Packet(msg.data)
            eth = pkt.get_protocol(ethernet.ethernet)

            if eth.ethertype == 0x88cc:
                return  # Ignore LLDP

            dpid = datapath.id
            self.mac_to_port.setdefault(dpid, {})
            self.mac_to_port[dpid][eth.src] = in_port

            out_port = self.mac_to_port[dpid].get(eth.dst, ofproto.OFPP_FLOOD)
            actions = []

            ip_pkt = pkt.get_protocol(ipv4.ipv4)

            if ip_pkt:
                if ip_pkt.proto == 17:  # UDP (VoIP)
                    actions.append(parser.OFPActionSetQueue(0))
                elif ip_pkt.proto == 6:  # TCP (HTTP)
                    actions.append(parser.OFPActionSetQueue(1))

            actions.append(parser.OFPActionOutput(out_port))

            if out_port != ofproto.OFPP_FLOOD:
                match = parser.OFPMatch(
                    in_port=in_port,
                    eth_type=0x0800,
                    ipv4_src=ip_pkt.src,
                    ipv4_dst=ip_pkt.dst,
                    ip_proto=ip_pkt.proto
                )
                self.add_flow(datapath, 1, match, actions)

            out = parser.OFPPacketOut(
                datapath=datapath,
                buffer_id=msg.buffer_id,
                in_port=in_port,
                actions=actions,
                data=msg.data if msg.buffer_id == ofproto.OFP_NO_BUFFER else None
            )
            datapath.send_msg(out)

        def add_flow(self, datapath, priority, match, actions):
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]

            mod = parser.OFPFlowMod(
                datapath=datapath,
                priority=priority,
                match=match,
                instructions=inst
            )
            datapath.send_msg(mod)
    ```
    Script Ryu ini mengimplementasikan tentang QoS (Quality of Service) sederhana yang memprioritaskan lalu lintas jaringan berbasis OpenFlow v1.3. Controller ini membagi bandwidth menjadi dua antrian prioritas: antrian 0 (80% bandwidth) untuk lalu lintas UDP/VoIP (prioritas tinggi) dan antrian 1 (20% bandwidth) untuk lalu lintas TCP/HTTP (prioritas rendah).
:::
    
:::warning
:::spoiler **Skenario 3 Outputs**
- Tanpa QoS
    :::danger
    :::spoiler **Tanpa QoS**
    - VoIP (UDP - High Priority)
    → Verifikasi
    ```markdown=
    mininet@vm-mininet:~$ sudo mn --custom qos_topology.py --topo QoS_topo --controller=remote,ip=10.0.0.4,port=30001
    /usr/local/bin/mn:4: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
      __import__('pkg_resources').run_script('mininet==2.3.1b4', 'mn')
    *** Creating network
    *** Adding controller
    *** Adding hosts:
    h1 h2 h3 h4
    *** Adding switches:
    s1 s2
    *** Adding links:
    (h1, s1) (h2, s1) (h3, s2) (h4, s2) (s1, s2)
    *** Configuring hosts
    h1 h2 h3 h4
    *** Starting controller
    c0
    *** Starting 2 switches
    s1 s2 ...
    *** Starting CLI:
    mininet> h3 iperf -s -u &
    mininet> h1 iperf -c h3 -u -b 10M
    ------------------------------------------------------------
    Client connecting to 10.0.0.3, UDP port 5001
    Sending 1470 byte datagrams, IPG target: 1121.52 us (kalman adjust)
    UDP buffer size:  208 KByte (default)
    ------------------------------------------------------------
    [  1] local 10.0.0.1 port 33022 connected with 10.0.0.3 port 5001
    [ ID] Interval       Transfer     Bandwidth
    [  1] 0.0000-10.0018 sec  12.5 MBytes  10.5 Mbits/sec
    [  1] Sent 8921 datagrams
    [  1] Server Report:
    [ ID] Interval       Transfer     Bandwidth        Jitter   Lost/Total Datagrams
    [  1] 0.0000-9.9913 sec  12.5 MBytes  10.5 Mbits/sec   0.006 ms 0/8920 (0%)
    [  1] 0.0000-9.9913 sec  5 datagrams received out-of-order
    mininet> exit
    *** Stopping 1 controllers
    c0
    *** Stopping 5 links
    .....
    *** Stopping 2 switches
    s1 s2
    *** Stopping 4 hosts
    h1 h2 h3 h4
    *** Done
    completed in 830.451 seconds
    ```
    
    → Hasil Dari simulasi menggunakan mininet dengan         menggunakan topologi khusus yang telah dirancang yang     menghubungkan 4 host (h1-h4) dan 2 switch (s1-s2).
    
    Setelah jaringan di jalankan, maka dilakukan             pengujian bandwidth antara h1 (client) dan h3             (server) menggunakan iperf dengan protokol UDP dengan     kecepatan 10Mbps.
    
    ![image](https://hackmd.io/_uploads/SJ3t9c9xgl.png)
    
    ![image](https://hackmd.io/_uploads/SyR0q59exx.png)
    → Diatas merupakan data yang diambil di Wiresharknya.
    </br>
    
    - HTTP (TCP - Low Priority)
    → Verifikasi
    ```markdown=
    mininet@vm-mininet:~$ sudo mn --custom qos_topology.py --topo QoS_topo --control                                                                                      ler=remote,ip=10.0.0.4,port=30001
    /usr/local/bin/mn:4: DeprecationWarning: pkg_resources is deprecated as an API.                                                                                       See https://setuptools.pypa.io/en/latest/pkg_resources.html
      __import__('pkg_resources').run_script('mininet==2.3.1b4', 'mn')
    *** Creating network
    *** Adding controller
    *** Adding hosts:
    h1 h2 h3 h4
    *** Adding switches:
    s1 s2
    *** Adding links:
    (h1, s1) (h2, s1) (h3, s2) (h4, s2) (s1, s2)
    *** Configuring hosts
    h1 h2 h3 h4
    *** Starting controller
    c0
    *** Starting 2 switches
    s1 s2 ...
    *** Starting CLI:
    mininet> h4 iperf -s &
    mininet> h2 iperf -c h4
    ------------------------------------------------------------
    Client connecting to 10.0.0.4, TCP port 5001
    TCP window size: 85.3 KByte (default)
    ------------------------------------------------------------
    [  1] local 10.0.0.2 port 35400 connected with 10.0.0.4 port 5001 (icwnd/mss/irt                                                                                      t=14/1448/6124)
    [ ID] Interval       Transfer     Bandwidth
    [  1] 0.0000-10.0156 sec  35.8 GBytes  30.7 Gbits/sec
    mininet> exit
    *** Stopping 1 controllers
    c0
    *** Stopping 5 links
    .....
    *** Stopping 2 switches
    s1 s2
    *** Stopping 4 hosts
    h1 h2 h3 h4
    *** Done
    completed in 1993.962 seconds
    ```
    
    → Hasil Dari simulasi menggunakan mininet dengan         menggunakan topologi khusus yang telah dirancang yang     menghubungkan 4 host (h1-h4) dan 2 switch (s1-s2).
    
    Setelah jaringan aktif, maka dilakukan                   pengujian bandwidth antara h2 (client) dan h4             (server) menggunakan iperf dengan protokol TCP.
    
    ![image](https://hackmd.io/_uploads/rk2Snq5lxl.png)
    
    
    ![image](https://hackmd.io/_uploads/BkvL2ccgll.png)
    → Diatas merupakan data yang diambil di Wiresharknya.

- Qos
    :::success
    :::spoiler **QoS**
    **1. H1 ke H3**
    ![WhatsApp Image 2025-05-09 at 23.18.06_be57a8c9](https://hackmd.io/_uploads/Skbj3jsglx.jpg)
    → Menjalankan perintah iperf, perintah yang pertama mininets h3 iperf -s -u & memulai server UDP pada host h3, lalu perintah yang kedua mininets h1 iperf -c h3 -u -b 10M mengirim traffic UDP dari host h1 ke h3 dengan bandwidth 10Mbps.
    ![WhatsApp Image 2025-05-09 at 23.23.33_201939f9](https://hackmd.io/_uploads/B1tihojegx.jpg)
    → Diatas merupakan Hasil ujicoba yang diambil pada         Wireshark dari H1 ke H3.
    
    **2. H2 ke H4**
    ![WhatsApp Image 2025-05-06 at 13.09.02_e760002d](https://hackmd.io/_uploads/B1UWhQPlge.jpg)
    → Menjalankan perintah iperf, perintah yang pertama h4 iperf -s -p 5002 & mengaktifkan server iperf pada host h4. Lalu perintah yang kedua h2 iperf -c h4 -p 5002 -b 2M -t 60 & mengirim traffic UDP dari host h2 ke h4 dengan bandwidth 2 Mbps selama 60 detik.
    ![WhatsApp Image 2025-05-06 at 13.09.02_cfcba822](https://hackmd.io/_uploads/rJk7h7vlle.jpg)
    ![WhatsApp Image 2025-05-06 at 13.09.01_373e279a](https://hackmd.io/_uploads/Byofh7vlxl.jpg)
    → Diatas merupakan Hasil ujicoba yang diambil pada         Wireshark dari H2 ke H4.
    
    3. Gunakan Wireshark untuk melihat bagaimana paket diprioritaskan.
    4. HTTP
    ![WhatsApp Image 2025-05-06 at 17.21.48_3aabe07f](https://hackmd.io/_uploads/Hyt2QPvglg.jpg)
    ![WhatsApp Image 2025-05-06 at 17.21.49_371a3bc9](https://hackmd.io/_uploads/S1R3XDvlgg.jpg)
    → Diatas merupakan data yang diambil di Wiresharknya.
:::