Skip to content

metric tie-breaking #28

Description

@github-actions

// TODO: metric tie-breaking


#include <net/arp.h>
#include <lock/lock.h>
#include <net/route.h>
#include <errors/errno.h>
#include <string.h>
#include <klog/klog.h>

static route_entry_t route_table[ROUTE_TABLE_SIZE];
static lock_t route_table_lock = LOCK_INITIALIZER("route_table");

void route_init(void)
{
    memset(route_table, 0, sizeof(route_table));
}

int route_add(uint32_t dest_network, uint32_t subnet_mask, uint32_t gateway,
              network_device_t* device, uint32_t metric, uint32_t flags)
{
    lock_acquire(&route_table_lock);

    // Find a free slot
    // scan route_table for an entry with ROUTE_FLAG_UP unset
    // If no free slot, unlock and return -ENOSPC
    // Fill in the entry fields and set ROUTE_FLAG_UP
    // If gateway is non-zero, also set ROUTE_FLAG_GATEWAY
    int free_slot = -1;
    for(int i = 0; i < ROUTE_TABLE_SIZE; i++)
    {
        route_entry_t* entry = &route_table[i];
        if((entry->flags & ROUTE_FLAG_UP) == 0)
        {
            free_slot = i;
            break;
        }
    }
    if(free_slot == -1)
    {
        lock_release(&route_table_lock);
        return -ENOSPC;
    }

    route_entry_t* entry = &route_table[free_slot];
    entry->dest_network = dest_network;
    entry->subnet_mask = subnet_mask;
    entry->gateway = gateway;
    entry->device = device;
    entry->metric = metric;
    entry->flags = flags | ROUTE_FLAG_UP | (entry->gateway ? ROUTE_FLAG_GATEWAY : 0);

    lock_release(&route_table_lock);
    return 0;
}

int route_remove(uint32_t dest_network, uint32_t subnet_mask)
{
    lock_acquire(&route_table_lock);

    // find matching entry (dest_network and subnet_mask both match)
    // Clear ROUTE_FLAG_UP (or memset the entry to 0)
    // If not found, unlock and return -ENOENT
    for(int i = 0; i < ROUTE_TABLE_SIZE; i++)
    {
        route_entry_t* entry = &route_table[i];
        if(entry->subnet_mask == subnet_mask && entry->dest_network == dest_network)
        {
            entry->flags &= ~ROUTE_FLAG_UP;
            lock_release(&route_table_lock);
            return 0;
        }
    }

    lock_release(&route_table_lock);
    return -ENOENT;
}

bool route_lookup(uint32_t dest_ip, route_result_t* result)
{
    lock_acquire(&route_table_lock);

    // Longest prefix match:
    // iterate all entries where ROUTE_FLAG_UP is set
    //   - Check if (dest_ip & entry->subnet_mask) == entry->dest_network
    //   - Track the match with the longest mask (most bits set = most specific)
    //   - On tie (same mask length), prefer lower metric
    //
    // If a match is found, fill result:
    //   - result->entry = best match
    //   - result->device = best->device
    //   - result->next_hop = best->gateway if ROUTE_FLAG_GATEWAY set,
    //                        otherwise dest_ip (on-link, ARP for destination directly)

    int best_match_weight = -1;
    int best_match = -1;
    for(int i = 0; i < ROUTE_TABLE_SIZE; i++)
    {
        route_entry_t* entry = &route_table[i];
        // skip entries that are not up
        if((entry->flags & ROUTE_FLAG_UP) == 0) continue;
        if((dest_ip & entry->subnet_mask) == entry->dest_network)
        {
            int mask_hamming_weight = __builtin_popcount(entry->subnet_mask);
            if(mask_hamming_weight > best_match_weight) {
                best_match = i;
                best_match_weight = mask_hamming_weight;
            }
            if(mask_hamming_weight == best_match_weight)
            {
                // TODO: metric tie-breaking
            }
        }
    }

    if(best_match == -1)
    {
        lock_release(&route_table_lock);
        return false;
    }

    result->entry = &route_table[best_match];
    result->device = route_table[best_match].device;
    if((route_table[best_match].flags & ROUTE_FLAG_GATEWAY) == 0)
    {
        result->next_hop = dest_ip;
    }
    else
    {
        result->next_hop = route_table[best_match].gateway;
    }
    lock_release(&route_table_lock);
    return true;
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions