Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ip6 scoped linklocal #113

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
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
31 changes: 20 additions & 11 deletions modules/ip6/control/address.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,24 +76,25 @@ struct nexthop *ip6_mcast_get_member(uint16_t iface_id, const struct rte_ipv6_ad
return NULL;
}

static int ip6_mcast_addr_add(struct iface *iface, const struct rte_ipv6_addr *ip) {
static int ip6_mcast_addr_add(struct iface *iface, const struct rte_ipv6_addr *ipv6) {
struct hoplist *maddrs = &iface_mcast_addrs[iface->id];
struct nexthop *nh = NULL;
struct rte_ipv6_addr ip = *ipv6;
unsigned i;

LOG(INFO, "%s: joining multicast group " IP6_F, iface->name, ip);
LOG(INFO, "%s: joining multicast group " IP6_F, iface->name, &ip);

for (i = 0; i < maddrs->count; i++)
if (rte_ipv6_addr_eq(&maddrs->nh[i]->ipv6, ip))
if (rte_ipv6_addr_eq(&maddrs->nh[i]->ipv6, &ip))
return errno_set(EEXIST);

if (i == ARRAY_DIM(maddrs->nh))
return errno_set(ENOSPC);

if ((nh = ip6_nexthop_lookup(iface->vrf_id, ip)) == NULL) {
if ((nh = ip6_nexthop_new(iface->vrf_id, GR_IFACE_ID_UNDEF, ip)) == NULL)
if ((nh = ip6_nexthop_lookup(iface->vrf_id, &ip)) == NULL) {
if ((nh = ip6_nexthop_new(iface->vrf_id, GR_IFACE_ID_UNDEF, &ip)) == NULL)
return errno_set(-errno);
rte_ether_mcast_from_ipv6(&nh->lladdr, ip);
rte_ether_mcast_from_ipv6(&nh->lladdr, &ip);
}

nexthop_incref(nh);
Expand Down Expand Up @@ -135,9 +136,10 @@ static int ip6_mcast_addr_del(struct iface *iface, const struct rte_ipv6_addr *i
}

static int
iface6_addr_add(const struct iface *iface, const struct rte_ipv6_addr *ip, uint8_t prefixlen) {
iface6_addr_add(const struct iface *iface, const struct rte_ipv6_addr *ipv6, uint8_t prefixlen) {
struct hoplist *addrs;
unsigned addr_index;
struct rte_ipv6_addr *ip = (struct rte_ipv6_addr *)ipv6;
struct nexthop *nh;
int ret;

Expand All @@ -155,6 +157,7 @@ iface6_addr_add(const struct iface *iface, const struct rte_ipv6_addr *ip, uint8
if (addrs->count == ARRAY_DIM(addrs->nh))
return errno_set(ENOSPC);

ip6_addr_linklocal_scope(ip, iface->id);
if (ip6_nexthop_lookup(iface->vrf_id, ip) != NULL)
return errno_set(EADDRINUSE);

Expand All @@ -180,15 +183,17 @@ iface6_addr_add(const struct iface *iface, const struct rte_ipv6_addr *ip, uint8

static struct api_out addr6_add(const void *request, void ** /*response*/) {
const struct gr_ip6_addr_add_req *req = request;
struct rte_ipv6_addr solicited_node;
struct rte_ipv6_addr solicited_node, ip;
struct iface *iface;
int ret;

iface = iface_from_id(req->addr.iface_id);
if (iface == NULL)
return api_out(errno, 0);
ip = req->addr.addr.ip;

if ((ret = iface6_addr_add(iface, &req->addr.addr.ip, req->addr.addr.prefixlen)) < 0)
ip6_addr_linklocal_scope(&ip, req->addr.iface_id);
if ((ret = iface6_addr_add(iface, &ip, req->addr.addr.prefixlen)) < 0)
if (ret != -EEXIST || !req->exist_ok)
return api_out(-ret, 0);

Expand All @@ -204,16 +209,19 @@ static struct api_out addr6_add(const void *request, void ** /*response*/) {

static struct api_out addr6_del(const void *request, void ** /*response*/) {
const struct gr_ip6_addr_del_req *req = request;
struct rte_ipv6_addr solicited_node;
struct rte_ipv6_addr solicited_node, scoped;
struct nexthop *nh = NULL;
struct hoplist *addrs;
unsigned i;

if ((addrs = ip6_addr_get_all(req->addr.iface_id)) == NULL)
return api_out(errno, 0);

scoped = req->addr.addr.ip;
ip6_addr_linklocal_scope(&scoped, req->addr.iface_id);

for (i = 0; i < addrs->count; i++) {
if (rte_ipv6_addr_eq(&addrs->nh[i]->ipv6, &req->addr.addr.ip)
if (rte_ipv6_addr_eq(&addrs->nh[i]->ipv6, &scoped)
&& addrs->nh[i]->prefixlen == req->addr.addr.prefixlen) {
nh = addrs->nh[i];
break;
Expand Down Expand Up @@ -271,6 +279,7 @@ static struct api_out addr6_list(const void *request, void **response) {
const struct nexthop *nh = addrs->nh[i];
addr = &resp->addrs[resp->n_addrs++];
addr->addr.ip = nh->ipv6;
ip6_addr_linklocal_unscope(&addr->addr.ip);
addr->addr.prefixlen = nh->prefixlen;
addr->iface_id = nh->iface_id;
}
Expand Down
14 changes: 14 additions & 0 deletions modules/ip6/control/gr_ip6_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,18 @@ struct hoplist *ip6_addr_get_all(uint16_t iface_id);
// determine if the given interface is member of the provided multicast address group
struct nexthop *ip6_mcast_get_member(uint16_t iface_id, const struct rte_ipv6_addr *mcast);

static inline int ip6_addr_linklocal_scope(struct rte_ipv6_addr *ip, uint16_t iface_id) {
if (!rte_ipv6_addr_is_linklocal(ip))
return errno_set(EFAULT);
((uint16_t *)ip->a)[1] = iface_id;
return 0;
}

static inline int ip6_addr_linklocal_unscope(struct rte_ipv6_addr *ip) {
if (!rte_ipv6_addr_is_linklocal(ip))
return errno_set(EFAULT);
((uint16_t *)ip->a)[1] = 0;
return 0;
}

#endif
17 changes: 14 additions & 3 deletions modules/ip6/control/nexthop.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ static control_input_t ip6_output_node;

void ip6_nexthop_unreachable_cb(struct rte_mbuf *m) {
struct rte_ipv6_hdr *ip = rte_pktmbuf_mtod(m, struct rte_ipv6_hdr *);
struct rte_ipv6_addr dst = ip->dst_addr;
struct rte_ipv6_addr dst;
struct nexthop *nh;

ip6_addr_linklocal_scope(&ip->dst_addr, mbuf_data(m)->iface->id);
dst = ip->dst_addr;

nh = ip6_route_lookup(control_output_mbuf_data(m)->iface->vrf_id, &dst);
if (nh == NULL)
goto free; // route to dst has disappeared
Expand Down Expand Up @@ -150,6 +153,9 @@ void ndp_probe_input_cb(struct rte_mbuf *m) {
if (!lladdr_found)
goto free;

// Scoped link local neighbor: encode iface id in the address
ip6_addr_linklocal_scope(&target, iface->id);

nh = ip6_nexthop_lookup(iface->vrf_id, &target);
if (nh == NULL) {
// We don't have an entry for the probe sender address yet.
Expand Down Expand Up @@ -202,6 +208,7 @@ void ndp_probe_input_cb(struct rte_mbuf *m) {

static struct api_out nh6_add(const void *request, void ** /*response*/) {
const struct gr_ip6_nh_add_req *req = request;
struct rte_ipv6_addr ip = req->nh.ipv6;
struct nexthop *nh;
int ret;

Expand All @@ -212,14 +219,15 @@ static struct api_out nh6_add(const void *request, void ** /*response*/) {
if (iface_from_id(req->nh.iface_id) == NULL)
return api_out(errno, 0);

if ((nh = ip6_nexthop_lookup(req->nh.vrf_id, &req->nh.ipv6)) != NULL) {
ip6_addr_linklocal_scope(&ip, req->nh.iface_id);
if ((nh = ip6_nexthop_lookup(req->nh.vrf_id, &ip)) != NULL) {
if (req->exist_ok && req->nh.iface_id == nh->iface_id
&& rte_is_same_ether_addr(&req->nh.mac, &nh->lladdr))
return api_out(0, 0);
return api_out(EEXIST, 0);
}

if ((nh = ip6_nexthop_new(req->nh.vrf_id, req->nh.iface_id, &req->nh.ipv6)) == NULL)
if ((nh = ip6_nexthop_new(req->nh.vrf_id, req->nh.iface_id, &ip)) == NULL)
return api_out(errno, 0);

nh->lladdr = req->nh.mac;
Expand Down Expand Up @@ -265,6 +273,7 @@ static void nh_list_cb(struct nexthop *nh, void *priv) {
return;

api_nh.ipv6 = nh->ipv6;
ip6_addr_linklocal_unscope(&api_nh.ipv6);
api_nh.iface_id = nh->iface_id;
api_nh.vrf_id = nh->vrf_id;
api_nh.mac = nh->lladdr;
Expand Down Expand Up @@ -294,6 +303,8 @@ static struct api_out nh6_list(const void *request, void **response) {
resp->n_nhs = gr_vec_len(ctx.nh);
if (ctx.nh != NULL)
memcpy(resp->nhs, ctx.nh, resp->n_nhs * sizeof(resp->nhs[0]));
for (int i = 0; i < resp->n_nhs; i++)
ip6_addr_linklocal_unscope(&resp->nhs[i].ipv6);
gr_vec_free(ctx.nh);
*response = resp;

Expand Down
4 changes: 4 additions & 0 deletions modules/ip6/control/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ static struct api_out route6_get(const void *request, void **response) {
return api_out(ENOMEM, 0);

resp->nh.ipv6 = nh->ipv6;
ip6_addr_linklocal_unscope(&resp->nh.ipv6);
resp->nh.iface_id = nh->iface_id;
resp->nh.mac = nh->lladdr;
resp->nh.flags = nh->flags;
Expand Down Expand Up @@ -293,6 +294,8 @@ static void route6_rib_to_api(struct gr_ip6_route_list_resp *resp, uint16_t vrf_
rte_rib6_get_depth(rn, &r->dest.prefixlen);
r->nh = nh_id_to_ptr(nh_id)->ipv6;
r->vrf_id = vrf_id;
ip6_addr_linklocal_unscope(&r->dest.ip);
ip6_addr_linklocal_unscope(&r->nh);
}
// check if there is a default route configured
if ((rn = rte_rib6_lookup_exact(rib, &zero, 0)) != NULL) {
Expand All @@ -301,6 +304,7 @@ static void route6_rib_to_api(struct gr_ip6_route_list_resp *resp, uint16_t vrf_
memset(&r->dest, 0, sizeof(r->dest));
r->nh = nh_id_to_ptr(nh_id)->ipv6;
r->vrf_id = vrf_id;
ip6_addr_linklocal_unscope(&r->nh);
}
}

Expand Down
2 changes: 2 additions & 0 deletions modules/ip6/datapath/gr_ip6_datapath.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ static inline void ip6_set_fields(
ip->hop_limits = IP6_DEFAULT_HOP_LIMIT;
ip->src_addr = *src;
ip->dst_addr = *dst;
ip6_addr_linklocal_unscope(&ip->src_addr);
ip6_addr_linklocal_unscope(&ip->dst_addr);
}

void ndp_update_nexthop(
Expand Down
5 changes: 4 additions & 1 deletion modules/ip6/datapath/ip6_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ ip6_error_process(struct rte_graph *graph, struct rte_node *node, void **objs, u
struct icmp6_err_ttl_exceeded *te;
struct ip6_local_mbuf_data *d;
const struct iface *iface;
struct rte_ipv6_addr src;
struct rte_ipv6_hdr *ip;
icmp6_type_t icmp_type;
struct rte_mbuf *mbuf;
Expand Down Expand Up @@ -89,7 +90,9 @@ ip6_error_process(struct rte_graph *graph, struct rte_node *node, void **objs, u
edge = NO_IP;
goto next;
}
if ((nh = ip6_addr_get_preferred(iface->id, &ip->src_addr)) == NULL) {
src = ip->src_addr;
ip6_addr_linklocal_scope(&src, iface->id);
if ((nh = ip6_addr_get_preferred(iface->id, &src)) == NULL) {
edge = NO_IP;
goto next;
}
Expand Down
2 changes: 2 additions & 0 deletions modules/ip6/datapath/ip6_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ ip6_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u
goto next;
}

ip6_addr_linklocal_scope(&ip->src_addr, iface->id);
ip6_addr_linklocal_scope(&ip->dst_addr, iface->id);
nh = ip6_route_lookup(iface->vrf_id, &ip->dst_addr);
if (nh == NULL) {
edge = DEST_UNREACH;
Expand Down
18 changes: 12 additions & 6 deletions modules/ip6/datapath/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,16 @@ ip6_output_process(struct rte_graph *graph, struct rte_node *node, void **objs,
if (edge != ETH_OUTPUT)
goto next;

if (!rte_ipv6_addr_is_mcast(&ip->dst_addr)
&& (!(nh->flags & GR_NH_F_REACHABLE)
|| (nh->flags & GR_NH_F_LINK && !rte_ipv6_addr_eq(&ip->dst_addr, &nh->ipv6))
)) {
edge = HOLD;
goto next;
ip6_addr_linklocal_scope(&ip->dst_addr, iface->id);
if (rte_ipv6_addr_is_mcast(&ip->dst_addr) == 0) {
if ((nh->flags & GR_NH_F_REACHABLE) == 0) {
if (nh->flags & GR_NH_F_LINK) {
if (!rte_ipv6_addr_eq(&ip->dst_addr, &nh->ipv6)) {
edge = HOLD;
goto next;
}
}
}
}

// Prepare ethernet layer info.
Expand All @@ -86,6 +90,8 @@ ip6_output_process(struct rte_graph *graph, struct rte_node *node, void **objs,
eth_data->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6);
sent++;
next:
ip6_addr_linklocal_unscope(&ip->src_addr);
ip6_addr_linklocal_unscope(&ip->dst_addr);
if (gr_mbuf_is_traced(mbuf)) {
struct rte_ipv6_hdr *t = gr_mbuf_trace_add(mbuf, node, sizeof(*t));
*t = *ip;
Expand Down
1 change: 1 addition & 0 deletions modules/ip6/datapath/ndp_na_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ static uint16_t ndp_na_input_process(
// There is no need to create an entry if none exists, since the
// recipient has apparently not initiated any communication with the
// target.
ip6_addr_linklocal_scope(&na->target, iface->id);
remote = ip6_nexthop_lookup(iface->vrf_id, &na->target);
ASSERT_NDP(remote != NULL);

Expand Down
5 changes: 5 additions & 0 deletions modules/ip6/datapath/ndp_ns_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ static uint16_t ndp_ns_input_process(
// - Target Address is not a multicast address.
ASSERT_NDP(!rte_ipv6_addr_is_mcast(&ns->target));

ip6_addr_linklocal_scope(&d->src, iface->id);
ip6_addr_linklocal_scope(&src, iface->id);
ip6_addr_linklocal_scope(&ns->target, iface->id);

local = ip6_nexthop_lookup(iface->vrf_id, &ns->target);
if (local == NULL || !(local->flags & GR_NH_F_LOCAL)) {
next = IGNORE;
Expand Down Expand Up @@ -146,6 +150,7 @@ static uint16_t ndp_ns_input_process(
na->router = 1;
na->solicited = solicited;
na->target = local->ipv6;
ip6_addr_linklocal_unscope(&na->target);
opt = (struct icmp6_opt *)rte_pktmbuf_append(mbuf, sizeof(*opt));
opt->type = ICMP6_OPT_TARGET_LLADDR;
opt->len = ICMP6_OPT_LEN(sizeof(*opt) + sizeof(*ll));
Expand Down
Loading