diff --git a/modules/ip6/control/address.c b/modules/ip6/control/address.c index 2a72dfe9..650166a6 100644 --- a/modules/ip6/control/address.c +++ b/modules/ip6/control/address.c @@ -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); @@ -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; @@ -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); @@ -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); @@ -204,7 +209,7 @@ 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; @@ -212,8 +217,11 @@ static struct api_out addr6_del(const void *request, void ** /*response*/) { 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; @@ -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; } diff --git a/modules/ip6/control/gr_ip6_control.h b/modules/ip6/control/gr_ip6_control.h index c90d505e..08c45b4e 100644 --- a/modules/ip6/control/gr_ip6_control.h +++ b/modules/ip6/control/gr_ip6_control.h @@ -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 diff --git a/modules/ip6/control/nexthop.c b/modules/ip6/control/nexthop.c index 7b3eb715..f241160f 100644 --- a/modules/ip6/control/nexthop.c +++ b/modules/ip6/control/nexthop.c @@ -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 @@ -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. @@ -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; @@ -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; @@ -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; @@ -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; diff --git a/modules/ip6/control/route.c b/modules/ip6/control/route.c index d107c62c..4e01652b 100644 --- a/modules/ip6/control/route.c +++ b/modules/ip6/control/route.c @@ -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; @@ -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) { @@ -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); } } diff --git a/modules/ip6/datapath/gr_ip6_datapath.h b/modules/ip6/datapath/gr_ip6_datapath.h index 5d5709b5..63d27c11 100644 --- a/modules/ip6/datapath/gr_ip6_datapath.h +++ b/modules/ip6/datapath/gr_ip6_datapath.h @@ -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( diff --git a/modules/ip6/datapath/ip6_error.c b/modules/ip6/datapath/ip6_error.c index 3523378e..48c16a80 100644 --- a/modules/ip6/datapath/ip6_error.c +++ b/modules/ip6/datapath/ip6_error.c @@ -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; @@ -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; } diff --git a/modules/ip6/datapath/ip6_input.c b/modules/ip6/datapath/ip6_input.c index af5a633a..90b0bd26 100644 --- a/modules/ip6/datapath/ip6_input.c +++ b/modules/ip6/datapath/ip6_input.c @@ -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; diff --git a/modules/ip6/datapath/ip6_output.c b/modules/ip6/datapath/ip6_output.c index 9362c50a..bf160452 100644 --- a/modules/ip6/datapath/ip6_output.c +++ b/modules/ip6/datapath/ip6_output.c @@ -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. @@ -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; diff --git a/modules/ip6/datapath/ndp_na_input.c b/modules/ip6/datapath/ndp_na_input.c index adfd3891..d8000355 100644 --- a/modules/ip6/datapath/ndp_na_input.c +++ b/modules/ip6/datapath/ndp_na_input.c @@ -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); diff --git a/modules/ip6/datapath/ndp_ns_input.c b/modules/ip6/datapath/ndp_ns_input.c index 6535ed45..fc59dfaa 100644 --- a/modules/ip6/datapath/ndp_ns_input.c +++ b/modules/ip6/datapath/ndp_ns_input.c @@ -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; @@ -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));