From 737bf4d8b6e9e1bf50be69e8c99028bb2696190c Mon Sep 17 00:00:00 2001 From: DmitriyEshenko Date: Fri, 10 Dec 2021 19:43:42 +0300 Subject: vrf: T10: Add VRF support Co-authored-by: Sergey V. Lobanov Co-authored-by: Vladislav Grishenko --- accel-pppd/CMakeLists.txt | 8 +++++ accel-pppd/cli/show_sessions.c | 9 ++++++ accel-pppd/ifcfg.c | 43 +++++++++++++++++++++++++ accel-pppd/include/ap_net.h | 5 +++ accel-pppd/include/ap_session.h | 4 +++ accel-pppd/net.c | 41 ++++++++++++++++++++++++ accel-pppd/radius/attr_defs.h | 2 ++ accel-pppd/radius/dict/dictionary | 1 + accel-pppd/radius/dict/dictionary.accel | 7 +++++ accel-pppd/radius/dm_coa.c | 45 ++++++++++++++++++++++++-- accel-pppd/radius/radius.c | 56 +++++++++++++++++++++------------ accel-pppd/session.c | 6 ++++ config.h.in | 1 + 13 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 accel-pppd/radius/dict/dictionary.accel diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt index d7eaf1d..23a1d0a 100644 --- a/accel-pppd/CMakeLists.txt +++ b/accel-pppd/CMakeLists.txt @@ -64,6 +64,14 @@ CHECK_INCLUDE_FILE("linux/netfilter/ipset/ip_set.h" HAVE_IPSET) INCLUDE(CheckFunctionExists) CHECK_FUNCTION_EXISTS(setns HAVE_SETNS) +INCLUDE (CheckCSourceCompiles) +CHECK_C_SOURCE_COMPILES(" +#include +int main(void) +{ + return IFLA_VRF_UNSPEC+IFLA_VRF_TABLE; +}" HAVE_VRF) + ADD_EXECUTABLE(accel-pppd memdebug.c session.c diff --git a/accel-pppd/cli/show_sessions.c b/accel-pppd/cli/show_sessions.c index 6ef6059..73c6a41 100644 --- a/accel-pppd/cli/show_sessions.c +++ b/accel-pppd/cli/show_sessions.c @@ -384,6 +384,14 @@ static void print_netns(struct ap_session *ses, char *buf) snprintf(buf, CELL_SIZE, "%s", ses->net->name); } +static void print_vrf(struct ap_session *ses, char *buf) +{ + if (ses->vrf_name) + snprintf(buf, CELL_SIZE, "%s", ses->vrf_name); + else + *buf = 0; +} + static void print_ifname(struct ap_session *ses, char *buf) { snprintf(buf, CELL_SIZE, "%s", ses->ifname); @@ -639,6 +647,7 @@ static void init(void) cli_register_simple_cmd2(show_ses_exec, show_ses_help, 2, "show", "sessions"); cli_show_ses_register("netns", "network namespace name", print_netns); + cli_show_ses_register("vrf", "vrf name", print_vrf); cli_show_ses_register("ifname", "interface name", print_ifname); cli_show_ses_register("username", "user name", print_username); cli_show_ses_register("ip", "IP address", print_ip); diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c index 6ab5505..3750060 100644 --- a/accel-pppd/ifcfg.c +++ b/accel-pppd/ifcfg.c @@ -19,8 +19,11 @@ #include "ipdb.h" #include "log.h" #include "backup.h" +#include "config.h" #include "memdebug.h" +#define VRF_DEFAULT_NAME "default" + // from /usr/include/linux/ipv6.h struct in6_ifreq { struct in6_addr ifr6_addr; @@ -56,6 +59,15 @@ void ap_session_ifup(struct ap_session *ses) ses->ifname_rename = NULL; } +#ifdef HAVE_VRF + if (ses->vrf_name) { + if (ap_session_vrf(ses, ses->vrf_name, -1)) { + ap_session_terminate(ses, TERM_NAS_ERROR, 0); + return; + } + } +#endif + triton_event_fire(EV_SES_ACCT_START, ses); if (ses->stop_time) @@ -334,3 +346,34 @@ int __export ap_session_rename(struct ap_session *ses, const char *ifname, int l return 0; } +#ifdef HAVE_VRF +int __export ap_session_vrf(struct ap_session *ses, const char *vrf_name, int len) +{ + if (len == -1) + len = strlen(vrf_name); + + int vrf_ifindex = 0; + + if (len) { + vrf_ifindex = ses->net->get_ifindex(vrf_name); + if (vrf_ifindex < 0) { + log_ppp_error("vrf '%s' not found\n", vrf_name); + return -1; + } + } else + vrf_name = VRF_DEFAULT_NAME; + + if (ses->net->set_vrf(ses->ifindex, vrf_ifindex)) { + log_ppp_error("set vrf %s failed ifindex=%d, vrf_ifindex=%d\n", vrf_name, ses->ifindex, vrf_ifindex); + return -1; + } else + log_ppp_info2("set vrf %s\n", vrf_name); + + if (!len) { + _free(ses->vrf_name); + ses->vrf_name = NULL; + } + + return 0; +} +#endif \ No newline at end of file diff --git a/accel-pppd/include/ap_net.h b/accel-pppd/include/ap_net.h index 984c6c1..063b893 100644 --- a/accel-pppd/include/ap_net.h +++ b/accel-pppd/include/ap_net.h @@ -6,6 +6,7 @@ #include "libnetlink.h" #include "list.h" +#include "config.h" struct ap_net { struct list_head entry; @@ -33,6 +34,10 @@ struct ap_net { int (*move_link)(struct ap_net *net, int ifindex); int (*get_ifindex)(const char * ifname); void (*release)(struct ap_net *net); +#ifdef HAVE_VRF + int (*set_vrf)(int ifindex, int vrf_ifindex); +#endif + }; extern __thread struct ap_net *net; diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h index 7efa110..1227718 100644 --- a/accel-pppd/include/ap_session.h +++ b/accel-pppd/include/ap_session.h @@ -73,6 +73,7 @@ struct ap_session char *chan_name; char ifname[AP_IFNAME_LEN]; char *ifname_rename; + char *vrf_name; int unit_idx; int ifindex; char sessionid[AP_SESSIONID_LEN+1]; @@ -151,6 +152,9 @@ int ap_check_username(const char *username); void ap_session_ifup(struct ap_session *ses); void ap_session_ifdown(struct ap_session *ses); int ap_session_rename(struct ap_session *ses, const char *ifname, int len); +#ifdef HAVE_VRF +int ap_session_vrf(struct ap_session *ses, const char *vrf_name, int len); +#endif int ap_session_read_stats(struct ap_session *ses, struct rtnl_link_stats *stats); diff --git a/accel-pppd/net.c b/accel-pppd/net.c index 809dfaa..26373fc 100644 --- a/accel-pppd/net.c +++ b/accel-pppd/net.c @@ -231,6 +231,44 @@ static int def_get_ifindex(const char *ifname) return ifr.ifr_ifindex; } +#ifdef HAVE_VRF +static int def_set_vrf(int ifindex, int vrf_ifindex) +{ + struct iplink_req { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req; + + struct rtnl_handle *rth = net->rtnl_get(); + + int r = 0; + + if (!rth) { + log_ppp_error("def_set_vrf rtnl_get failed\n"); + return -1; + } + + memset(&req, 0, sizeof(req) - 1024); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = AF_UNSPEC; + req.i.ifi_index = ifindex; + + addattr_l(&req.n, sizeof(req), IFLA_MASTER, &vrf_ifindex, sizeof(vrf_ifindex)); + + if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) { + log_ppp_error("def_set_vrf rtnl_talk failed\n"); + r = -1; + } + + net->rtnl_put(rth); + + return r; +} +#endif static void def_release(struct ap_net *d) { @@ -318,6 +356,9 @@ static struct ap_net *alloc_net(const char *name) net->move_link = def_move_link; net->get_ifindex = def_get_ifindex; net->release = def_release; +#ifdef HAVE_VRF + net->set_vrf = def_set_vrf; +#endif n->sock = socket(AF_INET, SOCK_DGRAM, 0); n->sock6 = socket(AF_INET6, SOCK_DGRAM, 0); diff --git a/accel-pppd/radius/attr_defs.h b/accel-pppd/radius/attr_defs.h index 8e5bf9b..39fd0c0 100644 --- a/accel-pppd/radius/attr_defs.h +++ b/accel-pppd/radius/attr_defs.h @@ -1,6 +1,8 @@ #define VENDOR_Microsoft 311 #define VENDOR_Accel_PPP 55999 +#define Accel_VRF_Name 1 + #define User_Name 1 #define User_Password 2 #define CHAP_Password 3 diff --git a/accel-pppd/radius/dict/dictionary b/accel-pppd/radius/dict/dictionary index cf9e367..2afd26f 100644 --- a/accel-pppd/radius/dict/dictionary +++ b/accel-pppd/radius/dict/dictionary @@ -76,6 +76,7 @@ $INCLUDE dictionary.rfc4818 $INCLUDE dictionary.rfc5176 $INCLUDE dictionary.rfc6911 +$INCLUDE dictionary.accel $INCLUDE dictionary.microsoft $INCLUDE dictionary.cisco $INCLUDE dictionary.alcatel diff --git a/accel-pppd/radius/dict/dictionary.accel b/accel-pppd/radius/dict/dictionary.accel new file mode 100644 index 0000000..849cc42 --- /dev/null +++ b/accel-pppd/radius/dict/dictionary.accel @@ -0,0 +1,7 @@ +VENDOR Accel-PPP 55999 + +BEGIN-VENDOR Accel-PPP + +ATTRIBUTE Accel-VRF-Name 1 string + +END-VENDOR Accel-PPP diff --git a/accel-pppd/radius/dm_coa.c b/accel-pppd/radius/dm_coa.c index 003a691..b58306c 100644 --- a/accel-pppd/radius/dm_coa.c +++ b/accel-pppd/radius/dm_coa.c @@ -17,6 +17,7 @@ #include "log.h" #include "radius_p.h" +#include "attr_defs.h" #include "memdebug.h" @@ -143,6 +144,24 @@ static void disconnect_request(struct radius_pd_t *rpd) ap_session_terminate(rpd->ses, TERM_ADMIN_RESET, 0); } +#ifdef HAVE_VRF +int rad_update_vrf(struct radius_pd_t *rpd, const char *vrf_name) +{ + if (*vrf_name == '0') { + // Delete interface from VRF + if (!ap_session_vrf(rpd->ses, NULL, 0)) + return 1; + } + else { + // Add interface to VRF + if(!ap_session_vrf(rpd->ses, vrf_name, -1)) + return 1; + } + + return 0; +} +#endif + static void coa_request(struct radius_pd_t *rpd) { struct rad_attr_t *class; @@ -153,6 +172,8 @@ static void coa_request(struct radius_pd_t *rpd) .request = rpd->dm_coa_req, }; + int send_ack = 0; + if (conf_verbose) { log_ppp_info2("recv "); rad_packet_print(rpd->dm_coa_req, NULL, log_ppp_info2); @@ -161,7 +182,7 @@ static void coa_request(struct radius_pd_t *rpd) triton_event_fire(EV_RADIUS_COA, &ev); if (ev.res) - dm_coa_send_nak(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr, 0); + goto out; else { class = rad_packet_find_attr(rpd->dm_coa_req, NULL, "Class"); if (class) { @@ -180,14 +201,32 @@ static void coa_request(struct radius_pd_t *rpd) else rad_packet_add_octets(rpd->acct_req->pack, NULL, "Class", rpd->attr_class, rpd->attr_class_len); } + send_ack = 1; + goto out; } attr = rad_packet_find_attr(rpd->dm_coa_req, NULL, "Session-Timeout"); - if (attr) + if (attr){ rad_update_session_timeout(rpd, attr->val.integer); + send_ack = 1; + goto out; + } +#ifdef HAVE_VRF + attr = rad_packet_find_attr(rpd->dm_coa_req, "Accel-PPP", "Accel-VRF-Name"); + if (attr){ + if(!rad_update_vrf(rpd, attr->val.string)){ + goto out; + } + } +#endif + send_ack = 1; + } +out: + if (send_ack) dm_coa_send_ack(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr); - } + else + dm_coa_send_nak(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr, 0); rad_packet_free(rpd->dm_coa_req); diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c index 9137f61..a1a9447 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -20,6 +20,7 @@ #include "radius_p.h" #include "attr_defs.h" +#include "config.h" #include "memdebug.h" @@ -282,28 +283,43 @@ int rad_proc_attrs(struct rad_req_t *req) req->rpd->acct_interim_jitter = conf_acct_interim_jitter; list_for_each_entry(attr, &req->reply->attrs, entry) { - if (attr->vendor && attr->vendor->id == VENDOR_Microsoft) { - switch (attr->attr->id) { - case MS_Primary_DNS_Server: - dns.ses = rpd->ses; - dns.dns1 = attr->val.ipaddr; - break; - case MS_Secondary_DNS_Server: - dns.ses = rpd->ses; - dns.dns2 = attr->val.ipaddr; - break; - case MS_Primary_NBNS_Server: - wins.ses = rpd->ses; - wins.wins1 = attr->val.ipaddr; - break; - case MS_Secondary_NBNS_Server: - wins.ses = rpd->ses; - wins.wins2 = attr->val.ipaddr; - break; + if (attr->vendor) { + if (attr->vendor->id == VENDOR_Microsoft) { + switch (attr->attr->id) { + case MS_Primary_DNS_Server: + dns.ses = rpd->ses; + dns.dns1 = attr->val.ipaddr; + break; + case MS_Secondary_DNS_Server: + dns.ses = rpd->ses; + dns.dns2 = attr->val.ipaddr; + break; + case MS_Primary_NBNS_Server: + wins.ses = rpd->ses; + wins.wins1 = attr->val.ipaddr; + break; + case MS_Secondary_NBNS_Server: + wins.ses = rpd->ses; + wins.wins2 = attr->val.ipaddr; + break; + } + continue; +#ifdef HAVE_VRF + } else if (attr->vendor->id == VENDOR_Accel_PPP) { + switch (attr->attr->id) { + case Accel_VRF_Name: + if (rpd->ses->vrf_name) + _free(rpd->ses->vrf_name); + rpd->ses->vrf_name = _malloc(attr->len + 1); + memcpy(rpd->ses->vrf_name, attr->val.string, attr->len); + rpd->ses->vrf_name[attr->len] = 0; + break; + } + continue; +#endif } continue; - } else if (attr->vendor) - continue; + } switch(attr->attr->id) { case User_Name: diff --git a/accel-pppd/session.c b/accel-pppd/session.c index 78d12f9..63c9c11 100644 --- a/accel-pppd/session.c +++ b/accel-pppd/session.c @@ -24,6 +24,7 @@ #include "iputils.h" #include "spinlock.h" #include "mempool.h" +#include "config.h" #include "memdebug.h" #define SID_SOURCE_SEQ 0 @@ -240,6 +241,11 @@ void __export ap_session_finished(struct ap_session *ses) ses->ifname_rename = NULL; } +#ifdef HAVE_VRF + if (ses->vrf_name) + ap_session_vrf(ses, NULL, 0); +#endif + if (ses->net) ses->net->release(ses->net); diff --git a/config.h.in b/config.h.in index 46fca37..e2186a0 100644 --- a/config.h.in +++ b/config.h.in @@ -2,3 +2,4 @@ //#cmakedefine RADIUS #cmakedefine HAVE_IPSET #cmakedefine HAVE_SETNS +#cmakedefine HAVE_VRF -- cgit v1.2.3