Understanding how a switch works in Go

Understanding how a switch works in Go

To better understand the operation of a network switch, we can create a simple simulation in Go.

In computer network management, switches play a crucial role. Unlike hubs, which send packets to all devices on the network, switches can send packets only to the specific destination device. This efficiency improvement is made possible through the use of the CAM (Content Addressable Memory) table, which maps MAC (Media Access Control) addresses to the switch ports.

Switches operate primarily at Layer 2 of the OSI model (Data Link Layer). Their task is to receive, process, and forward data packets between connected devices. Switches maintain a CAM table that stores the MAC addresses of connected devices and the physical ports they are associated with. When a packet arrives at a switch port, the source MAC address is recorded in the CAM table along with the ingress port. If the destination MAC address is already known, the switch sends the packet directly to the associated port. If it is not known, the switch performs flooding, sending the packet to all ports except the ingress port.

To better understand the operation of a network switch, we can create a simple simulation in Go. This example will show how a switch uses the CAM table to learn and forward packets based on MAC addresses.

The switch structure contains a map representing the CAM table. The map key is a MAC address and the value is the port number.


type Switch struct {
    camTable map[string]int // CAM addressing table
}

The LearnMacAddress method learns a MAC address by associating it with a specific port. It adds or updates the MAC address in the CAM table.


func (s *Switch) LearnMacAddress(macAddress string, port int) {
    s.camTable[macAddress] = port
    fmt.Printf("MAC %s learned on port %d\n", macAddress, port)
}

The ForwardFrame method simulates the frame forwarding process. It learns the source MAC address and looks up the destination MAC address in the CAM table. If the destination MAC address is found, the frame is forwarded to the corresponding port. If not found, the frame is flooded to all ports except the ingress port.


func (s *Switch) ForwardFrame(srcMac, dstMac string, port int) {
    s.LearnMacAddress(srcMac, port)
    if outPort, found := s.camTable[dstMac]; found {
        fmt.Printf("Forwarding frame from %s to %s via port %d\n", srcMac, dstMac, outPort)
    } else {
        fmt.Printf("Flooding frame from %s to %s to all ports except %d\n", srcMac, dstMac, port)
    }
}

The PrintCamTable method prints the current CAM table, showing which MAC addresses have been learned and to which ports they are associated.


func (s *Switch) PrintCamTable() {
    fmt.Println("\nCurrent CAM Table:")
    for mac, port := range s.camTable {
        fmt.Printf("MAC Address: %s -> Port: %d\n", mac, port)
    }
}

The GenerateMacAddress function generates a random MAC address using the uuid package.


func GenerateMacAddress() string {
    u := uuid.New()
    mac := strings.ToUpper(fmt.Sprintf("%02X:%02X:%02X:%02X:%02X:%02X", u[0], u[1], u[2], u[3], u[4], u[5]))
    return mac
}

Here is the complete example that integrates all the components:


package main

import (
    "fmt"
    "strings"
    "github.com/google/uuid"
)

type Switch struct {
    camTable map[string]int // CAM addressing table
}

func NewSwitch() *Switch {
    return &Switch{camTable: make(map[string]int)}
}

func (s *Switch) LearnMacAddress(macAddress string, port int) {
    s.camTable[macAddress] = port
    fmt.Printf("MAC %s learned on port %d\n", macAddress, port)
}

func (s *Switch) ForwardFrame(srcMac, dstMac string, port int) {
    s.LearnMacAddress(srcMac, port)
    if outPort, found := s.camTable[dstMac]; found {
        fmt.Printf("Forwarding frame from %s to %s via port %d\n", srcMac, dstMac, outPort)
    } else {
        fmt.Printf("Flooding frame from %s to %s to all ports except %d\n", srcMac, dstMac, port)
    }
}

func (s *Switch) PrintCamTable() {
    fmt.Println("\nCurrent CAM Table:")
    for mac, port := range s.camTable {
        fmt.Printf("MAC Address: %s -> Port: %d\n", mac, port)
    }
}

func GenerateMacAddress() string {
    u := uuid.New()
    mac := strings.ToUpper(fmt.Sprintf("%02X:%02X:%02X:%02X:%02X:%02X", u[0], u[1], u[2], u[3], u[4], u[5]))
    return mac
}

func main() {
    switchDevice := NewSwitch()

    srcMac1 := GenerateMacAddress()
    dstMac1 := GenerateMacAddress()
    srcMac2 := GenerateMacAddress()
    dstMac2 := GenerateMacAddress()
    srcMac3 := GenerateMacAddress()
    dstMac3 := GenerateMacAddress()

    switchDevice.ForwardFrame(srcMac1, dstMac1, 1)
    switchDevice.ForwardFrame(srcMac2, dstMac1, 2)
    switchDevice.ForwardFrame(srcMac3, dstMac2, 1)

    switchDevice.PrintCamTable()
}

Conclusion

This example demonstrates how a switch learns MAC addresses and uses the CAM table to forward frames to the correct ports, improving network efficiency. The Go simulation provides a practical representation of how network switches work, offering a solid foundation for understanding the fundamental concepts of MAC addressing and switching.