summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriyEshenko <dmitriy.eshenko@vyos.io>2021-12-10 19:43:42 +0300
committerDmitriyEshenko <dmitriy.eshenko@vyos.io>2021-12-16 23:03:52 +0300
commit737bf4d8b6e9e1bf50be69e8c99028bb2696190c (patch)
tree0fb5c5234841d6dbdd16bf5cfd18e0c841177243
parent51bd8165bb335a8db966c4df344810e7ef2c563c (diff)
downloadaccel-ppp-737bf4d8b6e9e1bf50be69e8c99028bb2696190c.tar.gz
accel-ppp-737bf4d8b6e9e1bf50be69e8c99028bb2696190c.zip
vrf: T10: Add VRF support
Co-authored-by: Sergey V. Lobanov <svlobanov@users.noreply.github.com> Co-authored-by: Vladislav Grishenko <themiron@users.noreply.github.com>
-rw-r--r--accel-pppd/CMakeLists.txt8
-rw-r--r--accel-pppd/cli/show_sessions.c9
-rw-r--r--accel-pppd/ifcfg.c43
-rw-r--r--accel-pppd/include/ap_net.h5
-rw-r--r--accel-pppd/include/ap_session.h4
-rw-r--r--accel-pppd/net.c41
-rw-r--r--accel-pppd/radius/attr_defs.h2
-rw-r--r--accel-pppd/radius/dict/dictionary1
-rw-r--r--accel-pppd/radius/dict/dictionary.accel7
-rw-r--r--accel-pppd/radius/dm_coa.c45
-rw-r--r--accel-pppd/radius/radius.c56
-rw-r--r--accel-pppd/session.c6
-rw-r--r--config.h.in1
13 files changed, 205 insertions, 23 deletions
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 <linux/if_link.h>
+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