From 979d1220f6e00db6b7712cb564c5b5b6100f10a1 Mon Sep 17 00:00:00 2001 From: Brady Johnson Date: Wed, 15 Apr 2020 10:53:33 +0200 Subject: [PATCH] Implement IPv6 PCEP connections --- pathd/path_pcep.c | 105 ++++++++++++++++++++++++++--------- pathd/path_pcep.h | 4 +- pathd/path_pcep_controller.c | 6 +- pathd/path_pcep_debug.c | 12 +++- pathd/path_pcep_lib.c | 33 ++++++++--- pathd/path_pcep_pcc.c | 49 +++++++++++----- 6 files changed, 154 insertions(+), 55 deletions(-) diff --git a/pathd/path_pcep.c b/pathd/path_pcep.c index 05d09c5dc02c..87faca70a5ef 100644 --- a/pathd/path_pcep.c +++ b/pathd/path_pcep.c @@ -248,31 +248,43 @@ DEFUN(show_pcep_counters, show_pcep_counters_cmd, "show pcep counters", } DEFUN_NOSH(pcep_cli_pcc, pcep_cli_pcc_cmd, - "pcc [ip A.B.C.D] [port (1024-65535)] [force_stateless]", + "pcc [ip A.B.C.D | ipv6 X:X::X:X] [port (1024-65535)] [force_stateless]", "PCC configuration\n" "PCC source ip\n" "PCC source IPv4 address\n" + "PCC source ip\n" + "PCC source IPv6 address\n" "PCC source port\n" "PCC source port value\n" "Force the PCC to use computation requests\n") { - /* TODO: Add support for IPv6 */ - struct in_addr pcc_addr; + struct ipaddr pcc_addr; uint32_t pcc_port = PCEP_DEFAULT_PORT; struct pcc_opts *opts, *opts_copy; bool force_stateless = false; int i = 1; - pcc_addr.s_addr = INADDR_ANY; + pcc_addr.ipaddr_v6 = in6addr_any; while (i < argc) { + if (0 == strcmp("ipv6", argv[i]->arg)) { + i++; + if (i >= argc) + return CMD_ERR_NO_MATCH; + if (!inet_pton(AF_INET6, argv[i]->arg, &pcc_addr.ipaddr_v6)) + return CMD_ERR_INCOMPLETE; + pcc_addr.ipa_type = IPADDR_V6; + i++; + continue; + } if (0 == strcmp("ip", argv[i]->arg)) { i++; if (i >= argc) return CMD_ERR_NO_MATCH; - if (!inet_pton(AF_INET, argv[i]->arg, &pcc_addr.s_addr)) + if (!inet_pton(AF_INET, argv[i]->arg, &pcc_addr.ipaddr_v4.s_addr)) return CMD_ERR_INCOMPLETE; + pcc_addr.ipa_type = IPADDR_V4; i++; continue; } @@ -295,7 +307,12 @@ DEFUN_NOSH(pcep_cli_pcc, pcep_cli_pcc_cmd, } opts = XCALLOC(MTYPE_PCEP, sizeof(*opts)); - opts->addr = pcc_addr; + opts->addr.ipa_type = pcc_addr.ipa_type; + if (IS_IPADDR_V6(&pcc_addr)) { + memcpy(&opts->addr.ipaddr_v6, &pcc_addr.ipaddr_v6, sizeof(struct in6_addr)); + } else { + opts->addr.ipaddr_v4.s_addr = pcc_addr.ipaddr_v4.s_addr; + } opts->port = pcc_port; opts->force_stateless = force_stateless; @@ -314,32 +331,49 @@ DEFUN_NOSH(pcep_cli_pcc, pcep_cli_pcc_cmd, } DEFUN(pcep_cli_pce_opts, pcep_cli_pce_opts_cmd, - "pce ip A.B.C.D [port (1024-65535)] [sr-draft07]", + "pce [ip A.B.C.D | ipv6 X:X::X:X] [port (1024-65535)] [sr-draft07]", "PCE configuration\n" - "PCE address\n" + "PCE IPv4 address\n" "Remote PCE server IPv4 address\n" + "PCE IPv6 address\n" + "Remote PCE server IPv6 address\n" "Remote PCE server port\n" "Remote PCE server port value\n" "Use the draft 07 of PCEP segemnt routing\n") { /* TODO: Add support for multiple PCE */ - /* TODO: Add support for IPv6 */ - struct in_addr pce_addr; + struct ipaddr pce_addr; uint32_t pce_port = PCEP_DEFAULT_PORT; struct pce_opts *pce_opts, *pce_opts_copy; bool draft07 = false; int i = 1; - if (0 != strcmp("ip", argv[i]->arg)) + /* Get the first argument, should be either ip or ipv6 */ + pce_addr.ipa_type = IPADDR_V4; + if (0 == strcmp("ipv6", argv[i]->arg)) { + pce_addr.ipa_type = IPADDR_V6; + } else if (0 != strcmp("ip", argv[i]->arg)) { return CMD_ERR_NO_MATCH; + } + + /* Get the first argument value */ i++; - if (i >= argc) + if (i >= argc) { return CMD_ERR_NO_MATCH; - if (!inet_pton(AF_INET, argv[i]->arg, &pce_addr.s_addr)) - return CMD_ERR_INCOMPLETE; - i++; + } + if (IS_IPADDR_V6(&pce_addr)) { + if (!inet_pton(AF_INET6, argv[i]->arg, &pce_addr.ipaddr_v6)) { + return CMD_ERR_INCOMPLETE; + } + } else { + if (!inet_pton(AF_INET, argv[i]->arg, &pce_addr.ipaddr_v4)) { + return CMD_ERR_INCOMPLETE; + } + } + /* Handle the rest of the arguments */ + i++; while (i < argc) { if (0 == strcmp("port", argv[i]->arg)) { i++; @@ -360,7 +394,12 @@ DEFUN(pcep_cli_pce_opts, pcep_cli_pce_opts_cmd, } pce_opts = XCALLOC(MTYPE_PCEP, sizeof(*pce_opts)); - pce_opts->addr = pce_addr; + pce_opts->addr.ipa_type = pce_addr.ipa_type; + if (IS_IPADDR_V6(&pce_addr)) { + memcpy(&pce_opts->addr.ipaddr_v6, &pce_addr.ipaddr_v6, sizeof(struct in6_addr)); + } else { + pce_opts->addr.ipaddr_v4 = pce_addr.ipaddr_v4; + } pce_opts->port = pce_port; pce_opts->draft07 = draft07; @@ -457,15 +496,21 @@ int pcep_cli_debug_set_all(uint32_t flags, bool set) int pcep_cli_pcc_config_write(struct vty *vty) { - /* TODO: Add support for IPv6 */ - char buff[128] = ""; int lines = 0; if (NULL != pcep_g->pcc_opts) { - if (INADDR_ANY != pcep_g->pcc_opts->addr.s_addr) - csnprintfrr(buff, sizeof(buff), " ip %pI4", - &pcep_g->pcc_opts->addr); + if (IS_IPADDR_V6(&pcep_g->pcc_opts->addr)) { + if (0 != memcmp(&in6addr_any, &pcep_g->pcc_opts->addr.ipaddr_v6, sizeof(struct in6_addr))) { + csnprintfrr(buff, sizeof(buff), " ip %pI6", + &pcep_g->pcc_opts->addr.ipaddr_v6); + } + } else { + if (INADDR_ANY != pcep_g->pcc_opts->addr.ipaddr_v4.s_addr) { + csnprintfrr(buff, sizeof(buff), " ip %pI4", + &pcep_g->pcc_opts->addr.ipaddr_v4); + } + } if (PCEP_DEFAULT_PORT != pcep_g->pcc_opts->port) csnprintfrr(buff, sizeof(buff), " port %d", pcep_g->pcc_opts->port); @@ -476,14 +521,20 @@ int pcep_cli_pcc_config_write(struct vty *vty) for (int i = 0; i < MAX_PCC; i++) { struct pce_opts *pce_opts = pcep_g->pce_opts[i]; if (NULL != pce_opts) { - if (PCEP_DEFAULT_PORT != pce_opts->port) + if (PCEP_DEFAULT_PORT != pce_opts->port) { csnprintfrr(buff, sizeof(buff), " port %d", pce_opts->port); - if (true == pce_opts->draft07) - csnprintfrr(buff, sizeof(buff), - " sr-draft07"); - vty_out(vty, " pce ip %pI4%s\n", - &pce_opts->addr, buff); + } + if (true == pce_opts->draft07) { + csnprintfrr(buff, sizeof(buff), " sr-draft07"); + } + if (IS_IPADDR_V6(&pce_opts->addr)) { + vty_out(vty, " pce ipv6 %pI6%s\n", + &pce_opts->addr.ipaddr_v6, buff); + } else { + vty_out(vty, " pce ip %pI4%s\n", + &pce_opts->addr.ipaddr_v4, buff); + } buff[0] = 0; lines++; } diff --git a/pathd/path_pcep.h b/pathd/path_pcep.h index 3fa171c78eea..0b96abf23aa9 100644 --- a/pathd/path_pcep.h +++ b/pathd/path_pcep.h @@ -79,13 +79,13 @@ } while (0) struct pce_opts { - struct in_addr addr; + struct ipaddr addr; short port; bool draft07; }; struct pcc_opts { - struct in_addr addr; + struct ipaddr addr; short port; bool force_stateless; }; diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c index 2d6435793ec8..29f32c72f848 100644 --- a/pathd/path_pcep_controller.c +++ b/pathd/path_pcep_controller.c @@ -184,8 +184,10 @@ int pcep_ctrl_initialize(struct thread_master *main_thread, ctrl_state->t_poll = NULL; ctrl_state->pcc_count = 0; ctrl_state->pcc_opts = - XCALLOC(MTYPE_PCEP, sizeof(*ctrl_state->pcc_opts)); - ctrl_state->pcc_opts->addr.s_addr = INADDR_ANY; + XCALLOC(MTYPE_PCEP, sizeof(*ctrl_state->pcc_opts)); + /* Default to IPv4 */ + ctrl_state->pcc_opts->addr.ipa_type = IPADDR_V4; + ctrl_state->pcc_opts->addr.ipaddr_v4.s_addr = INADDR_ANY; ctrl_state->pcc_opts->port = PCEP_DEFAULT_PORT; /* Keep the state reference for events */ diff --git a/pathd/path_pcep_debug.c b/pathd/path_pcep_debug.c index e91c33f39a0d..bbf55058f0eb 100644 --- a/pathd/path_pcep_debug.c +++ b/pathd/path_pcep_debug.c @@ -570,7 +570,11 @@ void _format_pcc_opts(int ps, struct pcc_opts *opts) } else { int ps2 = ps + DEBUG_IDENT_SIZE; PCEP_FORMAT("\n"); - PCEP_FORMAT("%*saddr: %pI4\n", ps2, "", &opts->addr); + if (IS_IPADDR_V6(&opts->addr)) { + PCEP_FORMAT("%*saddr: %pI6\n", ps2, "", &opts->addr.ipaddr_v6); + } else { + PCEP_FORMAT("%*saddr: %pI4\n", ps2, "", &opts->addr.ipaddr_v4); + } PCEP_FORMAT("%*sport: %i\n", ps2, "", opts->port); } } @@ -582,7 +586,11 @@ void _format_pce_opts(int ps, struct pce_opts *opts) } else { int ps2 = ps + DEBUG_IDENT_SIZE; PCEP_FORMAT("\n"); - PCEP_FORMAT("%*saddr: %pI4\n", ps2, "", &opts->addr); + if (IS_IPADDR_V6(&opts->addr)) { + PCEP_FORMAT("%*saddr: %pI6\n", ps2, "", &opts->addr.ipaddr_v6); + } else { + PCEP_FORMAT("%*saddr: %pI4\n", ps2, "", &opts->addr.ipaddr_v4); + } PCEP_FORMAT("%*sport: %i\n", ps2, "", opts->port); } } diff --git a/pathd/path_pcep_lib.c b/pathd/path_pcep_lib.c index d2d81201fb87..c09ed2b2a42b 100644 --- a/pathd/path_pcep_lib.c +++ b/pathd/path_pcep_lib.c @@ -85,7 +85,13 @@ pcep_session *pcep_lib_connect(struct pcc_opts *pcc_opts, config = create_default_pcep_configuration(); config->dst_pcep_port = pce_opts->port; config->src_pcep_port = pcc_opts->port; - config->src_ip = pcc_opts->addr; + if (IS_IPADDR_V6(&pcc_opts->addr)) { + config->is_src_ipv6 = true; + memcpy(&config->src_ip.src_ipv6, &pcc_opts->addr.ipaddr_v6, sizeof(struct in6_addr)); + } else { + config->is_src_ipv6 = false; + config->src_ip.src_ipv4 = pcc_opts->addr.ipaddr_v4; + } config->support_stateful_pce_lsp_update = !pcc_opts->force_stateless; config->support_pce_lsp_instantiation = false; @@ -99,7 +105,11 @@ pcep_session *pcep_lib_connect(struct pcc_opts *pcc_opts, config->pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = pce_opts->draft07; - sess = connect_pce(config, &pce_opts->addr); + if (IS_IPADDR_V6(&pce_opts->addr)) { + sess = connect_pce_ipv6(config, &pce_opts->addr.ipaddr_v6); + } else { + sess = connect_pce(config, &pce_opts->addr.ipaddr_v4); + } destroy_pcep_configuration(config); return sess; } @@ -119,23 +129,28 @@ struct pcep_message *pcep_lib_format_report(struct path *path) struct pcep_message *pcep_lib_format_request(uint32_t reqid, struct ipaddr *src, struct ipaddr *dst) { - /* TODO: Add support for IPv6 */ - assert(IS_IPADDR_V4(src)); - assert(IS_IPADDR_V4(dst)); + assert(src->ipa_type ==dst->ipa_type); double_linked_list *rp_tlvs; struct pcep_object_tlv_path_setup_type *setup_type_tlv; struct pcep_object_rp *rp; - struct pcep_object_endpoints_ipv4 *endpoints; + struct pcep_object_endpoints_ipv4 *endpoints_ipv4; + struct pcep_object_endpoints_ipv6 *endpoints_ipv6; rp_tlvs = dll_initialize(); setup_type_tlv = pcep_tlv_create_path_setup_type(SR_TE_PST); dll_append(rp_tlvs, setup_type_tlv); rp = pcep_obj_create_rp(0, false, false, false, reqid, rp_tlvs); - endpoints = - pcep_obj_create_endpoint_ipv4(&src->ipaddr_v4, &dst->ipaddr_v4); - return pcep_msg_create_request(rp, endpoints, NULL); + if (IS_IPADDR_V6(src)) { + endpoints_ipv6 = + pcep_obj_create_endpoint_ipv6(&src->ipaddr_v6, &dst->ipaddr_v6); + return pcep_msg_create_request_ipv6(rp, endpoints_ipv6, NULL); + } else { + endpoints_ipv4 = + pcep_obj_create_endpoint_ipv4(&src->ipaddr_v4, &dst->ipaddr_v4); + return pcep_msg_create_request(rp, endpoints_ipv4, NULL); + } } struct path *pcep_lib_parse_path(struct pcep_message *msg) diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index 7d27403720e7..bffa7a02724a 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -195,11 +195,21 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) pcep_lib_connect(pcc_state->pcc_opts, pcc_state->pce_opts); if (NULL == pcc_state->sess) { - flog_warn(EC_PATH_PCEP_LIB_CONNECT, - "failed to connect to PCE %pI4:%d from %pI4:%d", - &pcc_state->pce_opts->addr, pcc_state->pce_opts->port, - &pcc_state->pcc_opts->addr, - pcc_state->pcc_opts->port); + if (IS_IPADDR_V6(&pcc_state->pce_opts->addr)) { + flog_warn(EC_PATH_PCEP_LIB_CONNECT, + "failed to connect to PCE %pI6:%d from %pI6:%d", + &pcc_state->pce_opts->addr.ipaddr_v6, + pcc_state->pce_opts->port, + &pcc_state->pcc_opts->addr.ipaddr_v6, + pcc_state->pcc_opts->port); + } else { + flog_warn(EC_PATH_PCEP_LIB_CONNECT, + "failed to connect to PCE %pI4:%d from %pI4:%d", + &pcc_state->pce_opts->addr.ipaddr_v4, + pcc_state->pce_opts->port, + &pcc_state->pcc_opts->addr.ipaddr_v4, + pcc_state->pcc_opts->port); + } schedule_reconnect(ctrl_state, pcc_state); return 0; } @@ -402,8 +412,13 @@ void handle_pcep_lsp_update(struct ctrl_state *ctrl_state, { struct path *path; path = pcep_lib_parse_path(msg); - path->sender.ipa_type = IPADDR_V4; - path->sender.ipaddr_v4 = pcc_state->pce_opts->addr; + if (IS_IPADDR_V6(&pcc_state->pce_opts->addr)) { + path->sender.ipa_type = IPADDR_V6; + memcpy(&path->sender.ipaddr_v6, &pcc_state->pce_opts->addr.ipaddr_v6, sizeof(struct in6_addr)); + } else { + path->sender.ipa_type = IPADDR_V4; + path->sender.ipaddr_v4 = pcc_state->pce_opts->addr.ipaddr_v4; + } lookup_nbkey(pcc_state, path); push_srpid(pcc_state, path); @@ -509,20 +524,28 @@ void send_comp_request(struct ctrl_state *ctrl_state, struct pcep_message *msg; struct ipaddr src; - /* TODO: Add support for IPv6 */ - assert(IS_IPADDR_V4(&nbkey->endpoint)); /* The source address need to be defined explicitly for now */ - assert(INADDR_ANY != pcc_state->pcc_opts->addr.s_addr); + if (IS_IPADDR_V6(&pcc_state->pcc_opts->addr)) { + assert(0 != memcmp(&in6addr_any, &pcc_state->pcc_opts->addr.ipaddr_v6, + sizeof(struct in6_addr))); + } else { + assert(INADDR_ANY != pcc_state->pcc_opts->addr.ipaddr_v4.s_addr); + } reqid = push_req(pcc_state, nbkey); /* TODO: Add a timer to retry the computation request */ PCEP_DEBUG("%s Sending computation request for path from %pI4 to %pI4", - pcc_state->tag, &pcc_state->pcc_opts->addr, + pcc_state->tag, &pcc_state->pcc_opts->addr.ipaddr_v4, &nbkey->endpoint.ipaddr_v4); - src.ipa_type = IPADDR_V4; - src.ipaddr_v4.s_addr = pcc_state->pcc_opts->addr.s_addr; + src.ipa_type = pcc_state->pcc_opts->addr.ipa_type; + if (IS_IPADDR_V6(&pcc_state->pcc_opts->addr)) { + memcpy(&src.ipaddr_v6, &pcc_state->pcc_opts->addr.ipaddr_v6, + sizeof(struct in6_addr)); + } else { + src.ipaddr_v4.s_addr = pcc_state->pcc_opts->addr.ipaddr_v4.s_addr; + } msg = pcep_lib_format_request(reqid, &src, &nbkey->endpoint); send_pcep_message(ctrl_state, pcc_state, msg);