Add default APN for each EUA Type

MS may request an unknown APN. In this case we will use
the APN configured in the vty as default-apn but if
the type support does not match the request we will fail.

The commit adds two more vty commands to configure a default
vpn for v6 and for v4v6

Change-Id: I03fcf8a1532bd9988ea99a6afd3dc325174ce9d6
Fixes: OS#4511
This commit is contained in:
Keith Whyte 2020-04-25 05:39:21 +02:00
parent 04715d284f
commit a6a8cc1442
3 changed files with 77 additions and 29 deletions

View File

@ -446,16 +446,44 @@ int create_context_ind(struct pdp_t *pdp)
LOGPPDP(LOGL_DEBUG, pdp, "Processing create PDP context request for APN '%s'\n", LOGPPDP(LOGL_DEBUG, pdp, "Processing create PDP context request for APN '%s'\n",
apn_name ? name_buf : "(NONE)"); apn_name ? name_buf : "(NONE)");
/* FIXME: we manually force all context requests to dynamic here! */
if (pdp->eua.l > 2)
pdp->eua.l = 2;
memset(addr, 0, sizeof(addr));
if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
osmo_hexdump(pdp->eua.v, pdp->eua.l));
gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
return 0;
}
/* First find an exact APN name match */ /* First find an exact APN name match */
if (apn_name != NULL) if (apn_name != NULL)
apn = ggsn_find_apn(ggsn, name_buf); apn = ggsn_find_apn(ggsn, name_buf);
/* ignore if the APN has not been started */ /* ignore if the APN has not been started */
if (apn && !apn->started) if (apn && !apn->started)
apn = NULL; apn = NULL;
/* then try default (if any) */ /* then try default (if any) */
if (!apn) if (!apn) {
apn = ggsn->cfg.default_apn; switch (num_addr) {
case 2:
apn = ggsn->cfg.default_apn_v4v6;
break;
case 1:
if (in46a_is_v4(&addr[0])) {
apn = ggsn->cfg.default_apn_v4;
} else {
apn = ggsn->cfg.default_apn_v6;
}
break;
default:
/* in46a_from_eua() returned other than 1 or 2 ? */
OSMO_ASSERT(0);
break;
}
}
/* ignore if the APN has not been started */ /* ignore if the APN has not been started */
if (apn && !apn->started) if (apn && !apn->started)
apn = NULL; apn = NULL;
@ -467,23 +495,11 @@ int create_context_ind(struct pdp_t *pdp)
return 0; return 0;
} }
/* FIXME: we manually force all context requests to dynamic here! */
if (pdp->eua.l > 2)
pdp->eua.l = 2;
memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0)); memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */ memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
pdp->qos_neg.l = pdp->qos_req.l; pdp->qos_neg.l = pdp->qos_req.l;
memset(addr, 0, sizeof(addr));
if ((num_addr = in46a_from_eua(&pdp->eua, addr)) < 0) {
LOGPPDP(LOGL_ERROR, pdp, "Cannot decode EUA from MS/SGSN: %s\n",
osmo_hexdump(pdp->eua.v, pdp->eua.l));
gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
return 0;
}
/* Store the actual APN for logging and the VTY */ /* Store the actual APN for logging and the VTY */
rc = osmo_apn_from_str(pdp->apn_use.v, sizeof(pdp->apn_use.v), apn->cfg.name); rc = osmo_apn_from_str(pdp->apn_use.v, sizeof(pdp->apn_use.v), apn->cfg.name);
if (rc < 0) /* Unlikely this would happen, but anyway... */ if (rc < 0) /* Unlikely this would happen, but anyway... */

View File

@ -115,8 +115,10 @@ struct ggsn_ctx {
char *name; char *name;
/* Description string */ /* Description string */
char *description; char *description;
/* an APN that shall be used as default for any non-matching APN */ /* APNs that shall be used as default for any non-matching APN */
struct apn_ctx *default_apn; struct apn_ctx *default_apn_v4;
struct apn_ctx *default_apn_v6;
struct apn_ctx *default_apn_v4v6;
/* ADdress to which we listen for GTP */ /* ADdress to which we listen for GTP */
struct in46_addr listen_addr; struct in46_addr listen_addr;
/* Local GTP-C address advertised in GTP */ /* Local GTP-C address advertised in GTP */

View File

@ -269,30 +269,55 @@ DEFUN(cfg_ggsn_no_apn, cfg_ggsn_no_apn_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_ggsn_default_apn, cfg_ggsn_default_apn_cmd, DEFUN(cfg_ggsn_default_apn_v4, cfg_ggsn_default_apn_v4_cmd,
"default-apn NAME", "default-apn (v4|v6|v4v6) NAME",
"Set a default-APN to be used if no other APN matches\n" "Set a default-APN to be used if no other APN matches\n"
"Set a default-APN to be used if no other APN v4 matches\n"
"Set a default-APN to be used if no other APN v6 matches\n"
"Set a default-APN to be used if no other APN v4v6 matches\n"
"APN Name\n") "APN Name\n")
{ {
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index; struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
struct apn_ctx *apn; struct apn_ctx *apn;
apn = ggsn_find_apn(ggsn, argv[0]); /* backwards compatibility with 'default-apn NAME'. */
const char *apn_name = (argc > 1) ? argv[1] : argv[0];
const char *apn_type = (argc > 1) ? argv[0] : "v4";
apn = ggsn_find_apn(ggsn, apn_name);
if (!apn) { if (!apn) {
vty_out(vty, "%% No APN of name '%s' found%s", argv[0], VTY_NEWLINE); vty_out(vty, "%% No APN of name '%s' found%s", apn_name, VTY_NEWLINE);
return CMD_WARNING; return CMD_WARNING;
} }
ggsn->cfg.default_apn = apn; if (!strcmp(apn_type, "v4"))
ggsn->cfg.default_apn_v4 = apn;
if (!strcmp(apn_type, "v6"))
ggsn->cfg.default_apn_v6 = apn;
if (!strcmp(apn_type, "v4v6"))
ggsn->cfg.default_apn_v4v6 = apn;
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_ggsn_no_default_apn, cfg_ggsn_no_default_apn_cmd, ALIAS_DEPRECATED(cfg_ggsn_default_apn_v4, cfg_ggsn_default_apn_cmd,
"no default-apn", "default-apn NAME",
NO_STR "Remove default-APN to be used if no other APN matches\n") "Set a default-APN to be used if no other APN matches\n"
"APN Name\n")
DEFUN(cfg_ggsn_no_default_apn_v4, cfg_ggsn_no_default_apn_v4_cmd,
"no default-apn (v4|v6|v4v6)",
NO_STR "Remove default-APN to be used if no other APN v4 matches\n"
"Remove default-APN to be used if no other APN v4 matches\n"
"Remove default-APN to be used if no other APN v6 matches\n"
"Remove default-APN to be used if no other APN v4v6 matches\n")
{ {
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index; struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
ggsn->cfg.default_apn = NULL; if (!strcmp(argv[0], "v4"))
ggsn->cfg.default_apn_v4 = NULL;
if (!strcmp(argv[0], "v6"))
ggsn->cfg.default_apn_v6 = NULL;
if (!strcmp(argv[0], "v4v6"))
ggsn->cfg.default_apn_v4v6 = NULL;
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -790,8 +815,12 @@ static int config_write_ggsn(struct vty *vty)
vty_out(vty, " gtp user-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpu_addr), VTY_NEWLINE); vty_out(vty, " gtp user-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpu_addr), VTY_NEWLINE);
llist_for_each_entry(apn, &ggsn->apn_list, list) llist_for_each_entry(apn, &ggsn->apn_list, list)
config_write_apn(vty, apn); config_write_apn(vty, apn);
if (ggsn->cfg.default_apn) if (ggsn->cfg.default_apn_v4)
vty_out(vty, " default-apn %s%s", ggsn->cfg.default_apn->cfg.name, VTY_NEWLINE); vty_out(vty, " default-apn v4 %s%s", ggsn->cfg.default_apn_v4->cfg.name, VTY_NEWLINE);
if (ggsn->cfg.default_apn_v6)
vty_out(vty, " default-apn v6 %s%s", ggsn->cfg.default_apn_v6->cfg.name, VTY_NEWLINE);
if (ggsn->cfg.default_apn_v4v6)
vty_out(vty, " default-apn v4v6 %s%s", ggsn->cfg.default_apn_v4v6->cfg.name, VTY_NEWLINE);
if (ggsn->cfg.echo_interval) if (ggsn->cfg.echo_interval)
vty_out(vty, " echo-interval %u%s", ggsn->cfg.echo_interval, VTY_NEWLINE); vty_out(vty, " echo-interval %u%s", ggsn->cfg.echo_interval, VTY_NEWLINE);
/* must be last */ /* must be last */
@ -1096,7 +1125,8 @@ int ggsn_vty_init(void)
install_element(GGSN_NODE, &cfg_ggsn_apn_cmd); install_element(GGSN_NODE, &cfg_ggsn_apn_cmd);
install_element(GGSN_NODE, &cfg_ggsn_no_apn_cmd); install_element(GGSN_NODE, &cfg_ggsn_no_apn_cmd);
install_element(GGSN_NODE, &cfg_ggsn_default_apn_cmd); install_element(GGSN_NODE, &cfg_ggsn_default_apn_cmd);
install_element(GGSN_NODE, &cfg_ggsn_no_default_apn_cmd); install_element(GGSN_NODE, &cfg_ggsn_default_apn_v4_cmd);
install_element(GGSN_NODE, &cfg_ggsn_no_default_apn_v4_cmd);
install_element(GGSN_NODE, &cfg_ggsn_show_sgsn_cmd); install_element(GGSN_NODE, &cfg_ggsn_show_sgsn_cmd);
install_element(GGSN_NODE, &cfg_ggsn_echo_interval_cmd); install_element(GGSN_NODE, &cfg_ggsn_echo_interval_cmd);
install_element(GGSN_NODE, &cfg_ggsn_no_echo_interval_cmd); install_element(GGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);