Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/gr_net_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ typedef enum : uint8_t {
GR_AF_UNSPEC = AF_UNSPEC,
GR_AF_IP4 = AF_INET,
GR_AF_IP6 = AF_INET6,
GR_AF_MPLS = AF_MPLS,
} addr_family_t;

// Convert address family enum to string representation.
Expand All @@ -38,6 +39,8 @@ static inline const char *gr_af_name(addr_family_t af) {
return "ipv4";
case GR_AF_IP6:
return "ipv6";
case GR_AF_MPLS:
return "mpls";
}
return "?";
}
Expand All @@ -48,6 +51,7 @@ static inline bool gr_af_valid(addr_family_t af) {
case GR_AF_UNSPEC:
case GR_AF_IP4:
case GR_AF_IP6:
case GR_AF_MPLS:
return true;
}
return false;
Expand Down
3 changes: 3 additions & 0 deletions modules/infra/api/gr_nexthop.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ typedef enum : uint8_t {
GR_NH_T_BLACKHOLE, // Drop packets silently.
GR_NH_T_REJECT, // Drop packets with ICMP error.
GR_NH_T_GROUP, // ECMP for multipath routing.
GR_NH_T_MPLS, // MPLS label imposition/swap.
#define GR_NH_T_ALL UINT8_C(0xff) // Match all types in list operations.
} gr_nh_type_t;

Expand Down Expand Up @@ -200,6 +201,8 @@ static inline const char *gr_nh_type_name(const gr_nh_type_t type) {
return "reject";
case GR_NH_T_GROUP:
return "group";
case GR_NH_T_MPLS:
return "MPLS";
}
return "?";
}
Expand Down
6 changes: 6 additions & 0 deletions modules/infra/control/l3_nexthop.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const struct nexthop_af_ops *nexthop_af_ops_from_mbuf(const struct rte_mbuf *m)
return af_ops[GR_AF_IP4];
if (m->packet_type & RTE_PTYPE_L3_IPV6)
return af_ops[GR_AF_IP6];
if ((m->packet_type & RTE_PTYPE_TUNNEL_MASK) == RTE_PTYPE_TUNNEL_MPLS_IN_GRE)
return af_ops[GR_AF_MPLS];
return NULL;
}

Expand Down Expand Up @@ -79,6 +81,9 @@ static inline void set_nexthop_key(
key->ipv6.a[3] = iface_id & 0xff;
}
break;
case GR_AF_MPLS:
ABORT("AF_MPLS has no nexthop key with gw");
break;
case GR_AF_UNSPEC:
ABORT("AF_UNSPEC has no nexthop key with gw");
break;
Expand Down Expand Up @@ -189,6 +194,7 @@ static bool l3_equal(const struct nexthop *a, const struct nexthop *b) {
case GR_AF_IP6:
return rte_ipv6_addr_eq(&l3_a->ipv6, &l3_b->ipv6);
case GR_AF_UNSPEC:
case GR_AF_MPLS:
return true;
}
return false;
Expand Down
1 change: 1 addition & 0 deletions modules/infra/control/nexthop.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ bool nexthop_type_valid(gr_nh_type_t type) {
case GR_NH_T_BLACKHOLE:
case GR_NH_T_REJECT:
case GR_NH_T_GROUP:
case GR_NH_T_MPLS:
return true;
}
return false;
Expand Down
1 change: 1 addition & 0 deletions modules/infra/control/vrf.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ GR_IFACE_INFO(GR_IFACE_TYPE_VRF, iface_info_vrf, {
uint32_t vrf_ifindex;
void *fib4;
void *fib6;
void *fib_mpls;
});

// Increment VRF reference count.
Expand Down
33 changes: 33 additions & 0 deletions modules/infra/datapath/checksum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2025 Matej Muzila

#pragma once

#include <gr_net_types.h>

// RFC 1624 incremental checksum update for a 16-bit field.
static inline rte_be16_t
fixup_checksum_16(rte_be16_t old_cksum, rte_be16_t old_field, rte_be16_t new_field) {
uint32_t sum;

sum = ~old_cksum & 0xffff;
sum += (~old_field & 0xffff) + new_field;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);

return ~sum & 0xffff;
}

// RFC 1624 incremental checksum update for a 32-bit field.
static inline rte_be16_t
fixup_checksum_32(rte_be16_t old_cksum, ip4_addr_t old_addr, ip4_addr_t new_addr) {
uint32_t sum;

sum = ~old_cksum & 0xffff;
sum += (~old_addr & 0xffff) + (new_addr & 0xffff);
sum += (~old_addr >> 16) + (new_addr >> 16);
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);

return ~sum & 0xffff;
}
1 change: 1 addition & 0 deletions modules/l2/control/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ static int iface_vxlan_reconfig(
cur->template.ipv6.vxlan.vx_vni = vxlan_encode_vni(cur->vni);
break;
case GR_AF_UNSPEC:
case GR_AF_MPLS:
break;
}

Expand Down
1 change: 1 addition & 0 deletions modules/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ subdir('infra')
subdir('ip')
subdir('ip6')
subdir('ipip')
subdir('mpls')
subdir('l2')
subdir('l4')
subdir('policy')
Expand Down
101 changes: 101 additions & 0 deletions modules/mpls/api/gr_mpls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2025 Matej Muzila

#pragma once

#include <gr_api.h>
#include <gr_net_types.h>
#include <gr_nexthop.h>

#include <stdint.h>

#define GR_MPLS_MODULE 0xf00e

#define GR_MPLS_MAX_LABELS 16

#define GR_MPLS_MAX_STACK_DEPTH 30

#define GR_MPLS_LABEL_MAX 0xFFFFF

// Reserved MPLS label values (RFC 3032).
enum gr_mpls_reserved_labels : uint32_t {
GR_MPLS_LABEL_IPV4_EXPLICIT_NULL = 0,
GR_MPLS_LABEL_ROUTER_ALERT = 1,
GR_MPLS_LABEL_IPV6_EXPLICIT_NULL = 2,
GR_MPLS_LABEL_IMPLICIT_NULL = 3,
GR_MPLS_LABEL_FIRST_UNRESERVED = 16,
};

struct gr_nexthop_info_mpls {
uint8_t n_labels;
uint8_t ttl; // 0 = copy from payload.
addr_family_t payload_af; // Payload type after pop (GR_AF_UNSPEC = auto-detect).
struct l3_addr via;
uint32_t labels[GR_MPLS_MAX_LABELS];
};

// label routes
enum gr_mpls_requests : uint32_t {
GR_MPLS_LABEL_ROUTE_ADD = GR_MSG_TYPE(GR_MPLS_MODULE, 0x0001),
GR_MPLS_LABEL_ROUTE_DEL,
GR_MPLS_LABEL_ROUTE_GET,
GR_MPLS_LABEL_ROUTE_LIST,
};

// MPLS label route entry.
struct gr_mpls_label_route {
uint16_t vrf_id;
uint32_t in_label;
uint32_t nh_id;
gr_nh_origin_t origin;
};

// Add a label route to the LFIB.
struct gr_mpls_label_route_add_req {
uint16_t vrf_id;
uint32_t in_label; // 0 to GR_MPLS_LABEL_MAX.
uint32_t nh_id; // Must reference a GR_NH_T_MPLS nexthop.
gr_nh_origin_t origin;
uint8_t exist_ok;
};

GR_REQ(GR_MPLS_LABEL_ROUTE_ADD, struct gr_mpls_label_route_add_req, struct gr_empty);

// Delete a label route from the LFIB.
struct gr_mpls_label_route_del_req {
uint16_t vrf_id;
uint32_t in_label;
uint8_t missing_ok;
};

GR_REQ(GR_MPLS_LABEL_ROUTE_DEL, struct gr_mpls_label_route_del_req, struct gr_empty);

// Get a single label route by label value.
struct gr_mpls_label_route_get_req {
uint16_t vrf_id;
uint32_t in_label;
};

GR_REQ(GR_MPLS_LABEL_ROUTE_GET, struct gr_mpls_label_route_get_req, struct gr_mpls_label_route);

// List all label routes in a VRF.
struct gr_mpls_label_route_list_req {
uint16_t vrf_id;
uint16_t max_count;
};

GR_REQ_STREAM(
GR_MPLS_LABEL_ROUTE_LIST,
struct gr_mpls_label_route_list_req,
struct gr_mpls_label_route
);

// events

enum gr_mpls_events : uint32_t {
GR_EVENT_MPLS_ROUTE_ADD = GR_MSG_TYPE(GR_MPLS_MODULE, 0x1001),
GR_EVENT_MPLS_ROUTE_DEL,
};

GR_EVENT(GR_EVENT_MPLS_ROUTE_ADD, struct gr_mpls_label_route);
GR_EVENT(GR_EVENT_MPLS_ROUTE_DEL, struct gr_mpls_label_route);
5 changes: 5 additions & 0 deletions modules/mpls/api/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2025 Matej Muzila

api_headers += files('gr_mpls.h')
api_inc += include_directories('.')
Loading
Loading