diff options
| author | Andrii Melnychenko <a.melnychenko@vyos.io> | 2026-01-07 13:14:11 +0100 |
|---|---|---|
| committer | Andrii Melnychenko <a.melnychenko@vyos.io> | 2026-01-30 04:25:54 +0100 |
| commit | d4f230af1cc31447289a7e30640a471a818cfd69 (patch) | |
| tree | be58051108127df6f5d700691441425cedb891c6 | |
| parent | 048d31cb446879e0d1a1471b4ab99135a92bf289 (diff) | |
| download | accel-ppp-d4f230af1cc31447289a7e30640a471a818cfd69.tar.gz accel-ppp-d4f230af1cc31447289a7e30640a471a818cfd69.zip | |
netlink: Added VRF support
Added VRF support to the iproute routines.
Updated iproute* calls in the ipoe, radius, and dhcpv6 code.
Signed-off-by: Andrii Melnychenko <a.melnychenko@vyos.io>
| -rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 14 | ||||
| -rw-r--r-- | accel-pppd/ifcfg.c | 2 | ||||
| -rw-r--r-- | accel-pppd/ipv6/dhcpv6.c | 4 | ||||
| -rw-r--r-- | accel-pppd/libnetlink/iputils.c | 127 | ||||
| -rw-r--r-- | accel-pppd/libnetlink/iputils.h | 9 | ||||
| -rw-r--r-- | accel-pppd/radius/radius.c | 9 |
6 files changed, 137 insertions, 28 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 6ce35a69..bc55aa69 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -1022,9 +1022,9 @@ static void __ipoe_session_activate(struct ipoe_session *ses) in_addr_t gw; iproute_get(ses->router, &gw, NULL); if (gw) - iproute_add(0, ses->siaddr, ses->yiaddr, gw, conf_proto, 32); + iproute_add(0, ses->siaddr, ses->yiaddr, gw, conf_proto, 32, NULL); else - iproute_add(0, ses->siaddr, ses->router, gw, conf_proto, 32); + iproute_add(0, ses->siaddr, ses->router, gw, conf_proto, 32, NULL); }*/ if (serv->opt_mode == MODE_L3) @@ -1068,9 +1068,9 @@ static void __ipoe_session_activate(struct ipoe_session *ses) if (ses->ifindex == -1 && !serv->opt_ifcfg) { if (!serv->opt_ip_unnumbered) - iproute_add(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0); + iproute_add(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0, NULL); else - iproute_add(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0); + iproute_add(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0, NULL); } if (ses->l4_redirect) @@ -1171,7 +1171,7 @@ static void ipoe_session_started(struct ap_session *s) if (ses->ses.ipv4->peer_addr != ses->yiaddr) //ipaddr_add_peer(ses->ses.ifindex, ses->router, ses->yiaddr); // breaks quagga - iproute_add(ses->ses.ifindex, ses->router, ses->yiaddr, 0, conf_proto, 32, 0); + iproute_add(ses->ses.ifindex, ses->router, ses->yiaddr, 0, conf_proto, 32, 0, NULL); if (ses->ifindex != -1 && ses->xid) { ses->dhcpv4 = dhcpv4_create(ses->ctrl.ctx, ses->ses.ifname, ""); @@ -1255,9 +1255,9 @@ static void ipoe_session_finished(struct ap_session *s) } else if (ses->started) { if (!serv->opt_ifcfg) { if (!serv->opt_ip_unnumbered) - iproute_del(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0); + iproute_del(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0, NULL); else - iproute_del(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0); + iproute_del(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0, NULL); } } diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c index 3750060b..4e4a381a 100644 --- a/accel-pppd/ifcfg.c +++ b/accel-pppd/ifcfg.c @@ -234,7 +234,7 @@ void __export ap_session_ifdown(struct ap_session *ses) if (!a->installed) continue; if (a->prefix_len > 64) - ip6route_del(ses->ifindex, &a->addr, a->prefix_len, NULL, 0, 0); + ip6route_del(ses->ifindex, &a->addr, a->prefix_len, NULL, 0, 0, ses->vrf_name); else { struct in6_addr addr; memcpy(addr.s6_addr, &a->addr, 8); diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c index 85863e0c..92a6ed6c 100644 --- a/accel-pppd/ipv6/dhcpv6.c +++ b/accel-pppd/ipv6/dhcpv6.c @@ -162,7 +162,7 @@ static void ev_ses_finished(struct ap_session *ses) if (pd->dp_active) { struct ipv6db_addr_t *p; list_for_each_entry(p, &ses->ipv6_dp->prefix_list, entry) - ip6route_del(0, &p->addr, p->prefix_len, NULL, 0, 0); + ip6route_del(0, &p->addr, p->prefix_len, NULL, 0, 0, NULL); } ipdb_put_ipv6_prefix(ses, ses->ipv6_dp); @@ -184,7 +184,7 @@ static void insert_dp_routes(struct ap_session *ses, struct dhcpv6_pd *pd, struc addr = NULL; list_for_each_entry(p, &ses->ipv6_dp->prefix_list, entry) { - if (ip6route_add(ses->ifindex, &p->addr, p->prefix_len, addr, 0, 0)) { + if (ip6route_add(ses->ifindex, &p->addr, p->prefix_len, addr, 0, 0, NULL)) { err = errno; inet_ntop(AF_INET6, &p->addr, str1, sizeof(str1)); if (addr) diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c index 4bf7fd01..34181e2a 100644 --- a/accel-pppd/libnetlink/iputils.c +++ b/accel-pppd/libnetlink/iputils.c @@ -11,10 +11,13 @@ #include <errno.h> #include <time.h> #include <sys/uio.h> -//#include <linux/if_link.h> +#ifdef HAVE_VRF +#include <linux/if_link.h> +#endif //#include <linux/if_addr.h> //#include <linux/rtnetlink.h> #include <linux/fib_rules.h> +#include <net/if.h> #include "log.h" @@ -458,7 +461,81 @@ int __export ipaddr_del_peer(int ifindex, in_addr_t addr, in_addr_t peer) return r; } -int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio) +#ifdef HAVE_VRF +static int ipvrf_get_table(uint32_t *tb_id, const char *vrf_name) +{ + struct iplink_req { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[4096]; + } req; + struct rtnl_handle *rth = net->rtnl_get(); + struct rtattr *tb[IFLA_MAX+1]; + struct rtattr *li[IFLA_INFO_MAX+1]; + struct rtattr *vrf_attr[IFLA_VRF_MAX + 1]; + struct ifinfomsg *ifi; + int len; + int r = -1; + *tb_id = RT_TABLE_MAIN; + + log_ppp_info2("utils: getting route table for %s\n", vrf_name); + + if (!vrf_name) + return 0; + + memset(&req, 0, sizeof(req) - 4096); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETLINK; + req.i.ifi_family = AF_UNSPEC; + + addattr_l(&req.n, 4096, IFLA_IFNAME, vrf_name, strnlen(vrf_name, IFNAMSIZ)); + + r = rtnl_talk(rth, &req.n, 0, 0, &req.n, NULL, NULL, 0); + if (r < 0) { + log_ppp_error("BUG: route table \"%s\" not found\n", vrf_name); + return r; + } + + ifi = NLMSG_DATA(&req.n); + + len = req.n.nlmsg_len; + + len -= NLMSG_LENGTH(sizeof(*ifi)); + if (len < 0) { + goto error; + } + + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); + + if (!tb[IFLA_LINKINFO]) + goto error; + + parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); + + if (!li[IFLA_INFO_KIND] || !li[IFLA_INFO_DATA]) + goto error; + + if (strncmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf", 4)) { + log_ppp_error("BUG: link \"%s\" is not VRF\n", vrf_name); + goto error; + } + + parse_rtattr_nested(vrf_attr, IFLA_VRF_MAX, li[IFLA_INFO_DATA]); + if (vrf_attr[IFLA_VRF_TABLE]) + *tb_id = *(uint32_t *)RTA_DATA(vrf_attr[IFLA_VRF_TABLE]); + + if (*tb_id == 0) + log_ppp_error("BUG: VRF %s is missing table id\n", vrf_name); + + return 0; +error: + return -1; +} +#endif + +int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio, const char *vrf_name) { struct ipaddr_req { struct nlmsghdr n; @@ -473,16 +550,24 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw memset(&req, 0, sizeof(req) - 4096); + uint32_t rt_table = RT_TABLE_MAIN; +#ifdef HAVE_VRF + if (ipvrf_get_table(&rt_table, vrf_name) < 0) + return -1; +#endif + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; req.n.nlmsg_type = RTM_NEWROUTE; req.i.rtm_family = AF_INET; - req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_table = rt_table; req.i.rtm_scope = gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = mask; + if (rt_table != RT_TABLE_MAIN) + addattr32(&req.n, sizeof(req), RTA_TABLE, rt_table); if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); if (src) @@ -501,7 +586,7 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw return r; } -int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio) +int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio, const char *vrf_name) { struct ipaddr_req { struct nlmsghdr n; @@ -516,16 +601,24 @@ int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw memset(&req, 0, sizeof(req) - 4096); + uint32_t rt_table = RT_TABLE_MAIN; +#ifdef HAVE_VRF + if (ipvrf_get_table(&rt_table, vrf_name) < 0) + return -1; +#endif + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELROUTE; req.i.rtm_family = AF_INET; - req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_table = rt_table; req.i.rtm_scope = gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = mask; + if (rt_table != RT_TABLE_MAIN) + addattr32(&req.n, sizeof(req), RTA_TABLE, rt_table); if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); if (src) @@ -544,7 +637,7 @@ int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw return r; } -int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio) +int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio, const char *vrf_name) { struct ipaddr_req { struct nlmsghdr n; @@ -559,17 +652,25 @@ int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, memset(&req, 0, sizeof(req) - 4096); + uint32_t rt_table = RT_TABLE_MAIN; +#ifdef HAVE_VRF + if (ipvrf_get_table(&rt_table, vrf_name) < 0) + return -1; +#endif + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; req.n.nlmsg_type = RTM_NEWROUTE; req.i.rtm_family = AF_INET6; - req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_table = rt_table; req.i.rtm_scope = RT_SCOPE_UNIVERSE; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = pref_len; addattr_l(&req.n, sizeof(req), RTA_DST, dst, sizeof(*dst)); + if (rt_table != RT_TABLE_MAIN) + addattr32(&req.n, sizeof(req), RTA_TABLE, rt_table); if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); if (gw) @@ -585,7 +686,7 @@ int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, return r; } -int __export ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio) +int __export ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio, const char *vrf_name) { struct ipaddr_req { struct nlmsghdr n; @@ -600,17 +701,25 @@ int __export ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, memset(&req, 0, sizeof(req) - 4096); + uint32_t rt_table = RT_TABLE_MAIN; +#ifdef HAVE_VRF + if (ipvrf_get_table(&rt_table, vrf_name) < 0) + return -1; +#endif + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELROUTE; req.i.rtm_family = AF_INET6; - req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_table = rt_table; req.i.rtm_scope = RT_SCOPE_UNIVERSE; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = pref_len; addattr_l(&req.n, sizeof(req), RTA_DST, dst, sizeof(*dst)); + if (rt_table != RT_TABLE_MAIN) + addattr32(&req.n, sizeof(req), RTA_TABLE, rt_table); if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); if (gw) diff --git a/accel-pppd/libnetlink/iputils.h b/accel-pppd/libnetlink/iputils.h index 9292cea2..86500882 100644 --- a/accel-pppd/libnetlink/iputils.h +++ b/accel-pppd/libnetlink/iputils.h @@ -4,6 +4,7 @@ #include <linux/if_link.h> #include <netinet/in.h> #include <stdint.h> +#include <config.h> typedef int (*iplink_list_func)(int index, int flags, const char *name, int iflink, int vid, void *arg); @@ -20,12 +21,12 @@ int ipaddr_add_peer(int ifindex, in_addr_t addr, in_addr_t peer_addr); int ipaddr_del(int ifindex, in_addr_t addr, int mask); int ipaddr_del_peer(int ifindex, in_addr_t addr, in_addr_t peer); -int iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio); -int iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio); +int iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio, const char *vrf_name); +int iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio, const char *vrf_name); in_addr_t iproute_get(in_addr_t dst, in_addr_t *gw); -int ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio); -int ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio); +int ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio, const char *vrf_name); +int ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio, const char *vrf_name); int ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len); int ip6addr_add_peer(int ifindex, struct in6_addr *addr, struct in6_addr *peer_addr); int ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len); diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c index 8dbbe1cd..143c237c 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -801,8 +801,7 @@ static void ses_started(struct ap_session *ses) bool gw_spec = !IN6_IS_ADDR_UNSPECIFIED(&fr6->gw); char nbuf[INET6_ADDRSTRLEN]; char gwbuf[INET6_ADDRSTRLEN]; - - if (ip6route_add(gw_spec ? 0 : rpd->ses->ifindex, &fr6->prefix, fr6->plen, gw_spec ? &fr6->gw : NULL, 3, fr6->prio)) { + if (ip6route_add(gw_spec ? 0 : rpd->ses->ifindex, &fr6->prefix, fr6->plen, gw_spec ? &fr6->gw : NULL, 3, fr6->prio, rpd->ses->vrf_name)) { log_ppp_warn("radius: failed to add route %s/%hhu %s %u\n", u_ip6str(&fr6->prefix, nbuf), fr6->plen, u_ip6str(&fr6->gw, gwbuf), fr6->prio); @@ -810,7 +809,7 @@ static void ses_started(struct ap_session *ses) } for (fr = rpd->fr; fr; fr = fr->next) { - if (iproute_add(fr->gw ? 0 : rpd->ses->ifindex, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio)) { + if (iproute_add(fr->gw ? 0 : rpd->ses->ifindex, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio, rpd->ses->vrf_name)) { char dst[17], gw[17]; u_inet_ntoa(fr->dst, dst); u_inet_ntoa(fr->gw, gw); @@ -849,12 +848,12 @@ static void ses_finishing(struct ap_session *ses) * when the interface is removed. */ if (!IN6_IS_ADDR_UNSPECIFIED(&fr6->gw)) - ip6route_del(0, &fr6->prefix, fr6->plen, &fr6->gw, 3, fr6->prio); + ip6route_del(0, &fr6->prefix, fr6->plen, &fr6->gw, 3, fr6->prio, rpd->ses->vrf_name); } for (fr = rpd->fr; fr; fr = fr->next) { if (fr->gw) - iproute_del(0, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio); + iproute_del(0, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio, rpd->ses->vrf_name); } if (rpd->acct_started || rpd->acct_req) |
