From: Donald Sharp Date: Sun, 13 Mar 2022 22:19:33 +0000 (-0400) Subject: Merge pull request #10447 from ton31337/fix/json_with_whitespaces X-Git-Tag: frr-8.5.1~1153 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=7baebfb715fe61244930c18821f4c38d392bfeb0;hp=77a2f8e59297601a2382efc8da67009a2addc6ad;p=mirror_frr.git Merge pull request #10447 from ton31337/fix/json_with_whitespaces *: Fix JSON keys with whitespaces and PascalCase --- diff --git a/.clang-format b/.clang-format index a620b5c2c..b01157b05 100644 --- a/.clang-format +++ b/.clang-format @@ -28,6 +28,9 @@ ForEachMacros: - frr_each - frr_each_safe - frr_each_from + - frr_rev_each + - frr_rev_each_safe + - frr_rev_each_from - frr_with_mutex - frr_with_privs - LIST_FOREACH diff --git a/babeld/babeld.c b/babeld/babeld.c index 0104620cd..a1e00bfb8 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -49,11 +49,11 @@ THE SOFTWARE. DEFINE_MGROUP(BABELD, "babeld"); DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure"); -static int babel_init_routing_process(struct thread *thread); +static void babel_init_routing_process(struct thread *thread); static void babel_get_myid(void); static void babel_initial_noise(void); -static int babel_read_protocol (struct thread *thread); -static int babel_main_loop(struct thread *thread); +static void babel_read_protocol(struct thread *thread); +static void babel_main_loop(struct thread *thread); static void babel_set_timer(struct timeval *timeout); static void babel_fill_with_next_timeout(struct timeval *tv); static void @@ -175,8 +175,7 @@ fail: } /* thread reading entries form others babel daemons */ -static int -babel_read_protocol (struct thread *thread) +static void babel_read_protocol(struct thread *thread) { int rc; struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); @@ -207,14 +206,12 @@ babel_read_protocol (struct thread *thread) /* re-add thread */ thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read); - return 0; } /* Zebra will give some information, especially about interfaces. This function must be call with a litte timeout wich may give zebra the time to do his job, making these inits have sense. */ -static int -babel_init_routing_process(struct thread *thread) +static void babel_init_routing_process(struct thread *thread) { myseqno = (frr_weak_random() & 0xFFFF); babel_get_myid(); @@ -222,7 +219,6 @@ babel_init_routing_process(struct thread *thread) debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid)); babel_initial_noise(); babel_main_loop(thread);/* this function self-add to the t_update thread */ - return 0; } /* fill "myid" with an unique id (only if myid != {0}). */ @@ -327,8 +323,7 @@ babel_clean_routing_process(void) } /* Function used with timeout. */ -static int -babel_main_loop(struct thread *thread) +static void babel_main_loop(struct thread *thread) { struct timeval tv; struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); @@ -348,8 +343,8 @@ babel_main_loop(struct thread *thread) /* it happens often to have less than 1 ms, it's bad. */ timeval_add_msec(&tv, &tv, 300); babel_set_timer(&tv); - return 0; - } + return; + } gettime(&babel_now); @@ -410,7 +405,6 @@ babel_main_loop(struct thread *thread) } assert(0); /* this line should never be reach */ - return 0; } static void diff --git a/babeld/message.c b/babeld/message.c index 5c2e29d8b..559b8c4e4 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -140,12 +140,12 @@ parse_update_subtlv(const unsigned char *a, int alen, continue; } - if(i + 1 > alen) { + if(i + 1 >= alen) { flog_err(EC_BABEL_PACKET, "Received truncated attributes."); return; } len = a[i + 1]; - if(i + len > alen) { + if(i + len + 2 > alen) { flog_err(EC_BABEL_PACKET, "Received truncated attributes."); return; } @@ -182,19 +182,19 @@ parse_hello_subtlv(const unsigned char *a, int alen, int type, len, i = 0, ret = 0; while(i < alen) { - type = a[0]; + type = a[i]; if(type == SUBTLV_PAD1) { i++; continue; } - if(i + 1 > alen) { + if(i + 1 >= alen) { flog_err(EC_BABEL_PACKET, "Received truncated sub-TLV on Hello message."); return -1; } len = a[i + 1]; - if(i + len > alen) { + if(i + len + 2 > alen) { flog_err(EC_BABEL_PACKET, "Received truncated sub-TLV on Hello message."); return -1; @@ -228,19 +228,19 @@ parse_ihu_subtlv(const unsigned char *a, int alen, int type, len, i = 0, ret = 0; while(i < alen) { - type = a[0]; + type = a[i]; if(type == SUBTLV_PAD1) { i++; continue; } - if(i + 1 > alen) { + if(i + 1 >= alen) { flog_err(EC_BABEL_PACKET, "Received truncated sub-TLV on IHU message."); return -1; } len = a[i + 1]; - if(i + len > alen) { + if(i + len + 2 > alen) { flog_err(EC_BABEL_PACKET, "Received truncated sub-TLV on IHU message."); return -1; @@ -288,13 +288,18 @@ channels_len(unsigned char *channels) static int babel_packet_examin(const unsigned char *packet, int packetlen) { - unsigned i = 0, bodylen; + int i = 0, bodylen; const unsigned char *message; unsigned char type, len; if(packetlen < 4 || packet[0] != 42 || packet[1] != 2) return 1; DO_NTOHS(bodylen, packet + 2); + if(bodylen + 4 > packetlen) { + debugf(BABEL_DEBUG_COMMON, "Received truncated packet (%d + 4 > %d).", + bodylen, packetlen); + return 1; + } while (i < bodylen){ message = packet + 4 + i; type = message[0]; @@ -302,12 +307,12 @@ babel_packet_examin(const unsigned char *packet, int packetlen) i++; continue; } - if(i + 1 > bodylen) { + if(i + 2 > bodylen) { debugf(BABEL_DEBUG_COMMON,"Received truncated message."); return 1; } len = message[1]; - if(i + len > bodylen) { + if(i + len + 2 > bodylen) { debugf(BABEL_DEBUG_COMMON,"Received truncated message."); return 1; } @@ -366,12 +371,6 @@ parse_packet(const unsigned char *from, struct interface *ifp, DO_NTOHS(bodylen, packet + 2); - if(bodylen + 4 > packetlen) { - flog_err(EC_BABEL_PACKET, "Received truncated packet (%d + 4 > %d).", - bodylen, packetlen); - bodylen = packetlen - 4; - } - i = 0; while(i < bodylen) { message = packet + 4 + i; diff --git a/bfdd/bfd.c b/bfdd/bfd.c index fbe0436b5..455dd9fe8 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -609,27 +609,23 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, return bfd_key_lookup(key); } -int bfd_xmt_cb(struct thread *t) +void bfd_xmt_cb(struct thread *t) { struct bfd_session *bs = THREAD_ARG(t); ptm_bfd_xmt_TO(bs, 0); - - return 0; } -int bfd_echo_xmt_cb(struct thread *t) +void bfd_echo_xmt_cb(struct thread *t) { struct bfd_session *bs = THREAD_ARG(t); if (bs->echo_xmt_TO > 0) ptm_bfd_echo_xmt_TO(bs); - - return 0; } /* Was ptm_bfd_detect_TO() */ -int bfd_recvtimer_cb(struct thread *t) +void bfd_recvtimer_cb(struct thread *t) { struct bfd_session *bs = THREAD_ARG(t); @@ -639,12 +635,10 @@ int bfd_recvtimer_cb(struct thread *t) ptm_bfd_sess_dn(bs, BD_CONTROL_EXPIRED); break; } - - return 0; } /* Was ptm_bfd_echo_detect_TO() */ -int bfd_echo_recvtimer_cb(struct thread *t) +void bfd_echo_recvtimer_cb(struct thread *t) { struct bfd_session *bs = THREAD_ARG(t); @@ -654,8 +648,6 @@ int bfd_echo_recvtimer_cb(struct thread *t) ptm_bfd_sess_dn(bs, BD_ECHO_FAILED); break; } - - return 0; } struct bfd_session *bfd_session_new(void) @@ -1424,7 +1416,7 @@ int strtosa(const char *addr, struct sockaddr_any *sa) void integer2timestr(uint64_t time, char *buf, size_t buflen) { - unsigned int year, month, day, hour, minute, second; + uint64_t year, month, day, hour, minute, second; int rv; #define MINUTES (60) @@ -1436,7 +1428,7 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen) year = time / YEARS; time -= year * YEARS; - rv = snprintf(buf, buflen, "%u year(s), ", year); + rv = snprintfrr(buf, buflen, "%" PRIu64 " year(s), ", year); buf += rv; buflen -= rv; } @@ -1444,7 +1436,7 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen) month = time / MONTHS; time -= month * MONTHS; - rv = snprintf(buf, buflen, "%u month(s), ", month); + rv = snprintfrr(buf, buflen, "%" PRIu64 " month(s), ", month); buf += rv; buflen -= rv; } @@ -1452,7 +1444,7 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen) day = time / DAYS; time -= day * DAYS; - rv = snprintf(buf, buflen, "%u day(s), ", day); + rv = snprintfrr(buf, buflen, "%" PRIu64 " day(s), ", day); buf += rv; buflen -= rv; } @@ -1460,7 +1452,7 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen) hour = time / HOURS; time -= hour * HOURS; - rv = snprintf(buf, buflen, "%u hour(s), ", hour); + rv = snprintfrr(buf, buflen, "%" PRIu64 " hour(s), ", hour); buf += rv; buflen -= rv; } @@ -1468,12 +1460,12 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen) minute = time / MINUTES; time -= minute * MINUTES; - rv = snprintf(buf, buflen, "%u minute(s), ", minute); + rv = snprintfrr(buf, buflen, "%" PRIu64 " minute(s), ", minute); buf += rv; buflen -= rv; } second = time % MINUTES; - snprintf(buf, buflen, "%u second(s)", second); + snprintfrr(buf, buflen, "%" PRIu64 " second(s)", second); } const char *bs_to_string(const struct bfd_session *bs) diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 473886901..7ab5ef13b 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -426,7 +426,7 @@ int control_init(const char *path); void control_shutdown(void); int control_notify(struct bfd_session *bs, uint8_t notify_state); int control_notify_config(const char *op, struct bfd_session *bs); -int control_accept(struct thread *t); +void control_accept(struct thread *t); /* @@ -556,7 +556,7 @@ int bp_echov6_socket(const struct vrf *vrf); void ptm_bfd_snd(struct bfd_session *bfd, int fbit); void ptm_bfd_echo_snd(struct bfd_session *bfd); -int bfd_recv_cb(struct thread *t); +void bfd_recv_cb(struct thread *t); /* @@ -690,10 +690,10 @@ unsigned long bfd_get_session_count(void); /* Export callback functions for `event.c`. */ extern struct thread_master *master; -int bfd_recvtimer_cb(struct thread *t); -int bfd_echo_recvtimer_cb(struct thread *t); -int bfd_xmt_cb(struct thread *t); -int bfd_echo_xmt_cb(struct thread *t); +void bfd_recvtimer_cb(struct thread *t); +void bfd_echo_recvtimer_cb(struct thread *t); +void bfd_xmt_cb(struct thread *t); +void bfd_echo_xmt_cb(struct thread *t); extern struct in6_addr zero_addr; diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 8eda78ebd..34b171f40 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -531,7 +531,7 @@ static void cp_debug(bool mhop, struct sockaddr_any *peer, mhop ? "yes" : "no", peerstr, localstr, portstr, vrfstr); } -int bfd_recv_cb(struct thread *t) +void bfd_recv_cb(struct thread *t) { int sd = THREAD_FD(t); struct bfd_session *bfd; @@ -552,7 +552,7 @@ int bfd_recv_cb(struct thread *t) /* Handle echo packets. */ if (sd == bvrf->bg_echo || sd == bvrf->bg_echov6) { ptm_bfd_process_echo_pkt(bvrf, sd); - return 0; + return; } /* Sanitize input/output. */ @@ -590,14 +590,14 @@ int bfd_recv_cb(struct thread *t) if (mlen < BFD_PKT_LEN) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "too small (%ld bytes)", mlen); - return 0; + return; } /* Validate single hop packet TTL. */ if ((!is_mhop) && (ttl != BFD_TTL_VAL)) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "invalid TTL: %d expected %d", ttl, BFD_TTL_VAL); - return 0; + return; } /* @@ -611,24 +611,24 @@ int bfd_recv_cb(struct thread *t) if (BFD_GETVER(cp->diag) != BFD_VERSION) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "bad version %d", BFD_GETVER(cp->diag)); - return 0; + return; } if (cp->detect_mult == 0) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "detect multiplier set to zero"); - return 0; + return; } if ((cp->len < BFD_PKT_LEN) || (cp->len > mlen)) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "too small"); - return 0; + return; } if (cp->discrs.my_discr == 0) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "'my discriminator' is zero"); - return 0; + return; } /* Find the session that this packet belongs. */ @@ -636,7 +636,7 @@ int bfd_recv_cb(struct thread *t) if (bfd == NULL) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "no session found"); - return 0; + return; } /* @@ -648,7 +648,7 @@ int bfd_recv_cb(struct thread *t) cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "exceeded max hop count (expected %d, got %d)", bfd->mh_ttl, ttl); - return 0; + return; } } else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) { bfd->local_address = local; @@ -733,8 +733,6 @@ int bfd_recv_cb(struct thread *t) /* Send the control packet with the final bit immediately. */ ptm_bfd_snd(bfd, 1); } - - return 0; } /* diff --git a/bfdd/control.c b/bfdd/control.c index e772aadfc..473843fe2 100644 --- a/bfdd/control.c +++ b/bfdd/control.c @@ -52,8 +52,8 @@ struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, struct bfd_control_socket *control_new(int sd); static void control_free(struct bfd_control_socket *bcs); static void control_reset_buf(struct bfd_control_buffer *bcb); -static int control_read(struct thread *t); -static int control_write(struct thread *t); +static void control_read(struct thread *t); +static void control_write(struct thread *t); static void control_handle_request_add(struct bfd_control_socket *bcs, struct bfd_control_msg *bcm); @@ -155,21 +155,19 @@ void control_shutdown(void) } } -int control_accept(struct thread *t) +void control_accept(struct thread *t) { int csock, sd = THREAD_FD(t); csock = accept(sd, NULL, 0); if (csock == -1) { zlog_warn("%s: accept: %s", __func__, strerror(errno)); - return 0; + return; } control_new(csock); thread_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev); - - return 0; } @@ -394,7 +392,7 @@ static void control_reset_buf(struct bfd_control_buffer *bcb) bcb->bcb_left = 0; } -static int control_read(struct thread *t) +static void control_read(struct thread *t) { struct bfd_control_socket *bcs = THREAD_ARG(t); struct bfd_control_buffer *bcb = &bcs->bcs_bin; @@ -417,7 +415,7 @@ static int control_read(struct thread *t) bread = read(sd, &bcm, sizeof(bcm)); if (bread == 0) { control_free(bcs); - return 0; + return; } if (bread < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) @@ -425,7 +423,7 @@ static int control_read(struct thread *t) zlog_warn("%s: read: %s", __func__, strerror(errno)); control_free(bcs); - return 0; + return; } /* Validate header fields. */ @@ -434,14 +432,14 @@ static int control_read(struct thread *t) zlog_debug("%s: client closed due small message length: %d", __func__, bcm.bcm_length); control_free(bcs); - return 0; + return; } if (bcm.bcm_ver != BMV_VERSION_1) { zlog_debug("%s: client closed due bad version: %d", __func__, bcm.bcm_ver); control_free(bcs); - return 0; + return; } /* Prepare the buffer to load the message. */ @@ -456,7 +454,7 @@ static int control_read(struct thread *t) zlog_warn("%s: not enough memory for message size: %zu", __func__, bcb->bcb_left); control_free(bcs); - return 0; + return; } memcpy(bcb->bcb_buf, &bcm, sizeof(bcm)); @@ -469,7 +467,7 @@ skip_header: bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); if (bread == 0) { control_free(bcs); - return 0; + return; } if (bread < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) @@ -477,7 +475,7 @@ skip_header: zlog_warn("%s: read: %s", __func__, strerror(errno)); control_free(bcs); - return 0; + return; } bcb->bcb_pos += bread; @@ -518,11 +516,9 @@ skip_header: schedule_next_read: bcs->bcs_ev = NULL; thread_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); - - return 0; } -static int control_write(struct thread *t) +static void control_write(struct thread *t) { struct bfd_control_socket *bcs = THREAD_ARG(t); struct bfd_control_buffer *bcb = bcs->bcs_bout; @@ -532,19 +528,19 @@ static int control_write(struct thread *t) bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); if (bwrite == 0) { control_free(bcs); - return 0; + return; } if (bwrite < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { bcs->bcs_outev = NULL; thread_add_write(master, control_write, bcs, bcs->bcs_sd, &bcs->bcs_outev); - return 0; + return; } zlog_warn("%s: write: %s", __func__, strerror(errno)); control_free(bcs); - return 0; + return; } bcb->bcb_pos += bwrite; @@ -553,12 +549,10 @@ static int control_write(struct thread *t) bcs->bcs_outev = NULL; thread_add_write(master, control_write, bcs, bcs->bcs_sd, &bcs->bcs_outev); - return 0; + return; } control_queue_dequeue(bcs); - - return 0; } diff --git a/bfdd/dplane.c b/bfdd/dplane.c index 9dee2a558..c1081643e 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -107,7 +107,7 @@ struct bfd_dplane_ctx { */ typedef void (*bfd_dplane_expect_cb)(struct bfddp_message *msg, void *arg); -static int bfd_dplane_client_connect(struct thread *t); +static void bfd_dplane_client_connect(struct thread *t); static bool bfd_dplane_client_connecting(struct bfd_dplane_ctx *bdc); static void bfd_dplane_ctx_free(struct bfd_dplane_ctx *bdc); static int _bfd_dplane_add_session(struct bfd_dplane_ctx *bdc, @@ -325,17 +325,15 @@ static ssize_t bfd_dplane_flush(struct bfd_dplane_ctx *bdc) return total; } -static int bfd_dplane_write(struct thread *t) +static void bfd_dplane_write(struct thread *t) { struct bfd_dplane_ctx *bdc = THREAD_ARG(t); /* Handle connection stage. */ if (bdc->connecting && bfd_dplane_client_connecting(bdc)) - return 0; + return; bfd_dplane_flush(bdc); - - return 0; } static void @@ -614,18 +612,17 @@ skip_read: return 0; } -static int bfd_dplane_read(struct thread *t) +static void bfd_dplane_read(struct thread *t) { struct bfd_dplane_ctx *bdc = THREAD_ARG(t); int rv; rv = bfd_dplane_expect(bdc, 0, bfd_dplane_handle_message, NULL); if (rv == -1) - return 0; + return; stream_pulldown(bdc->inbuf); thread_add_read(master, bfd_dplane_read, bdc, bdc->sock, &bdc->inbufev); - return 0; } static void _bfd_session_register_dplane(struct hash_bucket *hb, void *arg) @@ -835,7 +832,7 @@ static uint16_t bfd_dplane_request_counters(const struct bfd_session *bs) /* * Data plane listening socket. */ -static int bfd_dplane_accept(struct thread *t) +static void bfd_dplane_accept(struct thread *t) { struct bfd_global *bg = THREAD_ARG(t); struct bfd_dplane_ctx *bdc; @@ -858,7 +855,6 @@ static int bfd_dplane_accept(struct thread *t) reschedule_and_return: thread_add_read(master, bfd_dplane_accept, bg, bg->bg_dplane_sock, &bglobal.bg_dplane_sockev); - return 0; } /* @@ -916,7 +912,7 @@ static bool bfd_dplane_client_connecting(struct bfd_dplane_ctx *bdc) } } -static int bfd_dplane_client_connect(struct thread *t) +static void bfd_dplane_client_connect(struct thread *t) { struct bfd_dplane_ctx *bdc = THREAD_ARG(t); int rv, sock; @@ -965,15 +961,12 @@ static int bfd_dplane_client_connect(struct thread *t) _bfd_dplane_client_bootstrap(bdc); } - return 0; - reschedule_connect: THREAD_OFF(bdc->inbufev); THREAD_OFF(bdc->outbufev); socket_close(&sock); thread_add_timer(master, bfd_dplane_client_connect, bdc, 3, &bdc->connectev); - return 0; } static void bfd_dplane_client_init(const struct sockaddr *sa, socklen_t salen) diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index b0eb85e5f..0e5f701fc 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -457,7 +457,7 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, } /* Sanity check: peer and local address must match IP types. */ - if (bpc->bpc_local.sa_sin.sin_family != 0 + if (bpc->bpc_local.sa_sin.sin_family != AF_UNSPEC && (bpc->bpc_local.sa_sin.sin_family != bpc->bpc_peer.sa_sin.sin_family)) { zlog_warn("ptm-read: peer family doesn't match local type"); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 192cd6ca8..dd27c9f6a 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -328,7 +328,12 @@ void aspath_free(struct aspath *aspath) void aspath_unintern(struct aspath **aspath) { struct aspath *ret; - struct aspath *asp = *aspath; + struct aspath *asp; + + if (!*aspath) + return; + + asp = *aspath; if (asp->refcnt) asp->refcnt--; diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5e773ca1f..a96b63cac 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -95,16 +95,6 @@ static const struct message attr_flag_str[] = { static struct hash *cluster_hash; -struct attr_extra *bgp_attr_extra_alloc(void) -{ - return XCALLOC(MTYPE_ATTR_EXTRA, sizeof(struct attr_extra)); -} - -void bgp_attr_extra_free(struct attr *attr) -{ - XFREE(MTYPE_ATTR_EXTRA, attr->extra); -} - static void *cluster_hash_alloc(void *p) { const struct cluster_list *val = (const struct cluster_list *)p; @@ -679,13 +669,12 @@ unsigned int attrhash_key_make(const void *p) if (attr->aspath) MIX(aspath_key_make(attr->aspath)); - if (attr->community) - MIX(community_hash_make(attr->community)); - - if (attr->lcommunity) - MIX(lcommunity_hash_make(attr->lcommunity)); - if (attr->ecommunity) - MIX(ecommunity_hash_make(attr->ecommunity)); + if (bgp_attr_get_community(attr)) + MIX(community_hash_make(bgp_attr_get_community(attr))); + if (bgp_attr_get_lcommunity(attr)) + MIX(lcommunity_hash_make(bgp_attr_get_lcommunity(attr))); + if (bgp_attr_get_ecommunity(attr)) + MIX(ecommunity_hash_make(bgp_attr_get_ecommunity(attr))); if (bgp_attr_get_ipv6_ecommunity(attr)) MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr))); if (bgp_attr_get_cluster(attr)) @@ -723,7 +712,9 @@ bool attrhash_cmp(const void *p1, const void *p2) if (attr1->flag == attr2->flag && attr1->origin == attr2->origin && attr1->nexthop.s_addr == attr2->nexthop.s_addr && attr1->aspath == attr2->aspath - && attr1->community == attr2->community && attr1->med == attr2->med + && bgp_attr_get_community(attr1) + == bgp_attr_get_community(attr2) + && attr1->med == attr2->med && attr1->local_pref == attr2->local_pref && attr1->rmap_change_flags == attr2->rmap_change_flags) { if (attr1->aggregator_as == attr2->aggregator_as @@ -733,10 +724,12 @@ bool attrhash_cmp(const void *p1, const void *p2) && attr1->tag == attr2->tag && attr1->label_index == attr2->label_index && attr1->mp_nexthop_len == attr2->mp_nexthop_len - && attr1->ecommunity == attr2->ecommunity + && bgp_attr_get_ecommunity(attr1) + == bgp_attr_get_ecommunity(attr2) && bgp_attr_get_ipv6_ecommunity(attr1) == bgp_attr_get_ipv6_ecommunity(attr2) - && attr1->lcommunity == attr2->lcommunity + && bgp_attr_get_lcommunity(attr1) + == bgp_attr_get_lcommunity(attr2) && bgp_attr_get_cluster(attr1) == bgp_attr_get_cluster(attr2) && bgp_attr_get_transit(attr1) @@ -787,7 +780,6 @@ static void attrhash_init(void) */ static void attr_vfree(void *attr) { - bgp_attr_extra_free(attr); XFREE(MTYPE_ATTR, attr); } @@ -850,7 +842,10 @@ static void *bgp_attr_hash_alloc(void *p) struct attr *bgp_attr_intern(struct attr *attr) { struct attr *find; - struct ecommunity *ecomm; + struct ecommunity *ecomm = NULL; + struct ecommunity *ipv6_ecomm = NULL; + struct lcommunity *lcomm = NULL; + struct community *comm = NULL; /* Intern referenced strucutre. */ if (attr->aspath) { @@ -859,34 +854,38 @@ struct attr *bgp_attr_intern(struct attr *attr) else attr->aspath->refcnt++; } - if (attr->community) { - if (!attr->community->refcnt) - attr->community = community_intern(attr->community); - else - attr->community->refcnt++; - } - if (attr->ecommunity) { - if (!attr->ecommunity->refcnt) - attr->ecommunity = ecommunity_intern(attr->ecommunity); + comm = bgp_attr_get_community(attr); + if (comm) { + if (!comm->refcnt) + bgp_attr_set_community(attr, community_intern(comm)); else - attr->ecommunity->refcnt++; + comm->refcnt++; } - ecomm = bgp_attr_get_ipv6_ecommunity(attr); + ecomm = bgp_attr_get_ecommunity(attr); if (ecomm) { if (!ecomm->refcnt) - bgp_attr_set_ipv6_ecommunity(attr, - ecommunity_intern(ecomm)); + bgp_attr_set_ecommunity(attr, ecommunity_intern(ecomm)); else ecomm->refcnt++; } - if (attr->lcommunity) { - if (!attr->lcommunity->refcnt) - attr->lcommunity = lcommunity_intern(attr->lcommunity); + ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr); + if (ipv6_ecomm) { + if (!ipv6_ecomm->refcnt) + bgp_attr_set_ipv6_ecommunity( + attr, ecommunity_intern(ipv6_ecomm)); else - attr->lcommunity->refcnt++; + ipv6_ecomm->refcnt++; + } + + lcomm = bgp_attr_get_lcommunity(attr); + if (lcomm) { + if (!lcomm->refcnt) + bgp_attr_set_lcommunity(attr, lcommunity_intern(lcomm)); + else + lcomm->refcnt++; } struct cluster_list *cluster = bgp_attr_get_cluster(attr); @@ -1008,17 +1007,17 @@ struct attr *bgp_attr_aggregate_intern( community_del_val(community, &gshut); } - attr.community = community; + bgp_attr_set_community(&attr, community); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); } if (ecommunity) { - attr.ecommunity = ecommunity; + bgp_attr_set_ecommunity(&attr, ecommunity); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } if (lcommunity) { - attr.lcommunity = lcommunity; + bgp_attr_set_lcommunity(&attr, lcommunity); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES); } @@ -1085,29 +1084,35 @@ struct attr *bgp_attr_aggregate_intern( /* Unintern just the sub-components of the attr, but not the attr */ void bgp_attr_unintern_sub(struct attr *attr) { - struct ecommunity *ecomm; + struct ecommunity *ecomm = NULL; + struct ecommunity *ipv6_ecomm = NULL; struct cluster_list *cluster; + struct lcommunity *lcomm = NULL; + struct community *comm = NULL; /* aspath refcount shoud be decrement. */ - if (attr->aspath) - aspath_unintern(&attr->aspath); + aspath_unintern(&attr->aspath); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)); - if (attr->community) - community_unintern(&attr->community); + comm = bgp_attr_get_community(attr); + community_unintern(&comm); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)); + bgp_attr_set_community(attr, NULL); - ecommunity_unintern(&attr->ecommunity); + ecomm = bgp_attr_get_ecommunity(attr); + ecommunity_unintern(&ecomm); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)); + bgp_attr_set_ecommunity(attr, NULL); - ecomm = bgp_attr_get_ipv6_ecommunity(attr); - ecommunity_unintern(&ecomm); + ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr); + ecommunity_unintern(&ipv6_ecomm); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES)); bgp_attr_set_ipv6_ecommunity(attr, NULL); - if (attr->lcommunity) - lcommunity_unintern(&attr->lcommunity); + lcomm = bgp_attr_get_lcommunity(attr); + lcommunity_unintern(&lcomm); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)); + bgp_attr_set_lcommunity(attr, NULL); cluster = bgp_attr_get_cluster(attr); if (cluster) { @@ -1143,41 +1148,6 @@ void bgp_attr_unintern_sub(struct attr *attr) srv6_vpn_unintern(&attr->srv6_vpn); } -/* - * We have some show commands that let you experimentally - * apply a route-map. When we apply the route-map - * we are reseting values but not saving them for - * posterity via intern'ing( because route-maps don't - * do that) but at this point in time we need - * to compare the new attr to the old and if the - * routemap has changed it we need to, as Snoop Dog says, - * Drop it like it's hot - */ -void bgp_attr_undup(struct attr *new, struct attr *old) -{ - if (new->aspath != old->aspath) - aspath_free(new->aspath); - - if (new->community != old->community) - community_free(&new->community); - - if (new->ecommunity != old->ecommunity) - ecommunity_free(&new->ecommunity); - - if (new->lcommunity != old->lcommunity) - lcommunity_free(&new->lcommunity); - - if (new->srv6_l3vpn != old->srv6_l3vpn) { - srv6_l3vpn_free(new->srv6_l3vpn); - new->srv6_l3vpn = NULL; - } - - if (new->srv6_vpn != old->srv6_vpn) { - srv6_vpn_free(new->srv6_vpn); - new->srv6_vpn = NULL; - } -} - /* Free bgp attribute and aspath. */ void bgp_attr_unintern(struct attr **pattr) { @@ -1194,7 +1164,6 @@ void bgp_attr_unintern(struct attr **pattr) if (attr->refcnt == 0) { ret = hash_release(attrhash, attr); assert(ret != NULL); - bgp_attr_extra_free(attr); XFREE(MTYPE_ATTR, attr); *pattr = NULL; } @@ -1205,22 +1174,34 @@ void bgp_attr_unintern(struct attr **pattr) void bgp_attr_flush(struct attr *attr) { struct ecommunity *ecomm; + struct ecommunity *ipv6_ecomm; struct cluster_list *cluster; + struct lcommunity *lcomm; + struct community *comm; if (attr->aspath && !attr->aspath->refcnt) { aspath_free(attr->aspath); attr->aspath = NULL; } - if (attr->community && !attr->community->refcnt) - community_free(&attr->community); - if (attr->ecommunity && !attr->ecommunity->refcnt) - ecommunity_free(&attr->ecommunity); - ecomm = bgp_attr_get_ipv6_ecommunity(attr); + comm = bgp_attr_get_community(attr); + if (comm && !comm->refcnt) + community_free(&comm); + bgp_attr_set_community(attr, NULL); + + ecomm = bgp_attr_get_ecommunity(attr); if (ecomm && !ecomm->refcnt) ecommunity_free(&ecomm); + bgp_attr_set_ecommunity(attr, NULL); + + ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr); + if (ipv6_ecomm && !ipv6_ecomm->refcnt) + ecommunity_free(&ipv6_ecomm); bgp_attr_set_ipv6_ecommunity(attr, NULL); - if (attr->lcommunity && !attr->lcommunity->refcnt) - lcommunity_free(&attr->lcommunity); + + lcomm = bgp_attr_get_lcommunity(attr); + if (lcomm && !lcomm->refcnt) + lcommunity_free(&lcomm); + bgp_attr_set_lcommunity(attr, NULL); cluster = bgp_attr_get_cluster(attr); if (cluster && !cluster->refcnt) { @@ -1963,13 +1944,14 @@ bgp_attr_community(struct bgp_attr_parser_args *args) const bgp_size_t length = args->length; if (length == 0) { - attr->community = NULL; + bgp_attr_set_community(attr, NULL); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); } - attr->community = - community_parse((uint32_t *)stream_pnt(peer->curr), length); + bgp_attr_set_community( + attr, + community_parse((uint32_t *)stream_pnt(peer->curr), length)); /* XXX: fix community_parse to use stream API and remove this */ stream_forward_getp(peer->curr, length); @@ -1977,7 +1959,7 @@ bgp_attr_community(struct bgp_attr_parser_args *args) /* The Community attribute SHALL be considered malformed if its * length is not a non-zero multiple of 4. */ - if (!attr->community) + if (!bgp_attr_get_community(attr)) return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); @@ -2297,17 +2279,18 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args) * Large community follows new attribute format. */ if (length == 0) { - attr->lcommunity = NULL; + bgp_attr_set_lcommunity(attr, NULL); /* Empty extcomm doesn't seem to be invalid per se */ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); } - attr->lcommunity = lcommunity_parse(stream_pnt(peer->curr), length); + bgp_attr_set_lcommunity( + attr, lcommunity_parse(stream_pnt(peer->curr), length)); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp(peer->curr, length); - if (!attr->lcommunity) + if (!bgp_attr_get_lcommunity(attr)) return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); @@ -2325,25 +2308,27 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) const bgp_size_t length = args->length; uint8_t sticky = 0; bool proxy = false; + struct ecommunity *ecomm; if (length == 0) { - attr->ecommunity = NULL; + bgp_attr_set_ecommunity(attr, NULL); /* Empty extcomm doesn't seem to be invalid per se */ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); } - attr->ecommunity = ecommunity_parse( + ecomm = ecommunity_parse( stream_pnt(peer->curr), length, CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); + bgp_attr_set_ecommunity(attr, ecomm); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp(peer->curr, length); /* The Extended Community attribute SHALL be considered malformed if * its length is not a non-zero multiple of 8. */ - if (!attr->ecommunity) + if (!bgp_attr_get_ecommunity(attr)) return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); @@ -2384,7 +2369,8 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) (bgp_encap_types *)&attr->encap_tunneltype); /* Extract link bandwidth, if any. */ - (void)ecommunity_linkbw_present(attr->ecommunity, &attr->link_bw); + (void)ecommunity_linkbw_present(bgp_attr_get_ecommunity(attr), + &attr->link_bw); return BGP_ATTR_PARSE_PROCEED; } @@ -3520,14 +3506,12 @@ done: * we can chuck as4_aggregator and as4_path alltogether in order * to save memory */ - if (as4_path) { - /* - * unintern - it is in the hash - * The flag that we got this is still there, but that - * does not do any trouble - */ - aspath_unintern(&as4_path); - } + /* + * unintern - it is in the hash + * The flag that we got this is still there, but that + * does not do any trouble + */ + aspath_unintern(&as4_path); transit = bgp_attr_get_transit(attr); if (ret != BGP_ATTR_PARSE_ERROR) { @@ -3584,7 +3568,7 @@ void bgp_attr_extcom_tunnel_type(struct attr *attr, if (!attr) return; - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return; @@ -4104,20 +4088,23 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, /* Community attribute. */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) { - if (attr->community->size * 4 > 255) { + struct community *comm = NULL; + + comm = bgp_attr_get_community(attr); + if (comm->size * 4 > 255) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_COMMUNITIES); - stream_putw(s, attr->community->size * 4); + stream_putw(s, comm->size * 4); } else { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_COMMUNITIES); - stream_putc(s, attr->community->size * 4); + stream_putc(s, comm->size * 4); } - stream_put(s, attr->community->val, attr->community->size * 4); + stream_put(s, comm->val, comm->size * 4); } /* @@ -4126,21 +4113,23 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) { - if (lcom_length(attr->lcommunity) > 255) { + if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putw(s, lcom_length(attr->lcommunity)); + stream_putw(s, + lcom_length(bgp_attr_get_lcommunity(attr))); } else { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putc(s, lcom_length(attr->lcommunity)); + stream_putc(s, + lcom_length(bgp_attr_get_lcommunity(attr))); } - stream_put(s, attr->lcommunity->val, - lcom_length(attr->lcommunity)); + stream_put(s, bgp_attr_get_lcommunity(attr)->val, + lcom_length(bgp_attr_get_lcommunity(attr))); } /* Route Reflector. */ @@ -4185,32 +4174,33 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, /* Extended Communities attribute. */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { + struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { - if (attr->ecommunity->size * 8 > 255) { + if (ecomm->size * 8 > 255) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); - stream_putw(s, attr->ecommunity->size * 8); + stream_putw(s, ecomm->size * 8); } else { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); - stream_putc(s, attr->ecommunity->size * 8); + stream_putc(s, ecomm->size * 8); } - stream_put(s, attr->ecommunity->val, - attr->ecommunity->size * 8); + stream_put(s, ecomm->val, ecomm->size * 8); } else { uint8_t *pnt; int tbit; int ecom_tr_size = 0; uint32_t i; - for (i = 0; i < attr->ecommunity->size; i++) { - pnt = attr->ecommunity->val + (i * 8); + for (i = 0; i < ecomm->size; i++) { + pnt = ecomm->val + (i * 8); tbit = *pnt; if (CHECK_FLAG(tbit, @@ -4240,8 +4230,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, stream_putc(s, ecom_tr_size * 8); } - for (i = 0; i < attr->ecommunity->size; i++) { - pnt = attr->ecommunity->val + (i * 8); + for (i = 0; i < ecomm->size; i++) { + pnt = ecomm->val + (i * 8); tbit = *pnt; if (CHECK_FLAG( @@ -4551,40 +4541,45 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr, /* Community attribute. */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { - if (attr->community->size * 4 > 255) { + struct community *comm = NULL; + + comm = bgp_attr_get_community(attr); + if (comm->size * 4 > 255) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_COMMUNITIES); - stream_putw(s, attr->community->size * 4); + stream_putw(s, comm->size * 4); } else { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_COMMUNITIES); - stream_putc(s, attr->community->size * 4); + stream_putc(s, comm->size * 4); } - stream_put(s, attr->community->val, attr->community->size * 4); + stream_put(s, comm->val, comm->size * 4); } /* Large Community attribute. */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { - if (lcom_length(attr->lcommunity) > 255) { + if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putw(s, lcom_length(attr->lcommunity)); + stream_putw(s, + lcom_length(bgp_attr_get_lcommunity(attr))); } else { stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); - stream_putc(s, lcom_length(attr->lcommunity)); + stream_putc(s, + lcom_length(bgp_attr_get_lcommunity(attr))); } - stream_put(s, attr->lcommunity->val, - lcom_length(attr->lcommunity)); + stream_put(s, bgp_attr_get_lcommunity(attr)->val, + lcom_length(bgp_attr_get_lcommunity(attr))); } /* Add a MP_NLRI attribute to dump the IPv6 next hop */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 6e9a4e7c3..1f199da16 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -159,11 +159,6 @@ struct bgp_attr_srv6_l3vpn { uint8_t transposition_offset; }; -struct attr_extra { - /* Extended Communities attribute. */ - struct ecommunity *ipv6_ecommunity; -}; - /* BGP core attribute structure. */ struct attr { /* AS Path structure */ @@ -204,8 +199,8 @@ struct attr { /* Extended Communities attribute. */ struct ecommunity *ecommunity; - /* Extra attributes, non IPv4/IPv6 AFI related */ - struct attr_extra *extra; + /* Extended Communities attribute. */ + struct ecommunity *ipv6_ecommunity; /* Large Communities attribute. */ struct lcommunity *lcommunity; @@ -394,7 +389,6 @@ extern void bgp_attr_finish(void); extern bgp_attr_parse_ret_t bgp_attr_parse(struct peer *, struct attr *, bgp_size_t, struct bgp_nlri *, struct bgp_nlri *); -extern void bgp_attr_undup(struct attr *new, struct attr *old); extern struct attr *bgp_attr_intern(struct attr *attr); extern void bgp_attr_unintern_sub(struct attr *); extern void bgp_attr_unintern(struct attr **); @@ -479,8 +473,6 @@ extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); extern bgp_attr_parse_ret_t bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr); -extern struct attr_extra *bgp_attr_extra_alloc(void); -extern void bgp_attr_extra_free(struct attr *attr); static inline int bgp_rmap_nhop_changed(uint32_t out_rmap_flags, uint32_t in_rmap_flags) @@ -515,25 +507,50 @@ static inline void bgp_attr_set_pmsi_tnl_type(struct attr *attr, } static inline struct ecommunity * -bgp_attr_get_ipv6_ecommunity(const struct attr *attr) +bgp_attr_get_ecommunity(const struct attr *attr) { - if (attr->extra) - return attr->extra->ipv6_ecommunity; + return attr->ecommunity; +} - return NULL; +static inline void bgp_attr_set_ecommunity(struct attr *attr, + struct ecommunity *ecomm) +{ + attr->ecommunity = ecomm; } -static inline void bgp_attr_set_ipv6_ecommunity(struct attr *attr, - struct ecommunity *ipv6_ecomm) +static inline struct lcommunity * +bgp_attr_get_lcommunity(const struct attr *attr) { - if (!attr->extra) { - if (!ipv6_ecomm) - return; + return attr->lcommunity; +} - attr->extra = bgp_attr_extra_alloc(); - } +static inline void bgp_attr_set_lcommunity(struct attr *attr, + struct lcommunity *lcomm) +{ + attr->lcommunity = lcomm; +} - attr->extra->ipv6_ecommunity = ipv6_ecomm; +static inline struct community *bgp_attr_get_community(const struct attr *attr) +{ + return attr->community; +} + +static inline void bgp_attr_set_community(struct attr *attr, + struct community *comm) +{ + attr->community = comm; +} + +static inline struct ecommunity * +bgp_attr_get_ipv6_ecommunity(const struct attr *attr) +{ + return attr->ipv6_ecommunity; +} + +static inline void bgp_attr_set_ipv6_ecommunity(struct attr *attr, + struct ecommunity *ipv6_ecomm) +{ + attr->ipv6_ecommunity = ipv6_ecomm; } static inline struct transit *bgp_attr_get_transit(const struct attr *attr) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index cbb071738..e528faded 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -47,15 +47,18 @@ bool bgp_route_evpn_same(const struct bgp_route_evpn *e1, void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac) { struct ecommunity_val routermac_ecom; + struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN); - if (!attr->ecommunity) - attr->ecommunity = ecommunity_new(); - ecommunity_add_val(attr->ecommunity, &routermac_ecom, false, false); - ecommunity_str(attr->ecommunity); + if (!ecomm) { + bgp_attr_set_ecommunity(attr, ecommunity_new()); + ecomm = bgp_attr_get_ecommunity(attr); + } + ecommunity_add_val(ecomm, &routermac_ecom, false, false); + ecommunity_str(ecomm); } /* converts to an esi @@ -100,7 +103,7 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) uint32_t i = 0; struct ecommunity *ecom; - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return false; @@ -132,7 +135,7 @@ uint8_t bgp_attr_default_gw(struct attr *attr) struct ecommunity *ecom; uint32_t i; - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return 0; @@ -165,7 +168,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg) uint16_t df_pref = 0; *alg = EVPN_MH_DF_ALG_SERVICE_CARVING; - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return 0; @@ -201,7 +204,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) uint32_t i; uint8_t flags = 0; - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return 0; @@ -248,7 +251,7 @@ void bgp_attr_evpn_na_flag(struct attr *attr, uint32_t i; uint8_t val; - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return; diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 1c9852f5c..96c34f919 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1315,7 +1315,7 @@ static void bmp_stat_put_u32(struct stream *s, size_t *cnt, uint16_t type, (*cnt)++; } -static int bmp_stats(struct thread *thread) +static void bmp_stats(struct thread *thread) { struct bmp_targets *bt = THREAD_ARG(thread); struct stream *s; @@ -1365,11 +1365,10 @@ static int bmp_stats(struct thread *thread) bmp_send_all(bt->bmpbgp, s); } - return 0; } /* read from the BMP socket to detect session termination */ -static int bmp_read(struct thread *t) +static void bmp_read(struct thread *t) { struct bmp *bmp = THREAD_ARG(t); char buf[1024]; @@ -1383,16 +1382,14 @@ static int bmp_read(struct thread *t) } else if (n == 0) { /* the TCP session was terminated by the far end */ bmp_wrerr(bmp, NULL, true); - return 0; + return; } else if (!(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) { /* the TCP session experienced a fatal error, likely a timeout */ bmp_wrerr(bmp, NULL, false); - return -1; + return; } thread_add_read(bm->master, bmp_read, bmp, bmp->socket, &bmp->t_read); - - return 0; } static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock) @@ -1475,7 +1472,7 @@ static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock) } /* Accept BMP connection. */ -static int bmp_accept(struct thread *thread) +static void bmp_accept(struct thread *thread) { union sockunion su; struct bmp_listener *bl = THREAD_ARG(thread); @@ -1490,10 +1487,9 @@ static int bmp_accept(struct thread *thread) bmp_sock = sockunion_accept(bl->sock, &su); if (bmp_sock < 0) { zlog_info("bmp: accept_sock failed: %s", safe_strerror(errno)); - return -1; + return; } bmp_open(bl->targets, bmp_sock); - return 0; } static void bmp_close(struct bmp *bmp) @@ -1837,7 +1833,7 @@ static void bmp_active_resolved(struct resolver_query *resq, const char *errstr, bmp_active_connect(ba); } -static int bmp_active_thread(struct thread *t) +static void bmp_active_thread(struct thread *t) { struct bmp_active *ba = THREAD_ARG(t); socklen_t slen; @@ -1861,7 +1857,7 @@ static int bmp_active_thread(struct thread *t) vrf_id = ba->targets->bgp->vrf_id; resolver_resolve(&ba->resq, AF_UNSPEC, vrf_id, ba->hostname, bmp_active_resolved); - return 0; + return; } slen = sizeof(status); @@ -1886,14 +1882,13 @@ static int bmp_active_thread(struct thread *t) ba->bmp->active = ba; ba->socket = -1; ba->curretry = ba->minretry; - return 0; + return; out_next: close(ba->socket); ba->socket = -1; ba->addrpos++; bmp_active_connect(ba); - return 0; } static void bmp_active_disconnected(struct bmp_active *ba) diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index a5dafd775..6e6a3cd58 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -497,6 +497,9 @@ void community_unintern(struct community **com) { struct community *ret; + if (!*com) + return; + if ((*com)->refcnt) (*com)->refcnt--; diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index c0dd3d6f8..f72a373a1 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -82,7 +82,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, struct peer_af *paf; const struct prefix *dest_p; struct update_subgroup *subgrp; - struct attr dummy_attr = {0}, attr = {0}; + struct attr advmap_attr = {0}, attr = {0}; struct bgp_path_info_extra path_extra = {0}; route_map_result_t ret; @@ -110,55 +110,53 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, assert(dest_p); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { - dummy_attr = *pi->attr; + advmap_attr = *pi->attr; /* Fill temp path_info */ prep_for_rmap_apply(&path, &path_extra, dest, pi, - pi->peer, &dummy_attr); + pi->peer, &advmap_attr); - RESET_FLAG(dummy_attr.rmap_change_flags); + RESET_FLAG(advmap_attr.rmap_change_flags); ret = route_map_apply(rmap, dest_p, &path); - bgp_attr_flush(&dummy_attr); - - if (ret != RMAP_PERMITMATCH) + if (ret != RMAP_PERMITMATCH || + !bgp_check_selected(pi, peer, addpath_capable, afi, + safi)) { + bgp_attr_flush(&advmap_attr); continue; + } - if (bgp_check_selected(pi, peer, addpath_capable, afi, - safi)) { - /* Skip route-map checks in - * subgroup_announce_check while executing from - * the conditional advertise scanner process. - * otherwise when route-map is also configured - * on same peer, routes in advertise-map may not - * be advertised as expected. + /* Skip route-map checks in + * subgroup_announce_check while executing from + * the conditional advertise scanner process. + * otherwise when route-map is also configured + * on same peer, routes in advertise-map may not + * be advertised as expected. + */ + if (update_type == ADVERTISE && + subgroup_announce_check(dest, pi, subgrp, dest_p, + &attr, &advmap_attr)) { + bgp_adj_out_set_subgroup(dest, subgrp, &attr, + pi); + } else { + /* If default originate is enabled for + * the peer, do not send explicit + * withdraw. This will prevent deletion + * of default route advertised through + * default originate. */ - if ((update_type == ADVERTISE) - && subgroup_announce_check(dest, pi, subgrp, - dest_p, &attr, - true)) - bgp_adj_out_set_subgroup(dest, subgrp, - &attr, pi); - else { - /* If default originate is enabled for - * the peer, do not send explicit - * withdraw. This will prevent deletion - * of default route advertised through - * default originate. - */ - if (CHECK_FLAG( - peer->af_flags[afi][safi], - PEER_FLAG_DEFAULT_ORIGINATE) - && is_default_prefix(dest_p)) - break; - - bgp_adj_out_unset_subgroup( - dest, subgrp, 1, - bgp_addpath_id_for_peer( - peer, afi, safi, - &pi->tx_addpath)); - } + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_DEFAULT_ORIGINATE) && + is_default_prefix(dest_p)) + break; + + bgp_adj_out_unset_subgroup( + dest, subgrp, 1, + bgp_addpath_id_for_peer( + peer, afi, safi, + &pi->tx_addpath)); } + bgp_attr_flush(&advmap_attr); } } UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); @@ -167,7 +165,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, /* Handler of conditional advertisement timer event. * Each route in the condition-map is evaluated. */ -static int bgp_conditional_adv_timer(struct thread *t) +static void bgp_conditional_adv_timer(struct thread *t) { afi_t afi; safi_t safi; @@ -288,7 +286,6 @@ static int bgp_conditional_adv_timer(struct thread *t) } peer->advmap_table_change = false; } - return 0; } void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi) diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 91e983e5d..62e8e71aa 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -113,7 +113,7 @@ int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc) /* Handler of reuse timer event. Each route in the current reuse-list is evaluated. RFC2439 Section 4.8.7. */ -static int bgp_reuse_timer(struct thread *t) +static void bgp_reuse_timer(struct thread *t) { struct bgp_damp_info *bdi; struct bgp_damp_info *next; @@ -178,8 +178,6 @@ static int bgp_reuse_timer(struct thread *t) * 4.8.6). */ bgp_reuse_list_add(bdi, bdc); } - - return 0; } /* A route becomes unreachable (RFC2439 Section 4.8.2). */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 64f71bebc..5d14ff0fa 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -411,16 +411,17 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size) if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) snprintf(buf + strlen(buf), size - strlen(buf), ", community %s", - community_str(attr->community, false)); + community_str(bgp_attr_get_community(attr), false)); if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) snprintf(buf + strlen(buf), size - strlen(buf), ", large-community %s", - lcommunity_str(attr->lcommunity, false)); + lcommunity_str(bgp_attr_get_lcommunity(attr), false)); if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) snprintf(buf + strlen(buf), size - strlen(buf), - ", extcommunity %s", ecommunity_str(attr->ecommunity)); + ", extcommunity %s", + ecommunity_str(bgp_attr_get_ecommunity(attr))); if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) snprintf(buf + strlen(buf), size - strlen(buf), diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 9ddfe7bb5..c389fec5f 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -88,7 +88,7 @@ struct bgp_dump { }; static int bgp_dump_unset(struct bgp_dump *bgp_dump); -static int bgp_dump_interval_func(struct thread *); +static void bgp_dump_interval_func(struct thread *); /* BGP packet dump output buffer. */ struct stream *bgp_dump_obuf; @@ -439,7 +439,7 @@ static unsigned int bgp_dump_routes_func(int afi, int first_run, return seq; } -static int bgp_dump_interval_func(struct thread *t) +static void bgp_dump_interval_func(struct thread *t) { struct bgp_dump *bgp_dump; bgp_dump = THREAD_ARG(t); @@ -462,8 +462,6 @@ static int bgp_dump_interval_func(struct thread *t) /* if interval is set reschedule */ if (bgp_dump->interval > 0) bgp_dump_interval_add(bgp_dump, bgp_dump->interval); - - return 0; } /* Dump common information. */ diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c index 0f9d5fc73..193c96a16 100644 --- a/bgpd/bgp_errors.c +++ b/bgpd/bgp_errors.c @@ -464,7 +464,7 @@ static struct log_ref ferr_bgp_err[] = { }, { .code = EC_BGP_INVALID_BGP_INSTANCE, - .title = "BGP instance for the specifc vrf is invalid", + .title = "BGP instance for the specific vrf is invalid", .description = "Indicates that specified bgp instance is NULL", .suggestion = "Get log files from router and open an issue", }, @@ -474,6 +474,12 @@ static struct log_ref ferr_bgp_err[] = { .description = "BGP route for the specified AFI/SAFI is NULL", .suggestion = "Get log files from router and open an issue", }, + { + .code = EC_BGP_NO_LL_ADDRESS_AVAILABLE, + .title = "BGP v6 peer with no LL address on outgoing interface", + .description = "BGP when using a v6 peer requires a v6 LL address to be configured on the outgoing interface as per RFC 4291 section 2.1", + .suggestion = "Add a v6 LL address to the outgoing interfaces as per RFC", + }, { .code = END_FERR, } diff --git a/bgpd/bgp_errors.h b/bgpd/bgp_errors.h index 20056d382..0b71af3fc 100644 --- a/bgpd/bgp_errors.h +++ b/bgpd/bgp_errors.h @@ -101,6 +101,7 @@ enum bgp_log_refs { EC_BGP_ROUTER_ID_SAME, EC_BGP_INVALID_BGP_INSTANCE, EC_BGP_INVALID_ROUTE, + EC_BGP_NO_LL_ADDRESS_AVAILABLE, }; extern void bgp_error_init(void); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index de246b07e..a9c006ca2 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -736,26 +736,28 @@ static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf, ecom_encap.val = (uint8_t *)eval.val; /* Add Encap */ - if (attr->ecommunity) { - old_ecom = attr->ecommunity; + if (bgp_attr_get_ecommunity(attr)) { + old_ecom = bgp_attr_get_ecommunity(attr); ecom = ecommunity_merge(ecommunity_dup(old_ecom), &ecom_encap); if (!old_ecom->refcnt) ecommunity_free(&old_ecom); } else ecom = ecommunity_dup(&ecom_encap); - attr->ecommunity = ecom; + bgp_attr_set_ecommunity(attr, ecom); attr->encap_tunneltype = tnl_type; /* Add the export RTs for L3VNI/VRF */ vrf_export_rtl = bgp_vrf->vrf_export_rtl; for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, ecom)) - attr->ecommunity = - ecommunity_merge(attr->ecommunity, ecom); + bgp_attr_set_ecommunity( + attr, + ecommunity_merge(bgp_attr_get_ecommunity(attr), ecom)); /* add the router mac extended community */ if (!is_zero_mac(&attr->rmac)) { encode_rmac_extcomm(&eval_rmac, &attr->rmac); - ecommunity_add_val(attr->ecommunity, &eval_rmac, true, true); + ecommunity_add_val(bgp_attr_get_ecommunity(attr), &eval_rmac, + true, true); } attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); @@ -800,12 +802,14 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, ecom_encap.val = (uint8_t *)eval.val; /* Add Encap */ - attr->ecommunity = ecommunity_dup(&ecom_encap); + bgp_attr_set_ecommunity(attr, ecommunity_dup(&ecom_encap)); attr->encap_tunneltype = tnl_type; /* Add the export RTs for L2VNI */ for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) - attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom); + bgp_attr_set_ecommunity( + attr, + ecommunity_merge(bgp_attr_get_ecommunity(attr), ecom)); /* Add the export RTs for L3VNI if told to - caller determines * when this should be done. @@ -815,8 +819,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) { for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, ecom)) - attr->ecommunity = ecommunity_merge( - attr->ecommunity, ecom); + bgp_attr_set_ecommunity( + attr, + ecommunity_merge( + bgp_attr_get_ecommunity(attr), + ecom)); } } @@ -828,14 +835,16 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, ecom_sticky.size = 1; ecom_sticky.unit_size = ECOMMUNITY_SIZE; ecom_sticky.val = (uint8_t *)eval_sticky.val; - attr->ecommunity = - ecommunity_merge(attr->ecommunity, &ecom_sticky); + bgp_attr_set_ecommunity( + attr, ecommunity_merge(bgp_attr_get_ecommunity(attr), + &ecom_sticky)); } /* Add RMAC, if told to. */ if (add_l3_ecomm) { encode_rmac_extcomm(&eval_rmac, &attr->rmac); - ecommunity_add_val(attr->ecommunity, &eval_rmac, true, true); + ecommunity_add_val(bgp_attr_get_ecommunity(attr), &eval_rmac, + true, true); } /* Add default gateway, if needed. */ @@ -845,8 +854,9 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, ecom_default_gw.size = 1; ecom_default_gw.unit_size = ECOMMUNITY_SIZE; ecom_default_gw.val = (uint8_t *)eval_default_gw.val; - attr->ecommunity = - ecommunity_merge(attr->ecommunity, &ecom_default_gw); + bgp_attr_set_ecommunity( + attr, ecommunity_merge(bgp_attr_get_ecommunity(attr), + &ecom_default_gw)); } proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT); @@ -856,8 +866,9 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, ecom_na.size = 1; ecom_na.unit_size = ECOMMUNITY_SIZE; ecom_na.val = (uint8_t *)eval_na.val; - attr->ecommunity = ecommunity_merge(attr->ecommunity, - &ecom_na); + bgp_attr_set_ecommunity( + attr, ecommunity_merge(bgp_attr_get_ecommunity(attr), + &ecom_na)); } attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); @@ -875,6 +886,7 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) uint8_t *pnt; int type = 0; int sub_type = 0; + struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); /* Build MM */ encode_mac_mobility_extcomm(0, seq_num, &eval); @@ -882,10 +894,9 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) /* Find current MM ecommunity */ ecom_val_ptr = NULL; - if (attr->ecommunity) { - for (i = 0; i < attr->ecommunity->size; i++) { - pnt = attr->ecommunity->val + - (i * attr->ecommunity->unit_size); + if (ecomm) { + for (i = 0; i < ecomm->size; i++) { + pnt = ecomm->val + (i * ecomm->unit_size); type = *pnt++; sub_type = *pnt++; @@ -893,8 +904,7 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) { ecom_val_ptr = - (attr->ecommunity->val + - (i * attr->ecommunity->unit_size)); + (ecomm->val + (i * ecomm->unit_size)); break; } } @@ -902,8 +912,7 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) /* Update the existing MM ecommunity */ if (ecom_val_ptr) { - memcpy(ecom_val_ptr, eval.val, sizeof(char) - * attr->ecommunity->unit_size); + memcpy(ecom_val_ptr, eval.val, sizeof(char) * ecomm->unit_size); } /* Add MM to existing */ else { @@ -912,11 +921,12 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) ecom_tmp.unit_size = ECOMMUNITY_SIZE; ecom_tmp.val = (uint8_t *)eval.val; - if (attr->ecommunity) - attr->ecommunity = - ecommunity_merge(attr->ecommunity, &ecom_tmp); + if (ecomm) + bgp_attr_set_ecommunity( + attr, ecommunity_merge(ecomm, &ecom_tmp)); else - attr->ecommunity = ecommunity_dup(&ecom_tmp); + bgp_attr_set_ecommunity(attr, + ecommunity_dup(&ecom_tmp)); } } @@ -2823,7 +2833,7 @@ static int is_route_matching_for_vrf(struct bgp *bgp_vrf, if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) return 0; - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return 0; @@ -2890,7 +2900,7 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn, if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) return 0; - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return 0; @@ -3374,7 +3384,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) evp = evpn_type1_prefix_vni_copy(&ad_evp, evp, attr->nexthop); - ecom = attr->ecommunity; + ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) return -1; diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 2254bc6ba..ea179ec2b 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -76,7 +76,7 @@ static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es, bool is_local); esi_t zero_esi_buf, *zero_esi = &zero_esi_buf; -static int bgp_evpn_run_consistency_checks(struct thread *t); +static void bgp_evpn_run_consistency_checks(struct thread *t); static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info *nh_info); static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info); @@ -598,7 +598,7 @@ static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es *es, ecom_encap.size = 1; ecom_encap.unit_size = ECOMMUNITY_SIZE; ecom_encap.val = (uint8_t *)eval.val; - attr->ecommunity = ecommunity_dup(&ecom_encap); + bgp_attr_set_ecommunity(attr, ecommunity_dup(&ecom_encap)); /* ES import RT */ memset(&mac, 0, sizeof(struct ethaddr)); @@ -608,15 +608,18 @@ static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es *es, ecom_es_rt.size = 1; ecom_es_rt.unit_size = ECOMMUNITY_SIZE; ecom_es_rt.val = (uint8_t *)eval_es_rt.val; - attr->ecommunity = - ecommunity_merge(attr->ecommunity, &ecom_es_rt); + bgp_attr_set_ecommunity( + attr, + ecommunity_merge(bgp_attr_get_ecommunity(attr), &ecom_es_rt)); /* DF election extended community */ memset(&ecom_df, 0, sizeof(ecom_df)); encode_df_elect_extcomm(&eval_df, es->df_pref); ecom_df.size = 1; ecom_df.val = (uint8_t *)eval_df.val; - attr->ecommunity = ecommunity_merge(attr->ecommunity, &ecom_df); + bgp_attr_set_ecommunity( + attr, + ecommunity_merge(bgp_attr_get_ecommunity(attr), &ecom_df)); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } @@ -861,7 +864,7 @@ static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es *es, ecom_encap.size = 1; ecom_encap.unit_size = ECOMMUNITY_SIZE; ecom_encap.val = (uint8_t *)eval.val; - attr->ecommunity = ecommunity_dup(&ecom_encap); + bgp_attr_set_ecommunity(attr, ecommunity_dup(&ecom_encap)); /* ESI label */ encode_esi_label_extcomm(&eval_esi_label, @@ -869,8 +872,9 @@ static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es *es, ecom_esi_label.size = 1; ecom_esi_label.unit_size = ECOMMUNITY_SIZE; ecom_esi_label.val = (uint8_t *)eval_esi_label.val; - attr->ecommunity = - ecommunity_merge(attr->ecommunity, &ecom_esi_label); + bgp_attr_set_ecommunity(attr, + ecommunity_merge(bgp_attr_get_ecommunity(attr), + &ecom_esi_label)); /* Add export RTs for all L2-VNIs associated with this ES */ /* XXX - suppress EAD-ES advertisment if there are no EVIs associated @@ -882,8 +886,10 @@ static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es *es, continue; for (ALL_LIST_ELEMENTS_RO(es_evi->vpn->export_rtl, rt_node, ecom)) - attr->ecommunity = ecommunity_merge(attr->ecommunity, - ecom); + bgp_attr_set_ecommunity( + attr, + ecommunity_merge(bgp_attr_get_ecommunity(attr), + ecom)); } attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); @@ -906,11 +912,13 @@ static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es *es, ecom_encap.size = 1; ecom_encap.unit_size = ECOMMUNITY_SIZE; ecom_encap.val = (uint8_t *)eval.val; - attr->ecommunity = ecommunity_dup(&ecom_encap); + bgp_attr_set_ecommunity(attr, ecommunity_dup(&ecom_encap)); /* Add export RTs for the L2-VNI */ for (ALL_LIST_ELEMENTS_RO(vpn->export_rtl, rt_node, ecom)) - attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom); + bgp_attr_set_ecommunity( + attr, + ecommunity_merge(bgp_attr_get_ecommunity(attr), ecom)); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } @@ -4114,7 +4122,7 @@ static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es *es) return proc_cnt; } -static int bgp_evpn_run_consistency_checks(struct thread *t) +static void bgp_evpn_run_consistency_checks(struct thread *t) { int proc_cnt = 0; int es_cnt = 0; @@ -4139,8 +4147,6 @@ static int bgp_evpn_run_consistency_checks(struct thread *t) thread_add_timer(bm->master, bgp_evpn_run_consistency_checks, NULL, BGP_EVPN_CONS_CHECK_INTERVAL, &bgp_mh_info->t_cons_check); - - return 0; } /***************************************************************************** @@ -4306,7 +4312,7 @@ static bool bgp_evpn_nh_cmp(const void *p1, const void *p2) if (n1 == NULL || n2 == NULL) return false; - return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0); + return (ipaddr_cmp(&n1->ip, &n2->ip) == 0); } void bgp_evpn_nh_init(struct bgp *bgp_vrf) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index f377c8352..7ddf15984 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1236,6 +1236,10 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, no_display = 0; for (; pi; pi = pi->next) { + struct community *picomm = NULL; + + picomm = bgp_attr_get_community(pi->attr); + total_count++; if (type == bgp_show_type_neighbor) { struct peer *peer = output_arg; @@ -1246,33 +1250,37 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, if (type == bgp_show_type_lcommunity_exact) { struct lcommunity *lcom = output_arg; - if (!pi->attr->lcommunity || - !lcommunity_cmp( - pi->attr->lcommunity, lcom)) + if (!bgp_attr_get_lcommunity( + pi->attr) || + !lcommunity_cmp( + bgp_attr_get_lcommunity( + pi->attr), + lcom)) continue; } if (type == bgp_show_type_lcommunity) { struct lcommunity *lcom = output_arg; - if (!pi->attr->lcommunity || - !lcommunity_match( - pi->attr->lcommunity, lcom)) + if (!bgp_attr_get_lcommunity( + pi->attr) || + !lcommunity_match( + bgp_attr_get_lcommunity( + pi->attr), + lcom)) continue; } if (type == bgp_show_type_community) { struct community *com = output_arg; - if (!pi->attr->community || - !community_match( - pi->attr->community, com)) + if (!picomm || + !community_match(picomm, com)) continue; } if (type == bgp_show_type_community_exact) { struct community *com = output_arg; - if (!pi->attr->community || - !community_cmp( - pi->attr->community, com)) + if (!picomm || + !community_cmp(picomm, com)) continue; } if (header) { @@ -3507,8 +3515,8 @@ DEFUN (bgp_evpn_advertise_all_vni, bgp_evpn = bgp_get_evpn(); if (bgp_evpn && bgp_evpn != bgp) { - vty_out(vty, "%% Please unconfigure EVPN in VRF %s\n", - bgp_evpn->name); + vty_out(vty, "%% Please unconfigure EVPN in %s\n", + bgp_evpn->name_pretty); return CMD_WARNING_CONFIG_FAILED; } @@ -3859,19 +3867,19 @@ DEFUN (bgp_evpn_advertise_type5, if (!(afi == AFI_IP || afi == AFI_IP6)) { vty_out(vty, - "%%only ipv4 or ipv6 address families are supported"); + "%%only ipv4 or ipv6 address families are supported\n"); return CMD_WARNING; } if (safi != SAFI_UNICAST) { vty_out(vty, - "%%only ipv4 unicast or ipv6 unicast are supported"); + "%%only ipv4 unicast or ipv6 unicast are supported\n"); return CMD_WARNING; } if ((oly != OVERLAY_INDEX_TYPE_NONE) && (oly != OVERLAY_INDEX_GATEWAY_IP)) { - vty_out(vty, "%%Unknown overlay-index type specified"); + vty_out(vty, "%%Unknown overlay-index type specified\n"); return CMD_WARNING; } @@ -4050,13 +4058,13 @@ DEFUN (no_bgp_evpn_advertise_type5, if (!(afi == AFI_IP || afi == AFI_IP6)) { vty_out(vty, - "%%only ipv4 or ipv6 address families are supported"); + "%%only ipv4 or ipv6 address families are supported\n"); return CMD_WARNING; } if (safi != SAFI_UNICAST) { vty_out(vty, - "%%only ipv4 unicast or ipv6 unicast are supported"); + "%%only ipv4 unicast or ipv6 unicast are supported\n"); return CMD_WARNING; } diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index 341cfe9d0..de3f2a9d4 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -170,9 +170,10 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, afi); snprintf(ec_string, sizeof(ec_string), "EC{none}"); - if (attr && attr->ecommunity) { - s = ecommunity_ecom2str(attr->ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + if (attr && bgp_attr_get_ecommunity(attr)) { + s = ecommunity_ecom2str( + bgp_attr_get_ecommunity(attr), + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); snprintf(ec_string, sizeof(ec_string), "EC{%s}", s == NULL ? "none" : s); diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 8873ca5c0..02dcdfcaa 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -303,12 +303,13 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, if (path->attr) ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(path->attr); - if (path->attr && (path->attr->ecommunity || ipv6_ecomm)) { + if (path->attr && (bgp_attr_get_ecommunity(path->attr) || ipv6_ecomm)) { /* Print attribute */ attr = path->attr; - if (attr->ecommunity) - s1 = ecommunity_ecom2str(attr->ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + if (bgp_attr_get_ecommunity(attr)) + s1 = ecommunity_ecom2str(bgp_attr_get_ecommunity(attr), + ECOMMUNITY_FORMAT_ROUTE_MAP, + 0); if (ipv6_ecomm) s2 = ecommunity_ecom2str( ipv6_ecomm, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 672fa4512..f8de3b8dc 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -90,13 +90,13 @@ static const char *const bgp_event_str[] = { function. */ /* BGP event function. */ -int bgp_event(struct thread *); +void bgp_event(struct thread *); /* BGP thread functions. */ -static int bgp_start_timer(struct thread *); -static int bgp_connect_timer(struct thread *); -static int bgp_holdtime_timer(struct thread *); -static int bgp_delayopen_timer(struct thread *); +static void bgp_start_timer(struct thread *); +static void bgp_connect_timer(struct thread *); +static void bgp_holdtime_timer(struct thread *); +static void bgp_delayopen_timer(struct thread *); /* BGP FSM functions. */ static int bgp_start(struct peer *); @@ -494,7 +494,7 @@ void bgp_timer_set(struct peer *peer) /* BGP start timer. This function set BGP_Start event to thread value and process event. */ -static int bgp_start_timer(struct thread *thread) +static void bgp_start_timer(struct thread *thread) { struct peer *peer; @@ -505,15 +505,12 @@ static int bgp_start_timer(struct thread *thread) THREAD_VAL(thread) = BGP_Start; bgp_event(thread); /* bgp_event unlocks peer */ - - return 0; } /* BGP connect retry timer. */ -static int bgp_connect_timer(struct thread *thread) +static void bgp_connect_timer(struct thread *thread) { struct peer *peer; - int ret; peer = THREAD_ARG(thread); @@ -526,20 +523,16 @@ static int bgp_connect_timer(struct thread *thread) if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Timer (connect timer expire)", peer->host); - if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) { + if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) bgp_stop(peer); - ret = -1; - } else { + else { THREAD_VAL(thread) = ConnectRetry_timer_expired; bgp_event(thread); /* bgp_event unlocks peer */ - ret = 0; } - - return ret; } /* BGP holdtime timer. */ -static int bgp_holdtime_timer(struct thread *thread) +static void bgp_holdtime_timer(struct thread *thread) { atomic_size_t inq_count; struct peer *peer; @@ -562,20 +555,15 @@ static int bgp_holdtime_timer(struct thread *thread) */ inq_count = atomic_load_explicit(&peer->ibuf->count, memory_order_relaxed); - if (inq_count) { + if (inq_count) BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); - return 0; - } - THREAD_VAL(thread) = Hold_Timer_expired; bgp_event(thread); /* bgp_event unlocks peer */ - - return 0; } -int bgp_routeadv_timer(struct thread *thread) +void bgp_routeadv_timer(struct thread *thread) { struct peer *peer; @@ -593,11 +581,10 @@ int bgp_routeadv_timer(struct thread *thread) /* MRAI timer will be started again when FIFO is built, no need to * do it here. */ - return 0; } /* RFC 4271 DelayOpenTimer */ -int bgp_delayopen_timer(struct thread *thread) +void bgp_delayopen_timer(struct thread *thread) { struct peer *peer; @@ -609,8 +596,6 @@ int bgp_delayopen_timer(struct thread *thread) THREAD_VAL(thread) = DelayOpen_timer_expired; bgp_event(thread); /* bgp_event unlocks peer */ - - return 0; } /* BGP Peer Down Cause */ @@ -674,7 +659,7 @@ static void bgp_graceful_restart_timer_off(struct peer *peer) bgp_timer_set(peer); } -static int bgp_llgr_stale_timer_expire(struct thread *thread) +static void bgp_llgr_stale_timer_expire(struct thread *thread) { struct peer_af *paf; struct peer *peer; @@ -700,8 +685,6 @@ static int bgp_llgr_stale_timer_expire(struct thread *thread) bgp_clear_stale_route(peer, afi, safi); bgp_graceful_restart_timer_off(peer); - - return 0; } static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) @@ -727,9 +710,10 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) if (pi->peer != peer) continue; - if (pi->attr->community && + if (bgp_attr_get_community(pi->attr) && community_include( - pi->attr->community, + bgp_attr_get_community( + pi->attr), COMMUNITY_NO_LLGR)) continue; @@ -755,9 +739,10 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) if (pi->peer != peer) continue; - if (pi->attr->community && - community_include(pi->attr->community, - COMMUNITY_NO_LLGR)) + if (bgp_attr_get_community(pi->attr) && + community_include( + bgp_attr_get_community(pi->attr), + COMMUNITY_NO_LLGR)) continue; if (bgp_debug_neighbor_events(peer)) @@ -776,7 +761,7 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) } } -static int bgp_graceful_restart_timer_expire(struct thread *thread) +static void bgp_graceful_restart_timer_expire(struct thread *thread) { struct peer *peer, *tmp_peer; struct listnode *node, *nnode; @@ -840,11 +825,9 @@ static int bgp_graceful_restart_timer_expire(struct thread *thread) } bgp_graceful_restart_timer_off(peer); - - return 0; } -static int bgp_graceful_stale_timer_expire(struct thread *thread) +static void bgp_graceful_stale_timer_expire(struct thread *thread) { struct peer *peer; afi_t afi; @@ -860,12 +843,10 @@ static int bgp_graceful_stale_timer_expire(struct thread *thread) FOREACH_AFI_SAFI_NSF (afi, safi) if (peer->nsf[afi][safi]) bgp_clear_stale_route(peer, afi, safi); - - return 0; } /* Selection deferral timer processing function */ -static int bgp_graceful_deferral_timer_expire(struct thread *thread) +static void bgp_graceful_deferral_timer_expire(struct thread *thread) { struct afi_safi_info *info; afi_t afi; @@ -887,7 +868,7 @@ static int bgp_graceful_deferral_timer_expire(struct thread *thread) XFREE(MTYPE_TMP, info); /* Best path selection */ - return bgp_best_path_select_defer(bgp, afi, safi); + bgp_best_path_select_defer(bgp, afi, safi); } static bool bgp_update_delay_applicable(struct bgp *bgp) @@ -1135,7 +1116,7 @@ int bgp_fsm_error_subcode(int status) } /* The maxmed onstartup timer expiry callback. */ -static int bgp_maxmed_onstartup_timer(struct thread *thread) +static void bgp_maxmed_onstartup_timer(struct thread *thread) { struct bgp *bgp; @@ -1146,8 +1127,6 @@ static int bgp_maxmed_onstartup_timer(struct thread *thread) bgp->maxmed_onstartup_over = 1; bgp_maxmed_update(bgp); - - return 0; } static void bgp_maxmed_onstartup_begin(struct bgp *bgp) @@ -1179,7 +1158,7 @@ static void bgp_maxmed_onstartup_process_status_change(struct peer *peer) } /* The update delay timer expiry callback. */ -static int bgp_update_delay_timer(struct thread *thread) +static void bgp_update_delay_timer(struct thread *thread) { struct bgp *bgp; @@ -1188,12 +1167,10 @@ static int bgp_update_delay_timer(struct thread *thread) bgp = THREAD_ARG(thread); THREAD_OFF(bgp->t_update_delay); bgp_update_delay_end(bgp); - - return 0; } /* The establish wait timer expiry callback. */ -static int bgp_establish_wait_timer(struct thread *thread) +static void bgp_establish_wait_timer(struct thread *thread) { struct bgp *bgp; @@ -1202,8 +1179,6 @@ static int bgp_establish_wait_timer(struct thread *thread) bgp = THREAD_ARG(thread); THREAD_OFF(bgp->t_establish_wait); bgp_check_update_delay(bgp); - - return 0; } /* Steps to begin the update delay: @@ -1660,7 +1635,7 @@ static int bgp_stop_with_notify(struct peer *peer, uint8_t code, * when the connection is established. A read event is triggered when the * connection is closed. Thus we need to cancel whichever one did not occur. */ -static int bgp_connect_check(struct thread *thread) +static void bgp_connect_check(struct thread *thread) { int status; socklen_t slen; @@ -1686,7 +1661,7 @@ static int bgp_connect_check(struct thread *thread) zlog_err("can't get sockopt for nonblocking connect: %d(%s)", errno, safe_strerror(errno)); BGP_EVENT_ADD(peer, TCP_fatal_error); - return -1; + return; } /* When status is 0 then TCP connection is established. */ @@ -1695,13 +1670,13 @@ static int bgp_connect_check(struct thread *thread) BGP_EVENT_ADD(peer, TCP_connection_open_w_delay); else BGP_EVENT_ADD(peer, TCP_connection_open); - return 1; + return; } else { if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [Event] Connect failed %d(%s)", peer->host, status, safe_strerror(status)); BGP_EVENT_ADD(peer, TCP_connection_open_failed); - return 0; + return; } } @@ -2542,18 +2517,15 @@ static const struct { }; /* Execute event process. */ -int bgp_event(struct thread *thread) +void bgp_event(struct thread *thread) { enum bgp_fsm_events event; struct peer *peer; - int ret; peer = THREAD_ARG(thread); event = THREAD_VAL(thread); - ret = bgp_event_update(peer, event); - - return (ret); + bgp_event_update(peer, event); } int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index 12cbad3eb..f3d1781ed 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -125,11 +125,11 @@ * Update FSM for peer based on whether we have valid nexthops or not. */ extern void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops); -extern int bgp_event(struct thread *); +extern void bgp_event(struct thread *); extern int bgp_event_update(struct peer *, enum bgp_fsm_events event); extern int bgp_stop(struct peer *peer); extern void bgp_timer_set(struct peer *); -extern int bgp_routeadv_timer(struct thread *); +extern void bgp_routeadv_timer(struct thread *); extern void bgp_fsm_change_status(struct peer *peer, int status); extern const char *const peer_down_str[]; extern void bgp_update_delay_end(struct bgp *); diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index 9b5a31f28..bd0dfb3a6 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -45,8 +45,8 @@ /* forward declarations */ static uint16_t bgp_write(struct peer *); static uint16_t bgp_read(struct peer *peer, int *code_p); -static int bgp_process_writes(struct thread *); -static int bgp_process_reads(struct thread *); +static void bgp_process_writes(struct thread *); +static void bgp_process_reads(struct thread *); static bool validate_header(struct peer *); /* generic i/o status codes */ @@ -121,7 +121,7 @@ void bgp_reads_off(struct peer *peer) /* * Called from I/O pthread when a file descriptor has become ready for writing. */ -static int bgp_process_writes(struct thread *thread) +static void bgp_process_writes(struct thread *thread) { static struct peer *peer; peer = THREAD_ARG(thread); @@ -130,7 +130,7 @@ static int bgp_process_writes(struct thread *thread) bool fatal = false; if (peer->fd < 0) - return -1; + return; struct frr_pthread *fpt = bgp_pth_io; @@ -161,8 +161,6 @@ static int bgp_process_writes(struct thread *thread) BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets, bgp_generate_updgrp_packets); } - - return 0; } /* @@ -172,7 +170,7 @@ static int bgp_process_writes(struct thread *thread) * We read as much data as possible, process as many packets as we can and * place them on peer->ibuf for secondary processing by the main thread. */ -static int bgp_process_reads(struct thread *thread) +static void bgp_process_reads(struct thread *thread) { /* clang-format off */ static struct peer *peer; // peer to read from @@ -186,7 +184,7 @@ static int bgp_process_reads(struct thread *thread) peer = THREAD_ARG(thread); if (peer->fd < 0 || bm->terminating) - return -1; + return; struct frr_pthread *fpt = bgp_pth_io; @@ -271,8 +269,6 @@ static int bgp_process_reads(struct thread *thread) thread_add_event(bm->master, bgp_process_packet, peer, 0, &peer->t_process_packet); } - - return 0; } /* diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index 9d8196878..60ad75c73 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -274,6 +274,9 @@ void lcommunity_unintern(struct lcommunity **lcom) { struct lcommunity *ret; + if (!*lcom) + return; + if ((*lcom)->refcnt) (*lcom)->refcnt--; diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 7fbadab69..ffb1ec162 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -43,7 +43,6 @@ DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group"); DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup"); DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet"); DEFINE_MTYPE(BGPD, ATTR, "BGP attribute"); -DEFINE_MTYPE(BGPD, ATTR_EXTRA, "BGP extra attribute"); DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath"); DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg"); DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index ffab8a1bc..63e7b40ef 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -39,7 +39,6 @@ DECLARE_MTYPE(BGP_UPDGRP); DECLARE_MTYPE(BGP_UPD_SUBGRP); DECLARE_MTYPE(BGP_PACKET); DECLARE_MTYPE(ATTR); -DECLARE_MTYPE(ATTR_EXTRA); DECLARE_MTYPE(AS_PATH); DECLARE_MTYPE(AS_SEG); DECLARE_MTYPE(AS_SEG_DATA); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index ba66bf3b6..6e695d030 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -624,7 +624,8 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, prev_mpath = cur_mpath; mpath_count++; if (ecommunity_linkbw_present( - cur_mpath->attr->ecommunity, + bgp_attr_get_ecommunity( + cur_mpath->attr), &bwval)) cum_bw += bwval; else @@ -714,7 +715,8 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, mpath_changed = 1; mpath_count++; if (ecommunity_linkbw_present( - new_mpath->attr->ecommunity, + bgp_attr_get_ecommunity( + new_mpath->attr), &bwval)) cum_bw += bwval; else @@ -737,9 +739,9 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (new_best) { bgp_path_info_mpath_count_set(new_best, mpath_count - 1); - if (mpath_count <= 1 - || !ecommunity_linkbw_present(new_best->attr->ecommunity, - &bwval)) + if (mpath_count <= 1 || + !ecommunity_linkbw_present( + bgp_attr_get_ecommunity(new_best->attr), &bwval)) all_paths_lb = false; else cum_bw += bwval; @@ -840,11 +842,15 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best, aspath = aspath_dup(attr.aspath); origin = attr.origin; community = - attr.community ? community_dup(attr.community) : NULL; - ecomm = (attr.ecommunity) ? ecommunity_dup(attr.ecommunity) - : NULL; - lcomm = (attr.lcommunity) ? lcommunity_dup(attr.lcommunity) - : NULL; + bgp_attr_get_community(&attr) + ? community_dup(bgp_attr_get_community(&attr)) + : NULL; + ecomm = (bgp_attr_get_ecommunity(&attr)) + ? ecommunity_dup(bgp_attr_get_ecommunity(&attr)) + : NULL; + lcomm = (bgp_attr_get_lcommunity(&attr)) + ? lcommunity_dup(bgp_attr_get_lcommunity(&attr)) + : NULL; for (mpinfo = bgp_path_info_mpath_first(new_best); mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) { @@ -856,55 +862,59 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best, if (origin < mpinfo->attr->origin) origin = mpinfo->attr->origin; - if (mpinfo->attr->community) { + if (bgp_attr_get_community(mpinfo->attr)) { if (community) { commerge = community_merge( community, - mpinfo->attr->community); + bgp_attr_get_community( + mpinfo->attr)); community = community_uniq_sort(commerge); community_free(&commerge); } else community = community_dup( - mpinfo->attr->community); + bgp_attr_get_community( + mpinfo->attr)); } - if (mpinfo->attr->ecommunity) { + if (bgp_attr_get_ecommunity(mpinfo->attr)) { if (ecomm) { ecommerge = ecommunity_merge( - ecomm, - mpinfo->attr->ecommunity); + ecomm, bgp_attr_get_ecommunity( + mpinfo->attr)); ecomm = ecommunity_uniq_sort(ecommerge); ecommunity_free(&ecommerge); } else ecomm = ecommunity_dup( - mpinfo->attr->ecommunity); + bgp_attr_get_ecommunity( + mpinfo->attr)); } - if (mpinfo->attr->lcommunity) { + if (bgp_attr_get_lcommunity(mpinfo->attr)) { if (lcomm) { lcommerge = lcommunity_merge( - lcomm, - mpinfo->attr->lcommunity); + lcomm, bgp_attr_get_lcommunity( + mpinfo->attr)); lcomm = lcommunity_uniq_sort(lcommerge); lcommunity_free(&lcommerge); } else lcomm = lcommunity_dup( - mpinfo->attr->lcommunity); + bgp_attr_get_lcommunity( + mpinfo->attr)); } } attr.aspath = aspath; attr.origin = origin; if (community) { - attr.community = community; + bgp_attr_set_community(&attr, community); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); } if (ecomm) { - attr.ecommunity = ecomm; + bgp_attr_set_ecommunity(&attr, ecomm); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } if (lcomm) { - attr.lcommunity = lcomm; + bgp_attr_set_lcommunity(&attr, lcomm); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES); } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index ce95b355a..32a1d9a15 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -520,18 +520,19 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid) * else: try to allocate as auto-mode */ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index, - struct in6_addr *sid) + struct in6_addr *sid_locator) { struct listnode *node; struct prefix_ipv6 *chunk; struct in6_addr sid_buf; bool alloced = false; - int label; + int label = 0; - if (!bgp || !sid) + if (!bgp || !sid_locator) return false; for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) { + *sid_locator = chunk->prefix; sid_buf = chunk->prefix; if (index != 0) { label = index << 12; @@ -556,7 +557,6 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index, return 0; sid_register(bgp, &sid_buf, bgp->srv6_locator_name); - *sid = sid_buf; return label; } @@ -564,7 +564,7 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi) { int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); char buf[256]; - struct in6_addr *sid; + struct in6_addr *tovpn_sid, *tovpn_sid_locator; uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label; bool tovpn_sid_auto = false; @@ -598,24 +598,33 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi) return; } - sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); + tovpn_sid_locator = + XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); tovpn_sid_transpose_label = - alloc_new_sid(bgp_vpn, tovpn_sid_index, sid); + alloc_new_sid(bgp_vpn, tovpn_sid_index, tovpn_sid_locator); if (tovpn_sid_transpose_label == 0) { zlog_debug("%s: not allocated new sid for vrf %s: afi %s", __func__, bgp_vrf->name_pretty, afi2str(afi)); return; } + tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); + *tovpn_sid = *tovpn_sid_locator; + transpose_sid(tovpn_sid, tovpn_sid_transpose_label, + BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET, + BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH); + if (debug) { - inet_ntop(AF_INET6, sid, buf, sizeof(buf)); + inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf)); zlog_debug("%s: new sid %s allocated for vrf %s: afi %s", __func__, buf, bgp_vrf->name_pretty, afi2str(afi)); } + + bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid; + bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator; bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label = tovpn_sid_transpose_label; - bgp_vrf->vpn_policy[afi].tovpn_sid = sid; } void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, @@ -847,16 +856,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ new_attr->srv6_l3vpn->func_len; extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len; - - if (new_attr->srv6_l3vpn->transposition_len - != 0) - transpose_sid( - &extra->sid[0].sid, - decode_label(label), - new_attr->srv6_l3vpn - ->transposition_offset, - new_attr->srv6_l3vpn - ->transposition_len); + extra->sid[0].transposition_len = + new_attr->srv6_l3vpn->transposition_len; + extra->sid[0].transposition_offset = + new_attr->srv6_l3vpn + ->transposition_offset; } else if (new_attr->srv6_vpn) setsids(bpi, &new_attr->srv6_vpn->sid, num_sids); @@ -951,14 +955,10 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ new_attr->srv6_l3vpn->loc_node_len; extra->sid[0].func_len = new_attr->srv6_l3vpn->func_len; extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len; - - if (new_attr->srv6_l3vpn->transposition_len != 0) - transpose_sid(&extra->sid[0].sid, - decode_label(label), - new_attr->srv6_l3vpn - ->transposition_offset, - new_attr->srv6_l3vpn - ->transposition_len); + extra->sid[0].transposition_len = + new_attr->srv6_l3vpn->transposition_len; + extra->sid[0].transposition_offset = + new_attr->srv6_l3vpn->transposition_offset; } else if (new_attr->srv6_vpn) setsids(new, &new_attr->srv6_vpn->sid, num_sids); } else @@ -1053,9 +1053,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ if (debug) zlog_debug("%s: from vrf %s", __func__, bgp_vrf->name_pretty); - if (debug && path_vrf->attr->ecommunity) { - char *s = ecommunity_ecom2str(path_vrf->attr->ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + if (debug && bgp_attr_get_ecommunity(path_vrf->attr)) { + char *s = ecommunity_ecom2str( + bgp_attr_get_ecommunity(path_vrf->attr), + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); zlog_debug("%s: %s path_vrf->type=%d, EC{%s}", __func__, bgp_vrf->name, path_vrf->type, s); @@ -1111,9 +1112,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ } } - if (debug && static_attr.ecommunity) { - char *s = ecommunity_ecom2str(static_attr.ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + if (debug && bgp_attr_get_ecommunity(&static_attr)) { + char *s = ecommunity_ecom2str( + bgp_attr_get_ecommunity(&static_attr), + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); zlog_debug("%s: post route map static_attr.ecommunity{%s}", __func__, s); @@ -1128,7 +1130,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ /* Export with the 'from' instance's export RTs. */ /* If doing VRF-to-VRF leaking, strip existing RTs first. */ - old_ecom = static_attr.ecommunity; + old_ecom = bgp_attr_get_ecommunity(&static_attr); if (old_ecom) { new_ecom = ecommunity_dup(old_ecom); if (CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST], @@ -1144,12 +1146,13 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ bgp_vrf->vpn_policy[afi] .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); } - static_attr.ecommunity = new_ecom; + bgp_attr_set_ecommunity(&static_attr, new_ecom); SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)); - if (debug && static_attr.ecommunity) { - char *s = ecommunity_ecom2str(static_attr.ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + if (debug && bgp_attr_get_ecommunity(&static_attr)) { + char *s = ecommunity_ecom2str( + bgp_attr_get_ecommunity(&static_attr), + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); zlog_debug("%s: post merge static_attr.ecommunity{%s}", __func__, s); @@ -1232,7 +1235,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ static_attr.originator_id = bgp_vpn->router_id; /* Set SID for SRv6 VPN */ - if (bgp_vrf->vpn_policy[afi].tovpn_sid) { + if (bgp_vrf->vpn_policy[afi].tovpn_sid_locator) { encode_label(bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label, &label); static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, @@ -1252,8 +1255,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ static_attr.srv6_l3vpn->transposition_offset = BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET; memcpy(&static_attr.srv6_l3vpn->sid, - bgp_vrf->vpn_policy[afi].tovpn_sid, - sizeof(static_attr.srv6_l3vpn->sid)); + bgp_vrf->vpn_policy[afi].tovpn_sid_locator, + sizeof(struct in6_addr)); } @@ -1261,8 +1264,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ &static_attr); /* hashed refcounted everything */ bgp_attr_flush(&static_attr); /* free locally-allocated parts */ - if (debug && new_attr->ecommunity) { - char *s = ecommunity_ecom2str(new_attr->ecommunity, + if (debug && bgp_attr_get_ecommunity(new_attr)) { + char *s = ecommunity_ecom2str(bgp_attr_get_ecommunity(new_attr), ECOMMUNITY_FORMAT_ROUTE_MAP, 0); zlog_debug("%s: new_attr->ecommunity{%s}", __func__, s); @@ -1481,7 +1484,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ /* Check for intersection of route targets */ if (!ecom_intersect( bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN], - path_vpn->attr->ecommunity)) { + bgp_attr_get_ecommunity(path_vpn->attr))) { if (debug) zlog_debug( "from vpn to vrf %s, skipping after no intersection of route targets", @@ -1500,18 +1503,18 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ struct ecommunity *new_ecom; /* If doing VRF-to-VRF leaking, strip RTs. */ - old_ecom = static_attr.ecommunity; + old_ecom = bgp_attr_get_ecommunity(&static_attr); if (old_ecom && CHECK_FLAG(bgp_vrf->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT)) { new_ecom = ecommunity_dup(old_ecom); ecommunity_strip_rts(new_ecom); - static_attr.ecommunity = new_ecom; + bgp_attr_set_ecommunity(&static_attr, new_ecom); if (new_ecom->size == 0) { UNSET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)); ecommunity_free(&new_ecom); - static_attr.ecommunity = NULL; + bgp_attr_set_ecommunity(&static_attr, NULL); } if (!old_ecom->refcnt) @@ -1728,7 +1731,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */ /* Check for intersection of route targets */ if (!ecom_intersect(bgp->vpn_policy[afi] .rtlist[BGP_VPN_POLICY_DIR_FROMVPN], - path_vpn->attr->ecommunity)) { + bgp_attr_get_ecommunity(path_vpn->attr))) { continue; } diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index b0d586223..5bf772fef 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -21,6 +21,7 @@ #ifndef _QUAGGA_BGP_MPLSVPN_H #define _QUAGGA_BGP_MPLSVPN_H +#include "bgpd/bgp_attr.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_rd.h" #include "bgpd/bgp_zebra.h" diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 3fb7619ed..0c325b678 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -342,7 +342,7 @@ static void bgp_socket_set_buffer_size(const int fd) } /* Accept bgp connection. */ -static int bgp_accept(struct thread *thread) +static void bgp_accept(struct thread *thread) { int bgp_sock; int accept_sock; @@ -363,7 +363,7 @@ static int bgp_accept(struct thread *thread) flog_err_sys(EC_LIB_SOCKET, "[Error] BGP accept socket fd is negative: %d", accept_sock); - return -1; + return; } thread_add_read(bm->master, bgp_accept, listener, accept_sock, @@ -402,7 +402,7 @@ static int bgp_accept(struct thread *thread) "[Error] BGP socket accept failed (%s); retrying", safe_strerror(save_errno)); } - return -1; + return; } set_nonblocking(bgp_sock); @@ -418,7 +418,7 @@ static int bgp_accept(struct thread *thread) "[Event] Could not get instance for incoming conn from %s", inet_sutop(&su, buf)); close(bgp_sock); - return -1; + return; } bgp_socket_set_buffer_size(bgp_sock); @@ -451,7 +451,7 @@ static int bgp_accept(struct thread *thread) TCP_connection_open); } - return 0; + return; } } @@ -463,7 +463,7 @@ static int bgp_accept(struct thread *thread) VRF_LOGNAME(vrf_lookup_by_id(bgp->vrf_id))); } close(bgp_sock); - return -1; + return; } if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN) @@ -474,7 +474,7 @@ static int bgp_accept(struct thread *thread) inet_sutop(&su, buf), bgp->name_pretty, bgp->as, VRF_LOGNAME(vrf_lookup_by_id(bgp->vrf_id))); close(bgp_sock); - return -1; + return; } /* @@ -489,7 +489,7 @@ static int bgp_accept(struct thread *thread) "[Event] Closing incoming conn for %s (%p) state %d", peer1->host, peer1, peer1->status); close(bgp_sock); - return -1; + return; } /* Check that at least one AF is activated for the peer. */ @@ -499,7 +499,7 @@ static int bgp_accept(struct thread *thread) "%s - incoming conn rejected - no AF activated for peer", peer1->host); close(bgp_sock); - return -1; + return; } /* Do not try to reconnect if the peer reached maximum @@ -512,7 +512,7 @@ static int bgp_accept(struct thread *thread) "[Event] Incoming BGP connection rejected from %s due to maximum-prefix or shutdown", peer1->host); close(bgp_sock); - return -1; + return; } if (bgp_debug_neighbor_events(peer1)) @@ -600,8 +600,6 @@ static int bgp_accept(struct thread *thread) * massage the event system to make things happy */ bgp_nht_interface_events(peer); - - return 0; } /* BGP socket bind. */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 19ae13720..d76873354 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -49,12 +49,10 @@ extern struct zclient *zclient; -static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, - int is_bgp_static_route); -static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, - int is_bgp_static_route); +static void register_zebra_rnh(struct bgp_nexthop_cache *bnc); +static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc); static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p); -static int bgp_nht_ifp_initial(struct thread *thread); +static void bgp_nht_ifp_initial(struct thread *thread); static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc) { @@ -92,8 +90,7 @@ static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) } /* only unregister if this is the last nh for this prefix*/ if (!bnc_existing_for_prefix(bnc)) - unregister_zebra_rnh( - bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)); + unregister_zebra_rnh(bnc); bnc_free(bnc); } } @@ -308,7 +305,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) && !is_default_host_route(&bnc->prefix)) - register_zebra_rnh(bnc, is_bgp_static_route); + register_zebra_rnh(bnc); if (pi && pi->nexthop != bnc) { /* Unlink from existing nexthop cache, if any. This will also @@ -387,7 +384,7 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer) zlog_debug( "Freeing connected NHT node %p for peer %s(%s)", bnc, peer->host, bnc->bgp->name_pretty); - unregister_zebra_rnh(bnc, 0); + unregister_zebra_rnh(bnc); bnc_free(bnc); } } @@ -608,14 +605,14 @@ void bgp_nht_ifp_down(struct interface *ifp) bgp_nht_ifp_handle(ifp, false); } -static int bgp_nht_ifp_initial(struct thread *thread) +static void bgp_nht_ifp_initial(struct thread *thread) { ifindex_t ifindex = THREAD_VAL(thread); struct bgp *bgp = THREAD_ARG(thread); struct interface *ifp = if_lookup_by_index(ifindex, bgp->vrf_id); if (!ifp) - return 0; + return; if (BGP_DEBUG(nht, NHT)) zlog_debug( @@ -626,8 +623,6 @@ static int bgp_nht_ifp_initial(struct thread *thread) bgp_nht_ifp_up(ifp); else bgp_nht_ifp_down(ifp); - - return 0; } /* @@ -667,6 +662,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) struct bgp_nexthop_cache_head *tree = NULL; struct bgp_nexthop_cache *bnc_nhc, *bnc_import; struct bgp *bgp; + struct prefix match; struct zapi_route nhr; afi_t afi; @@ -679,16 +675,16 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) return; } - if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) { zlog_err("%s[%s]: Failure to decode nexthop update", __func__, bgp->name_pretty); return; } - afi = family2afi(nhr.prefix.family); + afi = family2afi(match.family); tree = &bgp->nexthop_cache_table[afi]; - bnc_nhc = bnc_find(tree, &nhr.prefix, nhr.srte_color); + bnc_nhc = bnc_find(tree, &match, nhr.srte_color); if (!bnc_nhc) { if (BGP_DEBUG(nht, NHT)) zlog_debug( @@ -699,7 +695,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) tree = &bgp->import_check_table[afi]; - bnc_import = bnc_find(tree, &nhr.prefix, nhr.srte_color); + bnc_import = bnc_find(tree, &match, nhr.srte_color); if (!bnc_import) { if (BGP_DEBUG(nht, NHT)) zlog_debug( @@ -916,8 +912,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) * RETURNS: * void. */ -static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, - int is_bgp_import_route) +static void register_zebra_rnh(struct bgp_nexthop_cache *bnc) { /* Check if we have already registered */ if (bnc->flags & BGP_NEXTHOP_REGISTERED) @@ -938,8 +933,7 @@ static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, * RETURNS: * void. */ -static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, - int is_bgp_import_route) +static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc) { /* Check if we have already registered */ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) @@ -1174,7 +1168,7 @@ void bgp_nht_register_nexthops(struct bgp *bgp) frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], bnc) { - register_zebra_rnh(bnc, 0); + register_zebra_rnh(bnc); } } } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 4bb08404d..09db04178 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -386,7 +386,7 @@ static void bgp_write_proceed_actions(struct peer *peer) * update group a peer belongs to, encode this information into packets, and * enqueue the packets onto the peer's output buffer. */ -int bgp_generate_updgrp_packets(struct thread *thread) +void bgp_generate_updgrp_packets(struct thread *thread) { struct peer *peer = THREAD_ARG(thread); @@ -407,14 +407,14 @@ int bgp_generate_updgrp_packets(struct thread *thread) * update-delay processing). */ if (!peer_established(peer)) - return 0; + return; if ((peer->bgp->main_peers_update_hold) || bgp_update_delay_active(peer->bgp)) - return 0; + return; if (peer->t_routeadv) - return 0; + return; do { enum bgp_af_index index; @@ -541,8 +541,6 @@ int bgp_generate_updgrp_packets(struct thread *thread) bgp_writes_on(peer); bgp_write_proceed_actions(peer); - - return 0; } /* @@ -667,9 +665,6 @@ static void bgp_write_notify(struct peer *peer) assert(stream_get_endp(s) >= BGP_HEADER_SIZE); - /* Stop collecting data within the socket */ - sockopt_cork(peer->fd, 0); - /* * socket is in nonblocking mode, if we can't deliver the NOTIFY, well, * we only care about getting a clean shutdown at this point. @@ -1540,7 +1535,7 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size) return Receive_KEEPALIVE_message; } -static int bgp_refresh_stalepath_timer_expire(struct thread *thread) +static void bgp_refresh_stalepath_timer_expire(struct thread *thread) { struct peer_af *paf; @@ -1560,8 +1555,6 @@ static int bgp_refresh_stalepath_timer_expire(struct thread *thread) peer->host, afi2str(afi), safi2str(safi)); bgp_timer_set(peer); - - return 0; } /** @@ -2573,7 +2566,7 @@ int bgp_capability_receive(struct peer *peer, bgp_size_t size) * @param thread * @return 0 */ -int bgp_process_packet(struct thread *thread) +void bgp_process_packet(struct thread *thread) { /* Yes first of all get peer pointer. */ struct peer *peer; // peer @@ -2588,7 +2581,7 @@ int bgp_process_packet(struct thread *thread) /* Guard against scheduled events that occur after peer deletion. */ if (peer->status == Deleted || peer->status == Clearing) - return 0; + return; unsigned int processed = 0; @@ -2602,7 +2595,7 @@ int bgp_process_packet(struct thread *thread) } if (peer->curr == NULL) // no packets to process, hmm... - return 0; + return; /* skip the marker and copy the packet length */ stream_forward_getp(peer->curr, BGP_MARKER_SIZE); @@ -2732,8 +2725,6 @@ int bgp_process_packet(struct thread *thread) &peer->t_process_packet); } } - - return 0; } /* Send EOR when routes are processed by selection deferral timer */ @@ -2752,7 +2743,7 @@ void bgp_send_delayed_eor(struct bgp *bgp) * having the io pthread try to enqueue fsm events or mess with the peer * struct. */ -int bgp_packet_process_error(struct thread *thread) +void bgp_packet_process_error(struct thread *thread) { struct peer *peer; int code; @@ -2777,6 +2768,4 @@ int bgp_packet_process_error(struct thread *thread) } bgp_event_update(peer, code); - - return 0; } diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 280d3ec17..8c2de6d62 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -79,12 +79,12 @@ extern void bgp_check_update_delay(struct bgp *); extern int bgp_packet_set_marker(struct stream *s, uint8_t type); extern void bgp_packet_set_size(struct stream *s); -extern int bgp_generate_updgrp_packets(struct thread *); -extern int bgp_process_packet(struct thread *); +extern void bgp_generate_updgrp_packets(struct thread *); +extern void bgp_process_packet(struct thread *); extern void bgp_send_delayed_eor(struct bgp *bgp); /* Task callback to handle socket error encountered in the io pthread */ -int bgp_packet_process_error(struct thread *thread); +void bgp_packet_process_error(struct thread *thread); #endif /* _QUAGGA_BGP_PACKET_H */ diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index c10007a59..d3609cb01 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -770,8 +770,8 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, if (ret < 0) return -1; /* extract actiosn from flowspec ecom list */ - if (path && path->attr->ecommunity) { - ecom = path->attr->ecommunity; + if (path && bgp_attr_get_ecommunity(path->attr)) { + ecom = bgp_attr_get_ecommunity(path->attr); for (i = 0; i < ecom->size; i++) { ecom_eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); @@ -1314,10 +1314,7 @@ bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2) if (r1->afi != r2->afi) return false; - if (memcmp(&r1->nh, &r2->nh, sizeof(struct nexthop))) - return false; - - return true; + return nexthop_same(&r1->nh, &r2->nh); } struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 331f98fe9..78e4964d9 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -641,8 +641,9 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * below). See the Risks of Depreferencing Routes section (Section 5.2) * for a discussion of potential risks inherent in doing this. */ - if (newattr->community && - community_include(newattr->community, COMMUNITY_LLGR_STALE)) { + if (bgp_attr_get_community(newattr) && + community_include(bgp_attr_get_community(newattr), + COMMUNITY_LLGR_STALE)) { if (debug) zlog_debug( "%s: %s wins over %s due to LLGR_STALE community", @@ -650,8 +651,9 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 0; } - if (existattr->community && - community_include(existattr->community, COMMUNITY_LLGR_STALE)) { + if (bgp_attr_get_community(existattr) && + community_include(bgp_attr_get_community(existattr), + COMMUNITY_LLGR_STALE)) { if (debug) zlog_debug( "%s: %s loses to %s due to LLGR_STALE community", @@ -1522,20 +1524,22 @@ done: /* If community attribute includes no_export then return 1. */ static bool bgp_community_filter(struct peer *peer, struct attr *attr) { - if (attr->community) { + if (bgp_attr_get_community(attr)) { /* NO_ADVERTISE check. */ - if (community_include(attr->community, COMMUNITY_NO_ADVERTISE)) + if (community_include(bgp_attr_get_community(attr), + COMMUNITY_NO_ADVERTISE)) return true; /* NO_EXPORT check. */ - if (peer->sort == BGP_PEER_EBGP - && community_include(attr->community, COMMUNITY_NO_EXPORT)) + if (peer->sort == BGP_PEER_EBGP && + community_include(bgp_attr_get_community(attr), + COMMUNITY_NO_EXPORT)) return true; /* NO_EXPORT_SUBCONFED check. */ if (peer->sort == BGP_PEER_EBGP || peer->sort == BGP_PEER_CONFED) - if (community_include(attr->community, + if (community_include(bgp_attr_get_community(attr), COMMUNITY_NO_EXPORT_SUBCONFED)) return true; } @@ -1745,7 +1749,7 @@ void bgp_attr_add_llgr_community(struct attr *attr) struct community *merge; struct community *llgr; - old = attr->community; + old = bgp_attr_get_community(attr); llgr = community_str2com("llgr-stale"); assert(llgr); @@ -1764,7 +1768,7 @@ void bgp_attr_add_llgr_community(struct attr *attr) community_free(&llgr); - attr->community = new; + bgp_attr_set_community(attr, new); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); } @@ -1775,7 +1779,7 @@ void bgp_attr_add_gshut_community(struct attr *attr) struct community *merge; struct community *gshut; - old = attr->community; + old = bgp_attr_get_community(attr); gshut = community_str2com("graceful-shutdown"); assert(gshut); @@ -1793,7 +1797,7 @@ void bgp_attr_add_gshut_community(struct attr *attr) } community_free(&gshut); - attr->community = new; + bgp_attr_set_community(attr, new); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); /* When we add the graceful-shutdown community we must also @@ -1836,7 +1840,7 @@ void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr) bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, struct update_subgroup *subgrp, const struct prefix *p, struct attr *attr, - bool skip_rmap_check) + struct attr *post_attr) { struct bgp_filter *filter; struct peer *from; @@ -2067,8 +2071,16 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } } - /* For modify attribute, copy it to temporary structure. */ - *attr = *piattr; + /* For modify attribute, copy it to temporary structure. + * post_attr comes from BGP conditional advertisements, where + * attributes are already processed by advertise-map route-map, + * and this needs to be saved instead of overwriting from the + * path attributes. + */ + if (post_attr) + *attr = *post_attr; + else + *attr = *piattr; /* If local-preference is not set. */ if ((peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) @@ -2162,8 +2174,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, bgp_peer_as_override(bgp, afi, safi, peer, attr); /* Route map & unsuppress-map apply. */ - if (!skip_rmap_check - && (ROUTE_MAP_OUT_NAME(filter) || bgp_path_suppressed(pi))) { + if (!post_attr && + (ROUTE_MAP_OUT_NAME(filter) || bgp_path_suppressed(pi))) { struct bgp_path_info rmap_path = {0}; struct bgp_path_info_extra dummy_rmap_path_extra = {0}; struct attr dummy_attr = {0}; @@ -2200,10 +2212,11 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, if (ret == RMAP_DENYMATCH) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( - "%s [Update:SEND] %pFX is filtered by route-map", - peer->host, p); + "%s [Update:SEND] %pFX is filtered by route-map '%s'", + peer->host, p, + ROUTE_MAP_OUT_NAME(filter)); - bgp_attr_flush(attr); + bgp_attr_flush(&dummy_attr); return false; } } @@ -2218,8 +2231,16 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * implementations. */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_EBGP_REQUIRES_POLICY)) - if (!bgp_outbound_policy_exists(peer, filter)) + if (!bgp_outbound_policy_exists(peer, filter)) { + if (monotime_since(&bgp->ebgprequirespolicywarning, + NULL) > FIFTEENMINUTE2USEC || + bgp->ebgprequirespolicywarning.tv_sec == 0) { + zlog_warn( + "EBGP inbound/outbound policy not properly setup, please configure in order for your peering to work correctly"); + monotime(&bgp->ebgprequirespolicywarning); + } return false; + } /* draft-ietf-idr-deprecate-as-set-confed-set * Filter routes having AS_SET or AS_CONFED_SET in the path. @@ -2253,8 +2274,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * The route SHOULD NOT be advertised to any neighbor from which the * Long-lived Graceful Restart Capability has not been received. */ - if (attr->community && - community_include(attr->community, COMMUNITY_LLGR_STALE) && + if (bgp_attr_get_community(attr) && + community_include(bgp_attr_get_community(attr), + COMMUNITY_LLGR_STALE) && !CHECK_FLAG(peer->cap, PEER_CAP_LLGR_RCV) && !CHECK_FLAG(peer->cap, PEER_CAP_LLGR_ADV)) return false; @@ -2374,15 +2396,18 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, bgp_path_info_mpath_chkwtd(bgp, pi) && (cum_bw = bgp_path_info_mpath_cumbw(pi)) != 0 && !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET)) - attr->ecommunity = ecommunity_replace_linkbw( - bgp->as, attr->ecommunity, cum_bw, - CHECK_FLAG(peer->flags, - PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); + bgp_attr_set_ecommunity( + attr, + ecommunity_replace_linkbw( + bgp->as, bgp_attr_get_ecommunity(attr), cum_bw, + CHECK_FLAG( + peer->flags, + PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE))); return true; } -static int bgp_route_select_timer_expire(struct thread *thread) +static void bgp_route_select_timer_expire(struct thread *thread) { struct afi_safi_info *info; afi_t afi; @@ -2403,7 +2428,7 @@ static int bgp_route_select_timer_expire(struct thread *thread) XFREE(MTYPE_TMP, info); /* Best path selection */ - return bgp_best_path_select_defer(bgp, afi, safi); + bgp_best_path_select_defer(bgp, afi, safi); } void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, @@ -2687,7 +2712,7 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, if (selected) { if (subgroup_announce_check(dest, selected, subgrp, p, &attr, - false)) { + NULL)) { /* Route is selected, if the route is already installed * in FIB, then it is advertised */ @@ -3334,7 +3359,7 @@ void bgp_add_eoiu_mark(struct bgp *bgp) work_queue_add(bgp->process_queue, pqnode); } -static int bgp_maximum_prefix_restart_timer(struct thread *thread) +static void bgp_maximum_prefix_restart_timer(struct thread *thread) { struct peer *peer; @@ -3348,8 +3373,6 @@ static int bgp_maximum_prefix_restart_timer(struct thread *thread) if ((peer_clear(peer, NULL) < 0) && bgp_debug_neighbor_events(peer)) zlog_debug("%s: %s peer_clear failed", __func__, peer->host); - - return 0; } static uint32_t bgp_filtered_routes_count(struct peer *peer, afi_t afi, @@ -3382,7 +3405,7 @@ static uint32_t bgp_filtered_routes_count(struct peer *peer, afi_t afi, if (filtered) count++; - bgp_attr_undup(&attr, ain->attr); + bgp_attr_flush(&attr); } } @@ -3668,7 +3691,7 @@ static void bgp_attr_add_no_export_community(struct attr *attr) struct community *merge; struct community *no_export; - old = attr->community; + old = bgp_attr_get_community(attr); no_export = community_str2com("no-export"); assert(no_export); @@ -3687,7 +3710,7 @@ static void bgp_attr_add_no_export_community(struct attr *attr) community_free(&no_export); - attr->community = new; + bgp_attr_set_community(attr, new); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); } @@ -3840,6 +3863,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (!bgp_inbound_policy_exists(peer, &peer->filter[afi][safi])) { reason = "inbound policy missing"; + if (monotime_since(&bgp->ebgprequirespolicywarning, + NULL) > FIFTEENMINUTE2USEC || + bgp->ebgprequirespolicywarning.tv_sec == 0) { + zlog_warn( + "EBGP inbound/outbound policy not properly setup, please configure in order for your peering to work correctly"); + monotime(&bgp->ebgprequirespolicywarning); + } goto filtered; } @@ -3890,15 +3920,16 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * propagation SHOULD be chosen according to the operator's * routing policy. */ - if (new_attr.community - && community_include(new_attr.community, - COMMUNITY_BLACKHOLE)) + if (bgp_attr_get_community(&new_attr) && + community_include(bgp_attr_get_community(&new_attr), + COMMUNITY_BLACKHOLE)) bgp_attr_add_no_export_community(&new_attr); /* If we receive the graceful-shutdown community from an eBGP * peer we must lower local-preference */ - if (new_attr.community - && community_include(new_attr.community, COMMUNITY_GSHUT)) { + if (bgp_attr_get_community(&new_attr) && + community_include(bgp_attr_get_community(&new_attr), + COMMUNITY_GSHUT)) { new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); new_attr.local_pref = BGP_GSHUT_LOCAL_PREF; @@ -3926,6 +3957,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (bgp_mac_entry_exists(p) || bgp_mac_exist(&attr->rmac)) { peer->stat_pfx_nh_invalid++; reason = "self mac;"; + bgp_attr_flush(&new_attr); goto filtered; } @@ -3942,13 +3974,15 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, && (!CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED))) SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); - attr_new = bgp_attr_intern(&new_attr); - /* If maximum prefix count is configured and current prefix * count exeed it. */ - if (bgp_maximum_prefix_overflow(peer, afi, safi, 0)) + if (bgp_maximum_prefix_overflow(peer, afi, safi, 0)) { + bgp_attr_flush(&new_attr); return -1; + } + + attr_new = bgp_attr_intern(&new_attr); /* If the update is implicit withdraw. */ if (pi) { @@ -4118,16 +4152,19 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { int cmp; - cmp = ecommunity_cmp(pi->attr->ecommunity, - attr_new->ecommunity); + cmp = ecommunity_cmp( + bgp_attr_get_ecommunity(pi->attr), + bgp_attr_get_ecommunity(attr_new)); if (!cmp) { if (bgp_debug_update(peer, p, NULL, 1)) zlog_debug( "Change in EXT-COMM, existing %s new %s", ecommunity_str( - pi->attr->ecommunity), + bgp_attr_get_ecommunity( + pi->attr)), ecommunity_str( - attr_new->ecommunity)); + bgp_attr_get_ecommunity( + attr_new))); if (safi == SAFI_EVPN) bgp_evpn_unimport_route( bgp, afi, safi, p, pi); @@ -4167,6 +4204,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, extra->sid[0].loc_node_len = 0; extra->sid[0].func_len = 0; extra->sid[0].arg_len = 0; + extra->sid[0].transposition_len = 0; + extra->sid[0].transposition_offset = 0; if (attr->srv6_l3vpn->loc_block_len != 0) { extra->sid[0].loc_block_len = @@ -4177,21 +4216,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, attr->srv6_l3vpn->func_len; extra->sid[0].arg_len = attr->srv6_l3vpn->arg_len; - } - - /* - * draft-ietf-bess-srv6-services-07 - * The part of SRv6 SID may be encoded as MPLS - * Label for the efficient packing. - */ - if (attr->srv6_l3vpn->transposition_len != 0) - transpose_sid( - &extra->sid[0].sid, - decode_label(label), + extra->sid[0].transposition_len = attr->srv6_l3vpn - ->transposition_offset, + ->transposition_len; + extra->sid[0].transposition_offset = attr->srv6_l3vpn - ->transposition_len); + ->transposition_offset; + } } } else if (attr->srv6_vpn) { extra = bgp_path_info_extra_get(pi); @@ -4388,17 +4419,10 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, attr->srv6_l3vpn->loc_node_len; extra->sid[0].func_len = attr->srv6_l3vpn->func_len; extra->sid[0].arg_len = attr->srv6_l3vpn->arg_len; - - /* - * draft-ietf-bess-srv6-services-07 - * The part of SRv6 SID may be encoded as MPLS Label for - * the efficient packing. - */ - if (attr->srv6_l3vpn->transposition_len != 0) - transpose_sid( - &extra->sid[0].sid, decode_label(label), - attr->srv6_l3vpn->transposition_offset, - attr->srv6_l3vpn->transposition_len); + extra->sid[0].transposition_len = + attr->srv6_l3vpn->transposition_len; + extra->sid[0].transposition_offset = + attr->srv6_l3vpn->transposition_offset; } else if (attr->srv6_vpn) { sid_copy(&extra->sid[0].sid, &attr->srv6_vpn->sid); extra->num_sids = 1; @@ -4677,7 +4701,7 @@ void bgp_stop_announce_route_timer(struct peer_af *paf) * Callback that is invoked when the route announcement timer for a * peer_af expires. */ -static int bgp_announce_route_timer_expired(struct thread *t) +static void bgp_announce_route_timer_expired(struct thread *t) { struct peer_af *paf; struct peer *peer; @@ -4686,17 +4710,15 @@ static int bgp_announce_route_timer_expired(struct thread *t) peer = paf->peer; if (!peer_established(peer)) - return 0; + return; if (!peer->afc_nego[paf->afi][paf->safi]) - return 0; + return; peer_af_announce_route(paf, 1); /* Notify BGP conditional advertisement scanner percess */ peer->advmap_config_change[paf->afi][paf->safi] = true; - - return 0; } /* @@ -4846,7 +4868,7 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi, * Without splitting the full job into several part, * vtysh waits for the job to finish before responding to a BGP command */ -static int bgp_soft_reconfig_table_task(struct thread *thread) +static void bgp_soft_reconfig_table_task(struct thread *thread) { uint32_t iter, max_iter; int ret; @@ -4900,7 +4922,7 @@ static int bgp_soft_reconfig_table_task(struct thread *thread) &table->soft_reconfig_peers); bgp_soft_reconfig_table_flag( table, false); - return 0; + return; } } } @@ -4914,7 +4936,7 @@ static int bgp_soft_reconfig_table_task(struct thread *thread) table->soft_reconfig_init = false; thread_add_event(bm->master, bgp_soft_reconfig_table_task, table, 0, &table->soft_reconfig_thread); - return 0; + return; } /* we're done, clean up the background iteration context info and schedule route annoucement @@ -4925,8 +4947,6 @@ static int bgp_soft_reconfig_table_task(struct thread *thread) } list_delete(&table->soft_reconfig_peers); - - return 0; } @@ -5351,14 +5371,15 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) if (CHECK_FLAG( peer->af_sflags[afi][safi], PEER_STATUS_LLGR_WAIT) && - pi->attr->community && + bgp_attr_get_community(pi->attr) && !community_include( - pi->attr->community, + bgp_attr_get_community( + pi->attr), COMMUNITY_NO_LLGR)) - break; + continue; if (!CHECK_FLAG(pi->flags, BGP_PATH_STALE)) - break; + continue; /* * If this is VRF leaked route @@ -5384,12 +5405,13 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) continue; if (CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_LLGR_WAIT) && - pi->attr->community && - !community_include(pi->attr->community, - COMMUNITY_NO_LLGR)) - break; + bgp_attr_get_community(pi->attr) && + !community_include( + bgp_attr_get_community(pi->attr), + COMMUNITY_NO_LLGR)) + continue; if (!CHECK_FLAG(pi->flags, BGP_PATH_STALE)) - break; + continue; if (safi == SAFI_UNICAST && (peer->bgp->inst_type == BGP_INSTANCE_TYPE_VRF || @@ -6932,6 +6954,7 @@ static bool aggr_suppress_map_test(struct bgp *bgp, bgp->peer_self->rmap_type = 0; bgp_attr_flush(&attr); + aspath_unintern(&attr.aspath); return rmr == RMAP_PERMITMATCH; } @@ -7029,13 +7052,13 @@ static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin, if (!aspath_cmp(pi->attr->aspath, (aspath) ? aspath : ae)) return false; - if (!community_cmp(pi->attr->community, comm)) + if (!community_cmp(bgp_attr_get_community(pi->attr), comm)) return false; - if (!ecommunity_cmp(pi->attr->ecommunity, ecomm)) + if (!ecommunity_cmp(bgp_attr_get_ecommunity(pi->attr), ecomm)) return false; - if (!lcommunity_cmp(pi->attr->lcommunity, lcomm)) + if (!lcommunity_cmp(bgp_attr_get_lcommunity(pi->attr), lcomm)) return false; if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID)) @@ -7448,24 +7471,24 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, /* Compute aggregate route's community. */ - if (pi->attr->community) + if (bgp_attr_get_community(pi->attr)) bgp_compute_aggregate_community_hash( - aggregate, - pi->attr->community); + aggregate, + bgp_attr_get_community(pi->attr)); /* Compute aggregate route's extended community. */ - if (pi->attr->ecommunity) + if (bgp_attr_get_ecommunity(pi->attr)) bgp_compute_aggregate_ecommunity_hash( - aggregate, - pi->attr->ecommunity); + aggregate, + bgp_attr_get_ecommunity(pi->attr)); /* Compute aggregate route's large community. */ - if (pi->attr->lcommunity) + if (bgp_attr_get_lcommunity(pi->attr)) bgp_compute_aggregate_lcommunity_hash( - aggregate, - pi->attr->lcommunity); + aggregate, + bgp_attr_get_lcommunity(pi->attr)); } if (match) bgp_process(bgp, dest, afi, safi); @@ -7570,26 +7593,29 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, aggregate, pi->attr->aspath); - if (pi->attr->community) + if (bgp_attr_get_community(pi->attr)) /* Remove community from aggregate. */ bgp_remove_comm_from_aggregate_hash( - aggregate, - pi->attr->community); + aggregate, + bgp_attr_get_community( + pi->attr)); - if (pi->attr->ecommunity) + if (bgp_attr_get_ecommunity(pi->attr)) /* Remove ecommunity from aggregate. */ bgp_remove_ecomm_from_aggregate_hash( - aggregate, - pi->attr->ecommunity); + aggregate, + bgp_attr_get_ecommunity( + pi->attr)); - if (pi->attr->lcommunity) + if (bgp_attr_get_lcommunity(pi->attr)) /* Remove lcommunity from aggregate. */ bgp_remove_lcomm_from_aggregate_hash( - aggregate, - pi->attr->lcommunity); + aggregate, + bgp_attr_get_lcommunity( + pi->attr)); } } @@ -7688,24 +7714,23 @@ static void bgp_add_route_to_aggregate(struct bgp *bgp, /* Compute aggregate route's community. */ - if (pinew->attr->community) + if (bgp_attr_get_community(pinew->attr)) bgp_compute_aggregate_community( - aggregate, - pinew->attr->community); + aggregate, bgp_attr_get_community(pinew->attr)); /* Compute aggregate route's extended community. */ - if (pinew->attr->ecommunity) + if (bgp_attr_get_ecommunity(pinew->attr)) bgp_compute_aggregate_ecommunity( - aggregate, - pinew->attr->ecommunity); + aggregate, + bgp_attr_get_ecommunity(pinew->attr)); /* Compute aggregate route's large community. */ - if (pinew->attr->lcommunity) + if (bgp_attr_get_lcommunity(pinew->attr)) bgp_compute_aggregate_lcommunity( - aggregate, - pinew->attr->lcommunity); + aggregate, + bgp_attr_get_lcommunity(pinew->attr)); /* Retrieve aggregate route's as-path. */ @@ -7791,26 +7816,23 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, bgp_remove_aspath_from_aggregate(aggregate, pi->attr->aspath); - if (pi->attr->community) + if (bgp_attr_get_community(pi->attr)) /* Remove community from aggregate. */ bgp_remove_community_from_aggregate( - aggregate, - pi->attr->community); + aggregate, bgp_attr_get_community(pi->attr)); - if (pi->attr->ecommunity) + if (bgp_attr_get_ecommunity(pi->attr)) /* Remove ecommunity from aggregate. */ bgp_remove_ecommunity_from_aggregate( - aggregate, - pi->attr->ecommunity); + aggregate, bgp_attr_get_ecommunity(pi->attr)); - if (pi->attr->lcommunity) + if (bgp_attr_get_lcommunity(pi->attr)) /* Remove lcommunity from aggregate. */ bgp_remove_lcommunity_from_aggregate( - aggregate, - pi->attr->lcommunity); + aggregate, bgp_attr_get_lcommunity(pi->attr)); } /* If this node was suppressed, process the change. */ @@ -9130,9 +9152,9 @@ void route_vty_out(struct vty *vty, const struct prefix *p, if (safi == SAFI_EVPN && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { json_ext_community = json_object_new_object(); - json_object_string_add(json_ext_community, - "string", - attr->ecommunity->str); + json_object_string_add( + json_ext_community, "string", + bgp_attr_get_ecommunity(attr)->str); json_object_object_add(json_path, "extendedCommunity", json_ext_community); @@ -9185,7 +9207,8 @@ void route_vty_out(struct vty *vty, const struct prefix *p, if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { vty_out(vty, "%*s", 20, " "); - vty_out(vty, "%s\n", attr->ecommunity->str); + vty_out(vty, "%s\n", + bgp_attr_get_ecommunity(attr)->str); } } @@ -9520,10 +9543,10 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p, else json_object_string_add(json_overlay, "gw", buf); - if (attr->ecommunity) { + if (bgp_attr_get_ecommunity(attr)) { char *mac = NULL; struct ecommunity_val *routermac = ecommunity_lookup( - attr->ecommunity, ECOMMUNITY_ENCODE_EVPN, + bgp_attr_get_ecommunity(attr), ECOMMUNITY_ENCODE_EVPN, ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC); if (routermac) @@ -10481,14 +10504,16 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, /* Line 4 display Community */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { if (json_paths) { - if (!attr->community->json) - community_str(attr->community, true); - json_object_lock(attr->community->json); - json_object_object_add(json_path, "community", - attr->community->json); + if (!bgp_attr_get_community(attr)->json) + community_str(bgp_attr_get_community(attr), + true); + json_object_lock(bgp_attr_get_community(attr)->json); + json_object_object_add( + json_path, "community", + bgp_attr_get_community(attr)->json); } else { vty_out(vty, " Community: %s\n", - attr->community->str); + bgp_attr_get_community(attr)->str); } } @@ -10496,27 +10521,30 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { if (json_paths) { json_ext_community = json_object_new_object(); - json_object_string_add(json_ext_community, "string", - attr->ecommunity->str); + json_object_string_add( + json_ext_community, "string", + bgp_attr_get_ecommunity(attr)->str); json_object_object_add(json_path, "extendedCommunity", json_ext_community); } else { vty_out(vty, " Extended Community: %s\n", - attr->ecommunity->str); + bgp_attr_get_ecommunity(attr)->str); } } /* Line 6 display Large community */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { if (json_paths) { - if (!attr->lcommunity->json) - lcommunity_str(attr->lcommunity, true); - json_object_lock(attr->lcommunity->json); - json_object_object_add(json_path, "largeCommunity", - attr->lcommunity->json); + if (!bgp_attr_get_lcommunity(attr)->json) + lcommunity_str(bgp_attr_get_lcommunity(attr), + true); + json_object_lock(bgp_attr_get_lcommunity(attr)->json); + json_object_object_add( + json_path, "largeCommunity", + bgp_attr_get_lcommunity(attr)->json); } else { vty_out(vty, " Large Community: %s\n", - attr->lcommunity->str); + bgp_attr_get_lcommunity(attr)->str); } } @@ -10730,8 +10758,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, gr_remaining); } - if (path->peer->t_llgr_stale[afi][safi] && attr->community && - community_include(attr->community, COMMUNITY_LLGR_STALE)) { + if (path->peer->t_llgr_stale[afi][safi] && + bgp_attr_get_community(attr) && + community_include(bgp_attr_get_community(attr), + COMMUNITY_LLGR_STALE)) { unsigned long llgr_remaining = thread_timer_remain_second( path->peer->t_llgr_stale[afi][safi]); @@ -10869,6 +10899,10 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, json_paths = NULL; for (; pi; pi = pi->next) { + struct community *picomm = NULL; + + picomm = bgp_attr_get_community(pi->attr); + total_count++; if (type == bgp_show_type_prefix_version) { @@ -10884,9 +10918,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, int num; bool found = false; - if (pi->attr->community) { - frrstr_split(pi->attr->community->str, - " ", &communities, &num); + if (picomm) { + frrstr_split(picomm->str, " ", + &communities, &num); for (int i = 0; i < num; i++) { const char *com2alias = bgp_community2alias( @@ -10901,8 +10935,11 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, XFREE(MTYPE_TMP, communities); } - if (!found && pi->attr->lcommunity) { - frrstr_split(pi->attr->lcommunity->str, + if (!found && + bgp_attr_get_lcommunity(pi->attr)) { + frrstr_split(bgp_attr_get_lcommunity( + pi->attr) + ->str, " ", &communities, &num); for (int i = 0; i < num; i++) { const char *com2alias = @@ -11007,60 +11044,58 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, continue; } if (type == bgp_show_type_community_all) { - if (!pi->attr->community) + if (!picomm) continue; } if (type == bgp_show_type_community) { struct community *com = output_arg; - if (!pi->attr->community - || !community_match(pi->attr->community, - com)) + if (!picomm || !community_match(picomm, com)) continue; } if (type == bgp_show_type_community_exact) { struct community *com = output_arg; - if (!pi->attr->community - || !community_cmp(pi->attr->community, com)) + if (!picomm || !community_cmp(picomm, com)) continue; } if (type == bgp_show_type_community_list) { struct community_list *list = output_arg; - if (!community_list_match(pi->attr->community, - list)) + if (!community_list_match(picomm, list)) continue; } if (type == bgp_show_type_community_list_exact) { struct community_list *list = output_arg; - if (!community_list_exact_match( - pi->attr->community, list)) + if (!community_list_exact_match(picomm, list)) continue; } if (type == bgp_show_type_lcommunity) { struct lcommunity *lcom = output_arg; - if (!pi->attr->lcommunity - || !lcommunity_match(pi->attr->lcommunity, - lcom)) + if (!bgp_attr_get_lcommunity(pi->attr) || + !lcommunity_match( + bgp_attr_get_lcommunity(pi->attr), + lcom)) continue; } if (type == bgp_show_type_lcommunity_exact) { struct lcommunity *lcom = output_arg; - if (!pi->attr->lcommunity - || !lcommunity_cmp(pi->attr->lcommunity, - lcom)) + if (!bgp_attr_get_lcommunity(pi->attr) || + !lcommunity_cmp( + bgp_attr_get_lcommunity(pi->attr), + lcom)) continue; } if (type == bgp_show_type_lcommunity_list) { struct community_list *list = output_arg; - if (!lcommunity_list_match(pi->attr->lcommunity, - list)) + if (!lcommunity_list_match( + bgp_attr_get_lcommunity(pi->attr), + list)) continue; } if (type @@ -11068,11 +11103,12 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, struct community_list *list = output_arg; if (!lcommunity_list_exact_match( - pi->attr->lcommunity, list)) + bgp_attr_get_lcommunity(pi->attr), + list)) continue; } if (type == bgp_show_type_lcommunity_all) { - if (!pi->attr->lcommunity) + if (!bgp_attr_get_lcommunity(pi->attr)) continue; } if (type == bgp_show_type_dampend_paths @@ -11450,44 +11486,43 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, vty_out(vty, "not allocated\n"); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + struct community *picomm = NULL; + + picomm = bgp_attr_get_community(pi->attr); + count++; if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) { best = count; if (bgp_path_suppressed(pi)) suppress = 1; - if (pi->attr->community == NULL) + if (!picomm) continue; no_advertise += community_include( - pi->attr->community, COMMUNITY_NO_ADVERTISE); - no_export += community_include(pi->attr->community, - COMMUNITY_NO_EXPORT); - local_as += community_include(pi->attr->community, - COMMUNITY_LOCAL_AS); - accept_own += community_include(pi->attr->community, - COMMUNITY_ACCEPT_OWN); + picomm, COMMUNITY_NO_ADVERTISE); + no_export += + community_include(picomm, COMMUNITY_NO_EXPORT); + local_as += + community_include(picomm, COMMUNITY_LOCAL_AS); + accept_own += + community_include(picomm, COMMUNITY_ACCEPT_OWN); route_filter_translated_v4 += community_include( - pi->attr->community, - COMMUNITY_ROUTE_FILTER_TRANSLATED_v4); + picomm, COMMUNITY_ROUTE_FILTER_TRANSLATED_v4); route_filter_translated_v6 += community_include( - pi->attr->community, - COMMUNITY_ROUTE_FILTER_TRANSLATED_v6); + picomm, COMMUNITY_ROUTE_FILTER_TRANSLATED_v6); route_filter_v4 += community_include( - pi->attr->community, COMMUNITY_ROUTE_FILTER_v4); + picomm, COMMUNITY_ROUTE_FILTER_v4); route_filter_v6 += community_include( - pi->attr->community, COMMUNITY_ROUTE_FILTER_v6); - llgr_stale += community_include(pi->attr->community, - COMMUNITY_LLGR_STALE); - no_llgr += community_include(pi->attr->community, - COMMUNITY_NO_LLGR); - accept_own_nexthop += - community_include(pi->attr->community, - COMMUNITY_ACCEPT_OWN_NEXTHOP); - blackhole += community_include(pi->attr->community, - COMMUNITY_BLACKHOLE); - no_peer += community_include(pi->attr->community, - COMMUNITY_NO_PEER); + picomm, COMMUNITY_ROUTE_FILTER_v6); + llgr_stale += + community_include(picomm, COMMUNITY_LLGR_STALE); + no_llgr += community_include(picomm, COMMUNITY_NO_LLGR); + accept_own_nexthop += community_include( + picomm, COMMUNITY_ACCEPT_OWN_NEXTHOP); + blackhole += + community_include(picomm, COMMUNITY_BLACKHOLE); + no_peer += community_include(picomm, COMMUNITY_NO_PEER); } } @@ -12254,6 +12289,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, bool first = true; uint16_t show_flags = 0; enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED; + struct prefix p; if (uj) { argc--; @@ -12406,7 +12442,6 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, if (argv_find(argv, argc, "A.B.C.D/M", &idx) || argv_find(argv, argc, "X:X::X:X/M", &idx)) { const char *prefix_str = argv[idx]->arg; - struct prefix p; if (!str2prefix(prefix_str, &p)) { vty_out(vty, "%% Malformed Prefix\n"); @@ -12814,7 +12849,7 @@ static void bgp_table_stats_rn(struct bgp_dest *dest, struct bgp_dest *top, } } -static int bgp_table_stats_walker(struct thread *t) +static void bgp_table_stats_walker(struct thread *t) { struct bgp_dest *dest, *ndest; struct bgp_dest *top; @@ -12822,7 +12857,7 @@ static int bgp_table_stats_walker(struct thread *t) unsigned int space = 0; if (!(top = bgp_table_top(ts->table))) - return 0; + return; switch (ts->table->afi) { case AFI_IP: @@ -12835,7 +12870,7 @@ static int bgp_table_stats_walker(struct thread *t) space = EVPN_ROUTE_PREFIXLEN; break; default: - return 0; + return; } ts->counts[BGP_STATS_MAXBITLEN] = space; @@ -12858,8 +12893,6 @@ static int bgp_table_stats_walker(struct thread *t) bgp_table_stats_rn(dest, top, ts, space); } } - - return 0; } static void bgp_table_stats_all(struct vty *vty, afi_t afi, safi_t safi, @@ -13177,7 +13210,7 @@ static void bgp_peer_count_proc(struct bgp_dest *rn, struct peer_pcounts *pc) } } -static int bgp_peer_count_walker(struct thread *t) +static void bgp_peer_count_walker(struct thread *t) { struct bgp_dest *rn, *rm; const struct bgp_table *table; @@ -13197,8 +13230,6 @@ static int bgp_peer_count_walker(struct thread *t) } else for (rn = bgp_table_top(pc->table); rn; rn = bgp_route_next(rn)) bgp_peer_count_proc(rn, pc); - - return 0; } static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi, @@ -13586,7 +13617,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (type == bgp_show_adj_route_filtered && !route_filtered && ret != RMAP_DENY) { - bgp_attr_undup(&attr, ain->attr); + bgp_attr_flush(&attr); continue; } @@ -13596,7 +13627,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, route_vty_out_tmp(vty, dest, rn_p, &attr, safi, use_json, json_ar, wide); - bgp_attr_undup(&attr, ain->attr); + bgp_attr_flush(&attr); (*output_count)++; } } else if (type == bgp_show_adj_route_advertised) { @@ -13644,7 +13675,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, (*filtered_count)++; } - bgp_attr_undup(&attr, adj->attr); + bgp_attr_flush(&attr); } } else if (type == bgp_show_adj_route_bestpath) { struct bgp_path_info *pi; @@ -14135,7 +14166,7 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed, struct bgp *bgp = NULL; int idx = 0; bool uj = use_json(argc, argv); - uint16_t show_flags = 0; + uint16_t show_flags = BGP_SHOW_OPT_DETAIL; if (uj) { argc--; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 317995594..743b369bf 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -154,6 +154,8 @@ struct bgp_sid_info { uint8_t loc_node_len; uint8_t func_len; uint8_t arg_len; + uint8_t transposition_len; + uint8_t transposition_offset; }; /* Ancillary information to struct bgp_path_info, @@ -785,7 +787,7 @@ extern bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, struct update_subgroup *subgrp, const struct prefix *p, struct attr *attr, - bool skip_rmap_check); + struct attr *post_attr); extern void bgp_peer_clear_node_queue_drain_immediate(struct peer *peer); extern void bgp_process_queues_drain_immediate(void); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index c42e3c9b9..6fcc083e3 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1039,10 +1039,14 @@ static void *route_match_evpn_route_type_compile(const char *arg) route_type = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t)); - if (strncmp(arg, "ma", 2) == 0) + if (strncmp(arg, "ea", 2) == 0) + *route_type = BGP_EVPN_AD_ROUTE; + else if (strncmp(arg, "ma", 2) == 0) *route_type = BGP_EVPN_MAC_IP_ROUTE; else if (strncmp(arg, "mu", 2) == 0) *route_type = BGP_EVPN_IMET_ROUTE; + else if (strncmp(arg, "es", 2) == 0) + *route_type = BGP_EVPN_ES_ROUTE; else *route_type = BGP_EVPN_IP_PREFIX_ROUTE; @@ -1242,10 +1246,10 @@ route_match_alias(void *rule, const struct prefix *prefix, void *object) int num; bool found; - if (path->attr->community) { + if (bgp_attr_get_community(path->attr)) { found = false; - frrstr_split(path->attr->community->str, " ", &communities, - &num); + frrstr_split(bgp_attr_get_community(path->attr)->str, " ", + &communities, &num); for (int i = 0; i < num; i++) { const char *com2alias = bgp_community2alias(communities[i]); @@ -1258,10 +1262,10 @@ route_match_alias(void *rule, const struct prefix *prefix, void *object) return RMAP_MATCH; } - if (path->attr->lcommunity) { + if (bgp_attr_get_lcommunity(path->attr)) { found = false; - frrstr_split(path->attr->lcommunity->str, " ", &communities, - &num); + frrstr_split(bgp_attr_get_lcommunity(path->attr)->str, " ", + &communities, &num); for (int i = 0; i < num; i++) { const char *com2alias = bgp_community2alias(communities[i]); @@ -1437,10 +1441,12 @@ route_match_community(void *rule, const struct prefix *prefix, void *object) return RMAP_NOMATCH; if (rcom->exact) { - if (community_list_exact_match(path->attr->community, list)) + if (community_list_exact_match( + bgp_attr_get_community(path->attr), list)) return RMAP_MATCH; } else { - if (community_list_match(path->attr->community, list)) + if (community_list_match(bgp_attr_get_community(path->attr), + list)) return RMAP_MATCH; } @@ -1521,10 +1527,12 @@ route_match_lcommunity(void *rule, const struct prefix *prefix, void *object) return RMAP_NOMATCH; if (rcom->exact) { - if (lcommunity_list_exact_match(path->attr->lcommunity, list)) + if (lcommunity_list_exact_match( + bgp_attr_get_lcommunity(path->attr), list)) return RMAP_MATCH; } else { - if (lcommunity_list_match(path->attr->lcommunity, list)) + if (lcommunity_list_match(bgp_attr_get_lcommunity(path->attr), + list)) return RMAP_MATCH; } @@ -1589,7 +1597,7 @@ route_match_ecommunity(void *rule, const struct prefix *prefix, void *object) if (!list) return RMAP_NOMATCH; - if (ecommunity_list_match(path->attr->ecommunity, list)) + if (ecommunity_list_match(bgp_attr_get_ecommunity(path->attr), list)) return RMAP_MATCH; return RMAP_NOMATCH; @@ -2187,12 +2195,12 @@ route_set_community(void *rule, const struct prefix *prefix, void *object) rcs = rule; path = object; attr = path->attr; - old = attr->community; + old = bgp_attr_get_community(attr); /* "none" case. */ if (rcs->none) { attr->flag &= ~(ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)); - attr->community = NULL; + bgp_attr_set_community(attr, NULL); /* See the longer comment down below. */ if (old && old->refcnt == 0) community_free(&old); @@ -2217,7 +2225,7 @@ route_set_community(void *rule, const struct prefix *prefix, void *object) community_free(&old); /* will be interned by caller if required */ - attr->community = new; + bgp_attr_set_community(attr, new); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); @@ -2301,12 +2309,12 @@ route_set_lcommunity(void *rule, const struct prefix *prefix, void *object) rcs = rule; path = object; attr = path->attr; - old = attr->lcommunity; + old = bgp_attr_get_lcommunity(attr); /* "none" case. */ if (rcs->none) { attr->flag &= ~(ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)); - attr->lcommunity = NULL; + bgp_attr_set_lcommunity(attr, NULL); /* See the longer comment down below. */ if (old && old->refcnt == 0) @@ -2331,7 +2339,7 @@ route_set_lcommunity(void *rule, const struct prefix *prefix, void *object) lcommunity_free(&old); /* will be intern()'d or attr_flush()'d by bgp_update_main() */ - attr->lcommunity = new; + bgp_attr_set_lcommunity(attr, new); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES); @@ -2413,7 +2421,7 @@ route_set_lcommunity_delete(void *rule, const struct prefix *pfx, void *object) path = object; list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash, LARGE_COMMUNITY_LIST_MASTER); - old = path->attr->lcommunity; + old = bgp_attr_get_lcommunity(path->attr); if (list && old) { merge = lcommunity_list_match_delete(lcommunity_dup(old), list); @@ -2429,12 +2437,12 @@ route_set_lcommunity_delete(void *rule, const struct prefix *pfx, void *object) lcommunity_free(&old); if (new->size == 0) { - path->attr->lcommunity = NULL; + bgp_attr_set_lcommunity(path->attr, NULL); path->attr->flag &= ~ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES); lcommunity_free(&new); } else { - path->attr->lcommunity = new; + bgp_attr_set_lcommunity(path->attr, new); path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES); } @@ -2501,7 +2509,7 @@ route_set_community_delete(void *rule, const struct prefix *prefix, path = object; list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash, COMMUNITY_LIST_MASTER); - old = path->attr->community; + old = bgp_attr_get_community(path->attr); if (list && old) { merge = community_list_match_delete(community_dup(old), list); @@ -2517,12 +2525,12 @@ route_set_community_delete(void *rule, const struct prefix *prefix, community_free(&old); if (new->size == 0) { - path->attr->community = NULL; + bgp_attr_set_community(path->attr, NULL); path->attr->flag &= ~ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); community_free(&new); } else { - path->attr->community = new; + bgp_attr_set_community(path->attr, new); path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); } } @@ -2590,7 +2598,7 @@ route_set_ecommunity(void *rule, const struct prefix *prefix, void *object) if (rcs->none) { attr->flag &= ~(ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)); - attr->ecommunity = NULL; + bgp_attr_set_ecommunity(attr, NULL); return RMAP_OKAY; } @@ -2598,7 +2606,7 @@ route_set_ecommunity(void *rule, const struct prefix *prefix, void *object) return RMAP_OKAY; /* We assume additive for Extended Community. */ - old_ecom = path->attr->ecommunity; + old_ecom = bgp_attr_get_ecommunity(path->attr); if (old_ecom) { new_ecom = @@ -2614,7 +2622,7 @@ route_set_ecommunity(void *rule, const struct prefix *prefix, void *object) new_ecom = ecommunity_dup(rcs->ecom); /* will be intern()'d or attr_flush()'d by bgp_update_main() */ - path->attr->ecommunity = new_ecom; + bgp_attr_set_ecommunity(path->attr, new_ecom); path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); @@ -2764,7 +2772,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); /* add to route or merge with existing */ - old_ecom = path->attr->ecommunity; + old_ecom = bgp_attr_get_ecommunity(path->attr); if (old_ecom) { new_ecom = ecommunity_dup(old_ecom); ecommunity_add_val(new_ecom, &lb_eval, true, true); @@ -2778,7 +2786,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) } /* new_ecom will be intern()'d or attr_flush()'d in call stack */ - path->attr->ecommunity = new_ecom; + bgp_attr_set_ecommunity(path->attr, new_ecom); path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); /* Mark that route-map has set link bandwidth; used in attribute @@ -4036,13 +4044,11 @@ static void bgp_route_map_process_update_cb(char *rmap_name) vpn_policy_routemap_event(rmap_name); } -int bgp_route_map_update_timer(struct thread *thread) +void bgp_route_map_update_timer(struct thread *thread) { bm->t_rmap_update = NULL; route_map_walk_update_list(bgp_route_map_process_update_cb); - - return 0; } static void bgp_route_map_mark_update(const char *rmap_name) @@ -4165,14 +4171,18 @@ static const char *parse_evpn_rt_type(const char *num_rt_type) DEFUN_YANG (match_evpn_route_type, match_evpn_route_type_cmd, - "match evpn route-type ", + "match evpn route-type ", MATCH_STR EVPN_HELP_STR EVPN_TYPE_HELP_STR + EVPN_TYPE_1_HELP_STR + EVPN_TYPE_1_HELP_STR EVPN_TYPE_2_HELP_STR EVPN_TYPE_2_HELP_STR EVPN_TYPE_3_HELP_STR EVPN_TYPE_3_HELP_STR + EVPN_TYPE_4_HELP_STR + EVPN_TYPE_4_HELP_STR EVPN_TYPE_5_HELP_STR EVPN_TYPE_5_HELP_STR) { @@ -4192,15 +4202,19 @@ DEFUN_YANG (match_evpn_route_type, DEFUN_YANG (no_match_evpn_route_type, no_match_evpn_route_type_cmd, - "no match evpn route-type ", + "no match evpn route-type ", NO_STR MATCH_STR EVPN_HELP_STR EVPN_TYPE_HELP_STR + EVPN_TYPE_1_HELP_STR + EVPN_TYPE_1_HELP_STR EVPN_TYPE_2_HELP_STR EVPN_TYPE_2_HELP_STR EVPN_TYPE_3_HELP_STR EVPN_TYPE_3_HELP_STR + EVPN_TYPE_4_HELP_STR + EVPN_TYPE_4_HELP_STR EVPN_TYPE_5_HELP_STR EVPN_TYPE_5_HELP_STR) { diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index e5027359e..c724b938d 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -357,7 +357,7 @@ static struct prefix *pfx_record_to_prefix(struct pfx_record *record) return prefix; } -static int bgpd_sync_callback(struct thread *thread) +static void bgpd_sync_callback(struct thread *thread) { struct bgp *bgp; struct listnode *node; @@ -369,19 +369,19 @@ static int bgpd_sync_callback(struct thread *thread) thread_add_read(bm->master, bgpd_sync_callback, NULL, socket, &t_rpki); if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) { - while (read(socket, &rec, sizeof(rec) != -1)) + while (read(socket, &rec, sizeof(struct pfx_record)) != -1) ; atomic_store_explicit(&rtr_update_overflow, 0, memory_order_seq_cst); revalidate_all_routes(); - return 0; + return; } - retval = read(socket, &rec, sizeof(rec)); - if (retval != sizeof(rec)) { + retval = read(socket, &rec, sizeof(struct pfx_record)); + if (retval != sizeof(struct pfx_record)) { RPKI_DEBUG("Could not read from socket"); - return retval; + return; } /* RTR-Server crashed/terminated, let's handle and switch @@ -389,7 +389,7 @@ static int bgpd_sync_callback(struct thread *thread) */ if (rec.socket && rec.socket->state == RTR_ERROR_FATAL) { reset(true); - return 0; + return; } prefix = pfx_record_to_prefix(&rec); @@ -421,7 +421,6 @@ static int bgpd_sync_callback(struct thread *thread) } prefix_free(&prefix); - return 0; } static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, @@ -1262,7 +1261,7 @@ DEFPY (show_rpki_prefix, if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count, asn, &addr, prefix->prefixlen, &result) != PFX_SUCCESS) { - vty_out(vty, "Prefix lookup failed"); + vty_out(vty, "Prefix lookup failed\n"); return CMD_WARNING; } diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index bfcb4810d..aa3e44318 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -1157,7 +1157,7 @@ bool update_subgroup_check_merge(struct update_subgroup *subgrp, /* * update_subgroup_merge_check_thread_cb */ -static int update_subgroup_merge_check_thread_cb(struct thread *thread) +static void update_subgroup_merge_check_thread_cb(struct thread *thread) { struct update_subgroup *subgrp; @@ -1166,7 +1166,6 @@ static int update_subgroup_merge_check_thread_cb(struct thread *thread) subgrp->t_merge_check = NULL; update_subgroup_check_merge(subgrp, "triggered merge check"); - return 0; } /* @@ -1803,7 +1802,7 @@ update_group_default_originate_route_map_walkcb(struct update_group *updgrp, return UPDWALK_CONTINUE; } -int update_group_refresh_default_originate_route_map(struct thread *thread) +void update_group_refresh_default_originate_route_map(struct thread *thread) { struct bgp *bgp; char reason[] = "refresh default-originate route-map"; @@ -1813,8 +1812,6 @@ int update_group_refresh_default_originate_route_map(struct thread *thread) reason); thread_cancel(&bgp->t_rmap_def_originate_eval); bgp_unlock(bgp); - - return 0; } /* diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index 5a9bebf8f..0e10341bc 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -375,7 +375,7 @@ extern void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi, updgrp_walkcb cb, void *ctx); extern void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx); extern void update_group_periodic_merge(struct bgp *bgp); -extern int +extern void update_group_refresh_default_originate_route_map(struct thread *thread); extern void update_group_start_advtimer(struct bgp *bgp); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 2110dcb8b..0d8ee79ae 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -316,7 +316,7 @@ static void updgrp_show_adj(struct bgp *bgp, afi_t afi, safi_t safi, update_group_af_walk(bgp, afi, safi, updgrp_show_adj_walkcb, &ctx); } -static int subgroup_coalesce_timer(struct thread *thread) +static void subgroup_coalesce_timer(struct thread *thread) { struct update_subgroup *subgrp; struct bgp *bgp; @@ -351,8 +351,6 @@ static int subgroup_coalesce_timer(struct thread *thread) BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); } } - - return 0; } static int update_group_announce_walkcb(struct update_group *updgrp, void *arg) @@ -691,7 +689,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp, safi)) { if (subgroup_announce_check(dest, ri, subgrp, dest_p, &attr, - false)) { + NULL)) { /* Check if route can be advertised */ if (advertise) { if (!bgp_check_withdrawal(bgp, @@ -859,7 +857,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) bgp_dest_get_prefix(dest), pi, &tmp_pi); if (ret == RMAP_DENYMATCH) { - bgp_attr_undup(&tmp_attr, &attr); + bgp_attr_flush(&tmp_attr); continue; } else { new_attr = bgp_attr_intern(&tmp_attr); @@ -910,7 +908,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) if (subgroup_announce_check( dest, pi, subgrp, bgp_dest_get_prefix(dest), - &attr, false)) + &attr, NULL)) bgp_adj_out_set_subgroup( dest, subgrp, &attr, pi); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 72b604930..d21e257cb 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -687,10 +687,10 @@ static bool peer_address_self_check(struct bgp *bgp, union sockunion *su) union sockunion all_su; if (su->sa.sa_family == AF_INET) { - str2sockunion("0.0.0.0", &all_su); + (void)str2sockunion("0.0.0.0", &all_su); ifp = if_lookup_by_ipv4_exact(&su->sin.sin_addr, bgp->vrf_id); } else if (su->sa.sa_family == AF_INET6) { - str2sockunion("::", &all_su); + (void)str2sockunion("::", &all_su); ifp = if_lookup_by_ipv6_exact(&su->sin6.sin6_addr, su->sin6.sin6_scope_id, bgp->vrf_id); @@ -803,11 +803,15 @@ struct peer *peer_and_group_lookup_vty(struct vty *vty, const char *peer_str) return NULL; } -int bgp_vty_return(struct vty *vty, int ret) +int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret) { const char *str = NULL; switch (ret) { + case BGP_SUCCESS: + case BGP_CREATED: + case BGP_GR_NO_OPERATION: + break; case BGP_ERR_INVALID_VALUE: str = "Invalid value"; break; @@ -877,6 +881,36 @@ int bgp_vty_return(struct vty *vty, int ret) case BGP_ERR_GR_OPERATION_FAILED: str = "The Graceful Restart Operation failed due to an err."; break; + case BGP_ERR_PEER_GROUP_MEMBER: + str = "Peer-group member cannot override remote-as of peer-group."; + break; + case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: + str = "Peer-group members must be all internal or all external."; + break; + case BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND: + str = "Range specified cannot be deleted because it is not part of current config."; + break; + case BGP_ERR_INSTANCE_MISMATCH: + str = "Instance specified does not match the current instance."; + break; + case BGP_ERR_NO_INTERFACE_CONFIG: + str = "Interface specified is not being used for interface based peer."; + break; + case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED: + str = "No configuration already specified for soft reconfiguration."; + break; + case BGP_ERR_AS_MISMATCH: + str = "BGP is already running."; + break; + case BGP_ERR_AF_UNCONFIGURED: + str = "AFI/SAFI specified is not currently configured."; + break; + case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS: + str = "AS specified for local as is the same as the remote as and this is not allowed."; + break; + case BGP_ERR_INVALID_AS: + str = "Confederation AS specified is the same AS as our AS."; + break; } if (str) { vty_out(vty, "%% %s\n", str); @@ -4211,17 +4245,6 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, ret = peer_remote_as(bgp, &su, NULL, &as, as_type); } - /* This peer belongs to peer group. */ - switch (ret) { - case BGP_ERR_PEER_GROUP_MEMBER: - vty_out(vty, - "%% Peer-group member cannot override remote-as of peer-group\n"); - return CMD_WARNING_CONFIG_FAILED; - case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: - vty_out(vty, - "%% Peer-group members must be all internal or all external\n"); - return CMD_WARNING_CONFIG_FAILED; - } return bgp_vty_return(vty, ret); } @@ -4958,13 +4981,6 @@ DEFUN (neighbor_set_peer_group, ret = peer_group_bind(bgp, &su, peer, group, &as); - if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) { - vty_out(vty, - "%% Peer with AS %u cannot be in this peer-group, members must be all internal or all external\n", - as); - return CMD_WARNING_CONFIG_FAILED; - } - return bgp_vty_return(vty, ret); } @@ -8550,7 +8566,7 @@ DEFPY (af_sid_vpn_export, if (!yes) { /* implement me */ - vty_out(vty, "It's not implemented"); + vty_out(vty, "It's not implemented\n"); return CMD_WARNING_CONFIG_FAILED; } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index e028a7e8d..78eaac780 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -882,6 +882,12 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, */ if (!v6_ll_avail && if_is_loopback(ifp)) v6_ll_avail = true; + else { + flog_warn( + EC_BGP_NO_LL_ADDRESS_AVAILABLE, + "Interface: %s does not have a v6 LL address associated with it, waiting until one is created for it", + ifp->name); + } } else /* Link-local address. */ { @@ -1019,7 +1025,7 @@ static bool bgp_tm_chunk_obtained; static uint32_t bgp_tm_min, bgp_tm_max, bgp_tm_chunk_size; struct bgp *bgp_tm_bgp; -static int bgp_zebra_tm_connect(struct thread *t) +static void bgp_zebra_tm_connect(struct thread *t) { struct zclient *zclient; int delay = 10, ret = 0; @@ -1050,7 +1056,6 @@ static int bgp_zebra_tm_connect(struct thread *t) } thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay, &bgp_tm_thread_connect); - return 0; } bool bgp_zebra_tm_chunk_obtained(void) @@ -1261,6 +1266,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, struct bgp_path_info *mpinfo_cp = &local_info; route_tag_t tag; mpls_label_t label; + struct bgp_sid_info *sid_info; int nh_othervrf = 0; bool is_evpn; bool nh_updated = false; @@ -1477,9 +1483,22 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid) && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0].sid, + sid_info = &mpinfo->extra->sid[0]; + + memcpy(&api_nh->seg6_segs, &sid_info->sid, sizeof(api_nh->seg6_segs)); + if (sid_info->transposition_len != 0) { + if (!bgp_is_valid_label( + &mpinfo->extra->label[0])) + continue; + + label = label_pton(&mpinfo->extra->label[0]); + transpose_sid(&api_nh->seg6_segs, label, + sid_info->transposition_offset, + sid_info->transposition_len); + } + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); } @@ -1497,12 +1516,14 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, sizeof(bzo.aspath)); if (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) - strlcpy(bzo.community, info->attr->community->str, + strlcpy(bzo.community, + bgp_attr_get_community(info->attr)->str, sizeof(bzo.community)); if (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) - strlcpy(bzo.lcommunity, info->attr->lcommunity->str, + strlcpy(bzo.lcommunity, + bgp_attr_get_lcommunity(info->attr)->str, sizeof(bzo.lcommunity)); strlcpy(bzo.selection_reason, reason, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e6d4000ad..38a106359 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -651,9 +651,6 @@ int bgp_confederation_peers_add(struct bgp *bgp, as_t as) struct peer *peer; struct listnode *node, *nnode; - if (!bgp) - return BGP_ERR_INVALID_BGP; - if (bgp->as == as) return BGP_ERR_INVALID_AS; @@ -1226,7 +1223,7 @@ int bgp_global_gr_init(struct bgp *bgp) { /*Event -> */ /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/ - GLOBAL_INVALID, GLOBAL_HELPER, + GLOBAL_GR, GLOBAL_HELPER, /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/ GLOBAL_DISABLE, GLOBAL_INVALID }, @@ -3047,14 +3044,12 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, return 0; } -static int bgp_startup_timer_expire(struct thread *thread) +static void bgp_startup_timer_expire(struct thread *thread) { struct bgp *bgp; bgp = THREAD_ARG(thread); bgp->t_startup = NULL; - - return 0; } /* @@ -3239,6 +3234,10 @@ static struct bgp *bgp_create(as_t *as, const char *name, /*initilize global GR FSM */ bgp_global_gr_init(bgp); + + memset(&bgp->ebgprequirespolicywarning, 0, + sizeof(bgp->ebgprequirespolicywarning)); + return bgp; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index ae6427b35..a9475f39a 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -234,6 +234,7 @@ struct vpn_policy { */ uint32_t tovpn_sid_index; /* unset => set to 0 */ struct in6_addr *tovpn_sid; + struct in6_addr *tovpn_sid_locator; uint32_t tovpn_sid_transpose_label; struct in6_addr *tovpn_zebra_vrf_sid_last_sent; }; @@ -759,6 +760,9 @@ struct bgp { struct list *srv6_locator_chunks; struct list *srv6_functions; + struct timeval ebgprequirespolicywarning; +#define FIFTEENMINUTE2USEC (int64_t)15 * 60 * 1000000 + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp); @@ -1916,46 +1920,46 @@ enum bgp_clear_type { (((S) == OpenSent) || ((S) == OpenConfirm) || ((S) == Established)) /* BGP error codes. */ -#define BGP_SUCCESS 0 -#define BGP_CREATED 1 -#define BGP_ERR_INVALID_VALUE -1 -#define BGP_ERR_INVALID_FLAG -2 -#define BGP_ERR_INVALID_AS -3 -#define BGP_ERR_INVALID_BGP -4 -#define BGP_ERR_PEER_GROUP_MEMBER -5 -#define BGP_ERR_PEER_GROUP_NO_REMOTE_AS -7 -#define BGP_ERR_PEER_GROUP_CANT_CHANGE -8 -#define BGP_ERR_PEER_GROUP_MISMATCH -9 -#define BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT -10 -#define BGP_ERR_AS_MISMATCH -12 -#define BGP_ERR_PEER_FLAG_CONFLICT -13 -#define BGP_ERR_PEER_GROUP_SHUTDOWN -14 -#define BGP_ERR_PEER_FILTER_CONFLICT -15 -#define BGP_ERR_NOT_INTERNAL_PEER -16 -#define BGP_ERR_REMOVE_PRIVATE_AS -17 -#define BGP_ERR_AF_UNCONFIGURED -18 -#define BGP_ERR_SOFT_RECONFIG_UNCONFIGURED -19 -#define BGP_ERR_INSTANCE_MISMATCH -20 -#define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP -21 -#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS -22 -#define BGP_ERR_TCPSIG_FAILED -23 -#define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -24 -#define BGP_ERR_NO_IBGP_WITH_TTLHACK -25 -#define BGP_ERR_NO_INTERFACE_CONFIG -26 -#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -27 -#define BGP_ERR_AS_OVERRIDE -28 -#define BGP_ERR_INVALID_DYNAMIC_NEIGHBORS_LIMIT -29 -#define BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS -30 -#define BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND -31 -#define BGP_ERR_INVALID_FOR_DYNAMIC_PEER -32 -#define BGP_ERR_MAX -33 -#define BGP_ERR_INVALID_FOR_DIRECT_PEER -34 -#define BGP_ERR_PEER_SAFI_CONFLICT -35 - -/* BGP GR ERRORS */ -#define BGP_ERR_GR_INVALID_CMD -36 -#define BGP_ERR_GR_OPERATION_FAILED -37 -#define BGP_GR_NO_OPERATION -38 +enum bgp_create_error_code { + BGP_SUCCESS = 0, + BGP_CREATED = 1, + BGP_ERR_INVALID_VALUE = -1, + BGP_ERR_INVALID_FLAG = -2, + BGP_ERR_INVALID_AS = -3, + BGP_ERR_PEER_GROUP_MEMBER = -4, + BGP_ERR_PEER_GROUP_NO_REMOTE_AS = -5, + BGP_ERR_PEER_GROUP_CANT_CHANGE = -6, + BGP_ERR_PEER_GROUP_MISMATCH = -7, + BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT = -8, + BGP_ERR_AS_MISMATCH = -9, + BGP_ERR_PEER_FLAG_CONFLICT = -10, + BGP_ERR_PEER_GROUP_SHUTDOWN = -11, + BGP_ERR_PEER_FILTER_CONFLICT = -12, + BGP_ERR_NOT_INTERNAL_PEER = -13, + BGP_ERR_REMOVE_PRIVATE_AS = -14, + BGP_ERR_AF_UNCONFIGURED = -15, + BGP_ERR_SOFT_RECONFIG_UNCONFIGURED = -16, + BGP_ERR_INSTANCE_MISMATCH = -17, + BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP = -18, + BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS = -19, + BGP_ERR_TCPSIG_FAILED = -20, + BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK = -21, + BGP_ERR_NO_IBGP_WITH_TTLHACK = -22, + BGP_ERR_NO_INTERFACE_CONFIG = -23, + BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS = -24, + BGP_ERR_AS_OVERRIDE = -25, + BGP_ERR_INVALID_DYNAMIC_NEIGHBORS_LIMIT = -26, + BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS = -27, + BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND = -28, + BGP_ERR_INVALID_FOR_DYNAMIC_PEER = -29, + BGP_ERR_INVALID_FOR_DIRECT_PEER = -30, + BGP_ERR_PEER_SAFI_CONFLICT = -31, + + /* BGP GR ERRORS */ + BGP_ERR_GR_INVALID_CMD = -32, + BGP_ERR_GR_OPERATION_FAILED = -33, + BGP_GR_NO_OPERATION = -34, +}; /* * Enumeration of different policy kinds a peer can be configured with. @@ -2223,7 +2227,7 @@ extern int peer_ttl_security_hops_unset(struct peer *); extern void peer_tx_shutdown_message_set(struct peer *, const char *msg); extern void peer_tx_shutdown_message_unset(struct peer *); -extern int bgp_route_map_update_timer(struct thread *thread); +extern void bgp_route_map_update_timer(struct thread *thread); extern void bgp_route_map_terminate(void); extern int peer_cmp(struct peer *p1, struct peer *p2); diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 8bed5156b..1c8497843 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -800,8 +800,8 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ */ - attr.ecommunity = ecommunity_new(); - assert(attr.ecommunity); + bgp_attr_set_ecommunity(&attr, ecommunity_new()); + assert(bgp_attr_get_ecommunity(&attr)); if (TunnelType != BGP_ENCAP_TYPE_MPLS && TunnelType != BGP_ENCAP_TYPE_RESERVED) { @@ -817,25 +817,28 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ beec.val[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP; beec.val[6] = ((TunnelType) >> 8) & 0xff; beec.val[7] = (TunnelType)&0xff; - ecommunity_add_val(attr.ecommunity, &beec, false, false); + ecommunity_add_val(bgp_attr_get_ecommunity(&attr), &beec, false, + false); } /* * Add extended community attributes to match rt export list */ if (rt_export_list) { - attr.ecommunity = - ecommunity_merge(attr.ecommunity, rt_export_list); + bgp_attr_set_ecommunity( + &attr, ecommunity_merge(bgp_attr_get_ecommunity(&attr), + rt_export_list)); } - if (attr.ecommunity->size) { + struct ecommunity *ecomm = bgp_attr_get_ecommunity(&attr); + + if (ecomm->size) { attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } else { - ecommunity_free(&attr.ecommunity); - attr.ecommunity = NULL; + ecommunity_free(&ecomm); + bgp_attr_set_ecommunity(&attr, NULL); } - vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__, - attr.ecommunity); + vnc_zlog_debug_verbose("%s: attr.ecommunity=%p", __func__, ecomm); /* diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 07aed045c..1d58c0331 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -388,7 +388,7 @@ int rfapiGetVncTunnelUnAddr(struct attr *attr, struct prefix *p) return 0; /* MPLS carries UN address in next hop */ rfapiNexthop2Prefix(attr, p); - if (p->family != 0) + if (p->family != AF_UNSPEC) return 0; return ENOENT; @@ -457,7 +457,7 @@ int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p) return 0; default: if (p) - p->family = 0; + p->family = AF_UNSPEC; #ifdef DEBUG_ENCAP_MONITOR vnc_zlog_debug_verbose( "%s: bpi->extra->vnc.import.un_family is 0, no UN addr", @@ -1155,7 +1155,7 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1, bpi1->extra->vnc.import.un.addr6; break; default: - pfx_un1.family = 0; + pfx_un1.family = AF_UNSPEC; break; } } @@ -1174,13 +1174,13 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1, bpi2->extra->vnc.import.un.addr6; break; default: - pfx_un2.family = 0; + pfx_un2.family = AF_UNSPEC; break; } } } - if (pfx_un1.family == 0 || pfx_un2.family == 0) + if (pfx_un1.family == AF_UNSPEC || pfx_un2.family == AF_UNSPEC) return 0; if (pfx_un1.family != pfx_un2.family) @@ -1292,10 +1292,11 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, memcpy(&vo->v.l2addr.macaddr, &p->u.prefix_eth.octet, ETH_ALEN); /* only low 3 bytes of this are significant */ - (void)rfapiEcommunityGetLNI(bpi->attr->ecommunity, + (void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr), &vo->v.l2addr.logical_net_id); - (void)rfapiEcommunityGetEthernetTag(bpi->attr->ecommunity, - &vo->v.l2addr.tag_id); + (void)rfapiEcommunityGetEthernetTag( + bgp_attr_get_ecommunity(bpi->attr), + &vo->v.l2addr.tag_id); /* local_nve_id comes from lower byte of RD type */ vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1]; @@ -1358,7 +1359,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, struct prefix p; /* MPLS carries UN address in next hop */ rfapiNexthop2Prefix(bpi->attr, &p); - if (p.family != 0) { + if (p.family != AF_UNSPEC) { rfapiQprefix2Raddr(&p, &new->un_address); have_vnc_tunnel_un = 1; } @@ -2371,7 +2372,7 @@ static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi) * quagga lib/thread.h says this must return int even though * it doesn't do anything with the return value */ -static int rfapiWithdrawTimerVPN(struct thread *t) +static void rfapiWithdrawTimerVPN(struct thread *t) { struct rfapi_withdraw *wcb = t->arg; struct bgp_path_info *bpi = wcb->info; @@ -2384,13 +2385,13 @@ static int rfapiWithdrawTimerVPN(struct thread *t) vnc_zlog_debug_verbose( "%s: NULL BGP pointer, assume shutdown race condition!!!", __func__); - return 0; + return; } if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { vnc_zlog_debug_verbose( "%s: BGP delete in progress, assume shutdown race condition!!!", __func__); - return 0; + return; } assert(wcb->node); assert(bpi); @@ -2502,7 +2503,6 @@ done: RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, 1 + wcb->lockoffset); agg_unlock_node(wcb->node); /* decr ref count */ XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - return 0; } /* @@ -2609,7 +2609,7 @@ static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi, default: zlog_warn("%s: invalid encap nexthop length: %d", __func__, encap_bpi->attr->mp_nexthop_len); - vpn_bpi->extra->vnc.import.un_family = 0; + vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC; break; } } @@ -2634,7 +2634,7 @@ rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table, __func__); return 1; } - vpn_bpi->extra->vnc.import.un_family = 0; + vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC; memset(&vpn_bpi->extra->vnc.import.un, 0, sizeof(vpn_bpi->extra->vnc.import.un)); if (CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) { @@ -2673,7 +2673,7 @@ rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table, return 0; } -static int rfapiWithdrawTimerEncap(struct thread *t) +static void rfapiWithdrawTimerEncap(struct thread *t) { struct rfapi_withdraw *wcb = t->arg; struct bgp_path_info *bpi = wcb->info; @@ -2747,7 +2747,6 @@ done: agg_unlock_node(wcb->node); /* decr ref count */ XFREE(MTYPE_RFAPI_WITHDRAW, wcb); skiplist_free(vpn_node_sl); - return 0; } @@ -2759,7 +2758,7 @@ static void rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table, struct agg_node *rn, struct bgp_path_info *bpi, afi_t afi, safi_t safi, - int (*timer_service_func)(struct thread *)) + void (*timer_service_func)(struct thread *)) { uint32_t lifetime; struct rfapi_withdraw *wcb; @@ -2946,7 +2945,7 @@ static void rfapiBgpInfoFilteredImportEncap( * On a withdraw, peer and RD are sufficient to determine if * we should act. */ - if (!attr || !attr->ecommunity) { + if (!attr || !bgp_attr_get_ecommunity(attr)) { vnc_zlog_debug_verbose( "%s: attr, extra, or ecommunity missing, not importing", @@ -2954,15 +2953,17 @@ static void rfapiBgpInfoFilteredImportEncap( return; } #ifdef RFAPI_REQUIRE_ENCAP_BEEC - if (!rfapiEcommunitiesMatchBeec(attr->ecommunity)) { + if (!rfapiEcommunitiesMatchBeec( + bgp_attr_get_ecommunity(attr))) { vnc_zlog_debug_verbose( "%s: it=%p: no match for BGP Encapsulation ecommunity", __func__, import_table); return; } #endif - if (!rfapiEcommunitiesIntersect(import_table->rt_import_list, - attr->ecommunity)) { + if (!rfapiEcommunitiesIntersect( + import_table->rt_import_list, + bgp_attr_get_ecommunity(attr))) { vnc_zlog_debug_verbose( "%s: it=%p: no ecommunity intersection", @@ -3407,16 +3408,17 @@ void rfapiBgpInfoFilteredImportVPN( * we should act. */ if (action == FIF_ACTION_UPDATE) { - if (!attr || !attr->ecommunity) { + if (!attr || !bgp_attr_get_ecommunity(attr)) { vnc_zlog_debug_verbose( "%s: attr, extra, or ecommunity missing, not importing", __func__); return; } - if ((import_table != bgp->rfapi->it_ce) - && !rfapiEcommunitiesIntersect(import_table->rt_import_list, - attr->ecommunity)) { + if ((import_table != bgp->rfapi->it_ce) && + !rfapiEcommunitiesIntersect( + import_table->rt_import_list, + bgp_attr_get_ecommunity(attr))) { vnc_zlog_debug_verbose( "%s: it=%p: no ecommunity intersection", @@ -3626,7 +3628,7 @@ void rfapiBgpInfoFilteredImportVPN( /* Not a big deal, just means VPN route got here first */ vnc_zlog_debug_verbose("%s: no encap route for vn addr %pFX", __func__, &vn_prefix); - info_new->extra->vnc.import.un_family = 0; + info_new->extra->vnc.import.un_family = AF_UNSPEC; } if (rn) { @@ -3891,7 +3893,7 @@ void rfapiProcessUpdate(struct peer *peer, * Find rt containing LNI (Logical Network ID), which * _should_ always be present when mac address is present */ - rc = rfapiEcommunityGetLNI(attr->ecommunity, &lni); + rc = rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(attr), &lni); vnc_zlog_debug_verbose( "%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p", @@ -4058,7 +4060,7 @@ static void rfapiProcessPeerDownRt(struct peer *peer, struct agg_node *rn; struct bgp_path_info *bpi; struct agg_table *rt; - int (*timer_service_func)(struct thread *); + void (*timer_service_func)(struct thread *); assert(afi == AFI_IP || afi == AFI_IP6); diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h index 50093111c..387e6c47c 100644 --- a/bgpd/rfapi/rfapi_import.h +++ b/bgpd/rfapi/rfapi_import.h @@ -126,8 +126,6 @@ extern void rfapiCheckRefcount(struct agg_node *rn, safi_t safi, extern int rfapiHasNonRemovedRoutes(struct agg_node *rn); -extern int rfapiProcessDeferredClose(struct thread *t); - extern int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p); extern void rfapiNexthop2Prefix(struct attr *attr, struct prefix *p); diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c index ce916c104..58a0f8dea 100644 --- a/bgpd/rfapi/rfapi_monitor.c +++ b/bgpd/rfapi/rfapi_monitor.c @@ -731,7 +731,7 @@ void rfapiMonitorResponseRemovalOn(struct bgp *bgp) bgp->rfapi_cfg->flags &= ~BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE; } -static int rfapiMonitorTimerExpire(struct thread *t) +static void rfapiMonitorTimerExpire(struct thread *t) { struct rfapi_monitor_vpn *m = t->arg; @@ -740,8 +740,6 @@ static int rfapiMonitorTimerExpire(struct thread *t) /* delete the monitor */ rfapiMonitorDel(bgp_get_default(), m->rfd, &m->p); - - return 0; } static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn *m) @@ -1041,7 +1039,7 @@ void rfapiMonitorMovedUp(struct rfapi_import_table *import_table, } } -static int rfapiMonitorEthTimerExpire(struct thread *t) +static void rfapiMonitorEthTimerExpire(struct thread *t) { struct rfapi_monitor_eth *m = t->arg; @@ -1052,7 +1050,6 @@ static int rfapiMonitorEthTimerExpire(struct thread *t) rfapiMonitorEthDel(bgp_get_default(), m->rfd, &m->macaddr, m->logical_net_id); - return 0; } static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth *m) diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index d1f335f54..ba0c576f1 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -291,7 +291,7 @@ struct rfapi_rib_tcb { /* * remove route from rib */ -static int rfapiRibExpireTimer(struct thread *t) +static void rfapiRibExpireTimer(struct thread *t) { struct rfapi_rib_tcb *tcb = t->arg; @@ -328,8 +328,6 @@ static int rfapiRibExpireTimer(struct thread *t) XFREE(MTYPE_RFAPI_RECENT_DELETE, tcb); RFAPI_RIB_CHECK_COUNTS(1, 0); - - return 0; } static void rfapiRibStartTimer(struct rfapi_descriptor *rfd, @@ -682,10 +680,11 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, memcpy(&vo->v.l2addr.macaddr, bpi->extra->vnc.import.rd.val + 2, ETH_ALEN); - (void)rfapiEcommunityGetLNI(bpi->attr->ecommunity, + (void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr), &vo->v.l2addr.logical_net_id); - (void)rfapiEcommunityGetEthernetTag(bpi->attr->ecommunity, - &vo->v.l2addr.tag_id); + (void)rfapiEcommunityGetEthernetTag( + bgp_attr_get_ecommunity(bpi->attr), + &vo->v.l2addr.tag_id); /* local_nve_id comes from RD */ vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1]; @@ -1950,7 +1949,7 @@ rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd, && RFAPI_HOST_PREFIX(&rk.aux_prefix)) { /* mark as "none" if nhp->prefix is 0/32 or * 0/128 */ - rk.aux_prefix.family = 0; + rk.aux_prefix.family = AF_UNSPEC; } } diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 6762c2b4a..b95bace0d 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -417,8 +417,8 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, } } - if (bpi->attr->ecommunity) { - s = ecommunity_ecom2str(bpi->attr->ecommunity, + if (bgp_attr_get_ecommunity(bpi->attr)) { + s = ecommunity_ecom2str(bgp_attr_get_ecommunity(bpi->attr), ECOMMUNITY_FORMAT_ROUTE_MAP, 0); vty_out(vty, " EC{%s}", s); XFREE(MTYPE_ECOMMUNITY_STR, s); @@ -467,6 +467,8 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr) struct transit *transit; struct cluster_list *cluster; char buf[BUFSIZ]; + struct ecommunity *ecomm; + struct community *comm; if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) return; @@ -481,11 +483,14 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr) fp(out, " aspath=%p, refcnt=%d%s", attr->aspath, (attr->aspath ? attr->aspath->refcnt : 0), HVTYNL); - fp(out, " community=%p, refcnt=%d%s", attr->community, - (attr->community ? attr->community->refcnt : 0), HVTYNL); - fp(out, " ecommunity=%p, refcnt=%d%s", attr->ecommunity, - (attr->ecommunity ? attr->ecommunity->refcnt : 0), HVTYNL); + comm = bgp_attr_get_community(attr); + fp(out, " community=%p, refcnt=%d%s", comm, (comm ? comm->refcnt : 0), + HVTYNL); + + ecomm = bgp_attr_get_ecommunity(attr); + fp(out, " ecommunity=%p, refcnt=%d%s", ecomm, + (ecomm ? ecomm->refcnt : 0), HVTYNL); cluster = bgp_attr_get_cluster(attr); fp(out, " cluster=%p, refcnt=%d%s", cluster, @@ -623,8 +628,8 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) } /* RT list */ - if (bpi->attr->ecommunity) { - s = ecommunity_ecom2str(bpi->attr->ecommunity, + if (bgp_attr_get_ecommunity(bpi->attr)) { + s = ecommunity_ecom2str(bgp_attr_get_ecommunity(bpi->attr), ECOMMUNITY_FORMAT_ROUTE_MAP, 0); r = snprintf(p, REMAIN, " %s", s); INCP; diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index 68dc5a4f6..f4f2e1139 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -136,8 +136,9 @@ static int getce(struct bgp *bgp, struct attr *attr, struct prefix *pfx_ce) uint8_t *ecp; uint32_t i; uint16_t localadmin = bgp->rfapi_cfg->resolve_nve_roo_local_admin; + struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); - for (ecp = attr->ecommunity->val, i = 0; i < attr->ecommunity->size; + for (ecp = ecomm->val, i = 0; i < ecomm->size; ++i, ecp += ECOMMUNITY_SIZE) { if (VNC_DEBUG(EXPORT_BGP_GETCE)) { @@ -640,12 +641,14 @@ encap_attr_export(struct attr *new, struct attr *orig, /* TBD use lcom for IPv6 */ ecom_ro = vnc_route_origin_ecom_single(&use_nexthop->u.prefix4); } - if (new->ecommunity) { + if (bgp_attr_get_ecommunity(new)) { if (ecom_ro) - new->ecommunity = - ecommunity_merge(ecom_ro, new->ecommunity); + bgp_attr_set_ecommunity( + new, + ecommunity_merge(ecom_ro, + bgp_attr_get_ecommunity(new))); } else { - new->ecommunity = ecom_ro; + bgp_attr_set_ecommunity(new, ecom_ro); } if (ecom_ro) { new->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); @@ -972,9 +975,6 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) import_table = rfg->rfapi_import_table; - bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE); - /* TBD set some configured med, see add_vnc_route() */ - if (afi == AFI_IP || afi == AFI_IP6) { rt = import_table->imported_vpn[afi]; } else { @@ -983,6 +983,9 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) return; } + bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE); + /* TBD set some configured med, see add_vnc_route() */ + /* * Walk the NVE-Group's VNC Import table */ @@ -1725,7 +1728,7 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi, bgp_attr_unintern(&iattr); } -static int vncExportWithdrawTimer(struct thread *t) +static void vncExportWithdrawTimer(struct thread *t) { struct vnc_export_info *eti = t->arg; const struct prefix *p = agg_node_get_prefix(eti->node); @@ -1744,8 +1747,6 @@ static int vncExportWithdrawTimer(struct thread *t) * Free the eti */ vnc_eti_delete(eti); - - return 0; } /* diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index 0358c8d66..994de7d72 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -373,8 +373,8 @@ static int process_unicast_route(struct bgp *bgp, /* in */ */ rfapiUnicastNexthop2Prefix(afi, &hattr, unicast_nexthop); - if (hattr.ecommunity) - *ecom = ecommunity_dup(hattr.ecommunity); + if (bgp_attr_get_ecommunity(&hattr)) + *ecom = ecommunity_dup(bgp_attr_get_ecommunity(&hattr)); else *ecom = ecommunity_new(); @@ -480,8 +480,8 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( struct ecommunity *new_ecom = ecommunity_dup(ecom); - if (bpi->attr->ecommunity) - ecommunity_merge(new_ecom, bpi->attr->ecommunity); + if (bgp_attr_get_ecommunity(bpi->attr)) + ecommunity_merge(new_ecom, bgp_attr_get_ecommunity(bpi->attr)); if (bpi->extra) label = decode_label(&bpi->extra->label[0]); @@ -818,8 +818,8 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp, memset(&prd, 0, sizeof(prd)); rfapi_set_autord_from_vn(&prd, &vnaddr); - if (iattr && iattr->ecommunity) - ecom = ecommunity_dup(iattr->ecommunity); + if (iattr && bgp_attr_get_ecommunity(iattr)) + ecom = ecommunity_dup(bgp_attr_get_ecommunity(iattr)); } local_pref = calc_local_pref(iattr, peer); @@ -1015,8 +1015,9 @@ static void vnc_import_bgp_add_route_mode_nvegroup( else ecom = ecommunity_new(); - if (iattr && iattr->ecommunity) - ecom = ecommunity_merge(ecom, iattr->ecommunity); + if (iattr && bgp_attr_get_ecommunity(iattr)) + ecom = ecommunity_merge(ecom, + bgp_attr_get_ecommunity(iattr)); } local_pref = calc_local_pref(iattr, peer); diff --git a/configure.ac b/configure.ac index 85f8e854f..170d16ca6 100644 --- a/configure.ac +++ b/configure.ac @@ -765,7 +765,7 @@ AC_ARG_ENABLE([scripting], AS_HELP_STRING([--enable-scripting], [Build with scripting support])) AC_ARG_ENABLE([netlink-debug], - AS_HELP_STRING([--disable-netlink-debug], [pretty print netlink debug messages])) + AS_HELP_STRING([--disable-netlink-debug], [don't pretty print netlink debug messages])) if test "$enable_netlink_debug" != "no" ; then AC_DEFINE([NETLINK_DEBUG], [1], [Netlink extra debugging code]) @@ -1299,8 +1299,11 @@ AC_CHECK_FUNCS([ \ openat \ unlinkat \ posix_fallocate \ + sendmmsg \ ]) +AC_CHECK_MEMBERS([struct mmsghdr.msg_hdr], [], [], FRR_INCLUDES) + dnl ########################################################################## dnl LARGE if block spans a lot of "configure"! if test "$enable_clippy_only" != "yes"; then @@ -1368,6 +1371,8 @@ case "${enable_vtysh}" in AC_MSG_ERROR([libreadline (needed for vtysh) not found and/or missing dependencies]) ], [$LIBREADLINE]) ], []) + LIBS="$LIBS -lreadline" + AC_CHECK_FUNCS([rl_clear_visible_line]) LIBS="$prev_libs" AC_CHECK_HEADER([readline/history.h]) @@ -1523,6 +1528,13 @@ AC_CHECK_HEADERS([linux/mroute.h], [], [],[ #include ]) +AC_CHECK_HEADERS([linux/mroute6.h], [], [],[ + #include + #include + #define _LINUX_IN_H /* For Linux <= 2.6.25 */ + #include +]) + m4_define([FRR_INCLUDES], FRR_INCLUDES [#ifdef HAVE_LINUX_MROUTE_H @@ -2584,6 +2596,7 @@ AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra ap AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket]) AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information]) AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information]) +AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information]) AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory]) AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory]) diff --git a/debian/.gitignore b/debian/.gitignore index 0b267c6f5..d95d33a61 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -11,3 +11,4 @@ /files /frr.init /frr.service +/frr@.service diff --git a/debian/changelog b/debian/changelog index f5b392274..2b28c4c6d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ -frr (8.2~dev-1) UNRELEASED; urgency=medium +frr (8.3~dev-1) UNRELEASED; urgency=medium * New upstream release... - -- Jafar Al-Gharaibeh Mon, 08 Nov 2021 10:00:00 +0500 + -- Donatas Abraitis Tue, 01 Feb 2022 11:00:00 +0200 frr (8.1-0) unstable; urgency=medium diff --git a/debian/rules b/debian/rules index 0fa9c3a3b..7a719b7c6 100755 --- a/debian/rules +++ b/debian/rules @@ -72,6 +72,7 @@ override_dh_auto_install: # let dh_systemd_* and dh_installinit do their thing automatically cp tools/frr.service debian/frr.service + cp tools/frr@.service debian/frr@.service cp tools/frrinit.sh debian/frr.init -rm -f debian/tmp/usr/lib/frr/frr @@ -112,3 +113,4 @@ override_dh_auto_clean: if test -f Makefile; then make redistclean; fi -rm -f debian/frr.init -rm -f debian/frr.service + -rm -f debian/frr@.service diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index 9254eb473..ff6c4f6e1 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -48,6 +48,16 @@ a node and returns the parent of the node. This interface causes all manner of insidious problems, even for experienced developers, and needs to be fixed at some point in the future. +Deprecation of old style of commands +------------------------------------ + +There are currently 2 styles of defining commands within a FRR source file. +``DEFUN`` and ``DEFPY``. ``DEFPY`` should be used for all new commands that +a developer is writing. This is because it allows for much better handling +of command line arguments as well as ensuring that input is correct. ``DEFUN`` +is listed here for historical reasons as well as for ensuring that existing +code can be understood by new developers. + Defining Commands ----------------- All definitions for the CLI system are exposed in ``lib/command.h``. In this diff --git a/doc/developer/cspf.rst b/doc/developer/cspf.rst new file mode 100644 index 000000000..426553ff0 --- /dev/null +++ b/doc/developer/cspf.rst @@ -0,0 +1,196 @@ +Path Computation Algorithms +=========================== + +Introduction +------------ + +Both RSVP-TE and Segment Routing Flex Algo need to compute end to end path +with other constraints as the standard IGP metric. Based on Shortest Path First +(SPF) algorithms, a new class of Constrained SPF (CSPF) is provided by the FRR +library. + +Supported constraints are as follow: +- Standard IGP metric (here, CSPF provides the same result as a normal SPF) +- Traffic Engineering (TE) IGP metric +- Delay from the IGP Extended Metrics +- Bandwidth for a given Class of Service (CoS) for bandwidth reservation + +Algorithm +--------- + +The CSPF algorithm is based on a Priority Queue which store the on-going +possible path sorted by their respective weights. This weight corresponds +to the cost of the cuurent path from the source up to the current node. + +The algorithm is as followed: + +``` + cost = MAX_COST; + Priority_Queue.empty(); + Visited_Node.empty(); + Processed_Path.empty(); + src = new_path(source_address); + src.cost = 0; + dst = new_destinatio(destination_address); + dst.cost = MAX_COST; + Processed_Path.add(src); + Processed_Path.add(dst); + while (Priority_Queue.count != 0) { + current_path = Priority_Queue.pop(); + current_node = next_path.destination; + Visited_Node.add(current_node); + for (current_node.edges: edge) { + if (prune_edge(current_path, edge) + continue; + if (relax(current_path) && cost > current_path.cost) { + optim_path = current_path; + cost = current_path.cost; + } + } + } + + prune_edge(path, edge) { + // check that path + edge meet constraints e.g. + if (current_path.cost + edge.cost > constrained_cost) + return false; + else + return true; + } + + relax_edge(current_path, edge) { + next_node = edge.destination; + if (Visited_Node.get(next_node)) + return false; + next_path = Processed_Path.get(edge.destination); + if (!next_path) { + next_path = new path(edge.destination); + Processed_Path.add(next_path); + } + total_cost = current_path.cost + edge.cost; + if (total_cost < next_path.cost) { + next_path = current_path; + next_path.add_edge(edge); + next_path.cost = total_cost; + Priority_Queue.add(next_path); + } + return (next_path.destination == destination); + } + +``` + +Definition +---------- + +.. c:struct:: constraints + +This is the constraints structure that contains: + +- cost: the total cost that the path must respect +- ctype: type of constraints: + + - CSPF_METRIC for standard metric + - CSPF_TE_METRIC for TE metric + - CSPF_DELAY for delay metric + +- bw: bandwidth that the path must respect +- cos: Class of Service (COS) for the bandwidth +- family: AF_INET or AF_INET6 +- type: RSVP_TE, SR_TE or SRV6_TE + +.. c:struct:: c_path + +This is the Constraint Path structure that contains: + +- edges: List of Edges that compose the path +- status: FAILED, IN_PROGRESS, SUCCESS, NO_SOURCE, NO_DESTINATION, SAME_SRC_DST +- weight: the cost from source to the destination of the path +- dst: key of the destination vertex + +.. c:struct:: cspf + +This is the main structure for path computation. Even if it is public, you +don't need to set manually the internal field of the structure. Instead, use +the following functions: + +.. c:function:: struct cspf *cspf_new(void); + +Function to create an empty cspf for future call of path computation + +.. c:function:: struct cspf *cspf_init(struct cspf *algo, const struct ls_vertex *src, const struct ls_vertex *dst, struct constraints *csts); + +This function initialize the cspf with source and destination vertex and +constraints and return pointer to the cspf structure. If input cspf structure +is NULL, a new cspf structure is allocated and initialize. + +.. c:function:: struct cspf *cspf_init_v4(struct cspf *algo, struct ls_ted *ted, const struct in_addr src, const struct in_addr dst, struct constraints *csts); + +Same as cspf_init, but here, source and destination vertex are extract from +the TED data base based on respective IPv4 source and destination addresses. + +.. c:function:: struct cspf *cspf_init_v6(struct cspf *algo, struct ls_ted *ted, const struct in6_addr src, const struct in6_addr dst, struct constraints *csts); + +Same as cspf_init_v4 but with IPv6 source and destination addresses. + +.. c:function:: void cspf_clean(struct cspf *algo); + +Clean internal structure of cspf in order to reuse it for another path +computation. + +.. c:function:: void cspf_del(struct cspf *algo); + +Delete cspf structure. A call to cspf_clean() function is perform prior to +free allocated memeory. + +.. c:function:: struct c_path *compute_p2p_path(struct ls_ted *ted, struct cspf *algo); + +Compute point to point path from the ted and cspf. +The function always return a constraints path. The status of the path gives +indication about the success or failure of the algorithm. If cspf structure has +not been initialize with a call to `cspf_init() or cspf_init_XX()`, the +algorithm returns a constraints path with status set to FAILED. +Note that a call to `cspf_clean()` is performed at the end of this function, +thus it is mandatory to initialize the cspf structure again prior to call again +the path computation algorithm. + + +Usage +----- + +Of course, CSPF algorithm needs a network topology that contains the +various metrics. Link State provides such Traffic Engineering Database. + +To perform a Path Computation with given constraints, proceed as follow: + +.. code-block:: c + struct cspf *algo; + struct ls_ted *ted; + struct in_addr src; + struct in_addr dst; + struct constraints csts; + struct c_path *path; + + // Create a new CSPF structure + algo = cspf_new(); + + // Initialize constraints + csts.cost = 100; + csts.ctype = CSPF_TE_METRIC; + csts.family = AF_INET; + csts.type = SR_TE; + csts.bw = 1000000; + csts.cos = 3; + + // Then, initialise th CSPF with source, destination and constraints + cspf_init_v4(algo, ted, src, dst, &csts); + + // Finally, got the Computed Path; + path = compute_p2p_path(ted, algo); + + if (path.status == SUCCESS) + zlog_info("Got a valid constraints path"); + else + zlog_info("Unable to compute constraints path. Got %d status", path->status); + + +If you would compute another path, you must call `cspf_init()` prior to +`compute_p2p_path()` to change source, destination and/or constraints. diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst index 6a7f9c4ca..4ef0ca841 100644 --- a/doc/developer/frr-release-procedure.rst +++ b/doc/developer/frr-release-procedure.rst @@ -204,7 +204,7 @@ Stage 3 - Publish .. code-block:: console - cp .md .md + cp content/release/.md content/release/.md Paste the GitHub release announcement text into this document, and **remove line breaks**. In other words, this:: @@ -220,10 +220,17 @@ Stage 3 - Publish This is very important otherwise the announcement will be unreadable on the website. - Make sure to add a link to the GitHub releases page at the top. + To get the number of commiters and commits, here is a couple of handy commands: + + .. code-block:: console - Once finished, manually add a new entry into ``index.html`` to link to this - new announcement. Look at past commits to see how to do this. + # The number of commits + % git log --oneline --no-merges base_8.2...base_8.1 | wc -l + + # The number of commiters + % git shortlog --summary --no-merges base_8.2...base_8.1 | wc -l + + Make sure to add a link to the GitHub releases page at the top. #. Deploy the updated ``frr-www`` on the frrouting.org web server and verify that the announcement text is visible. diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst index dc8f23692..4eaa85115 100644 --- a/doc/developer/lists.rst +++ b/doc/developer/lists.rst @@ -1,23 +1,23 @@ .. _lists: -List implementations +Type-safe containers ==================== .. note:: - The term *list* is used generically for lists, skiplists, trees and hash - tables in this document. + This section previously used the term *list*; it was changed to *container* + to be more clear. -Common list interface ---------------------- +Common container interface +-------------------------- -FRR includes a set of list-like data structure implementations with abstracted +FRR includes a set of container implementations with abstracted common APIs. The purpose of this is easily allow swapping out one data structure for another while also making the code easier to read and write. -There is one API for unsorted lists and a similar but not identical API for -sorted lists - and heaps use a middle ground of both. +There is one API for unsorted containers and a similar but not identical API +for sorted containers - and heaps use a middle ground of both. -For unsorted lists, the following implementations exist: +For unsorted containers, the following implementations exist: - single-linked list with tail pointer (e.g. STAILQ in BSD) @@ -31,7 +31,7 @@ Being partially sorted, the oddball structure: - an 8-ary heap -For sorted lists, these data structures are implemented: +For sorted containers, these data structures are implemented: - single-linked list @@ -44,7 +44,7 @@ For sorted lists, these data structures are implemented: - hash table (note below) Except for hash tables, each of the sorted data structures has a variant with -unique and non-unique list items. Hash tables always require unique items +unique and non-unique items. Hash tables always require unique items and mostly follow the "sorted" API but use the hash value as sorting key. Also, iterating while modifying does not work with hash tables. Conversely, the heap always has non-unique items, but iterating while modifying @@ -60,7 +60,7 @@ in the future: The APIs are all designed to be as type-safe as possible. This means that -there will be a compiler warning when an item doesn't match the list, or +there will be a compiler warning when an item doesn't match the container, or the return value has a different type, or other similar situations. **You should never use casts with these APIs.** If a cast is neccessary in relation to these APIs, there is probably something wrong with the overall design. @@ -100,35 +100,39 @@ Available types: Functions provided: -+------------------------------------+------+------+------+---------+------------+ -| Function | LIST | HEAP | HASH | \*_UNIQ | \*_NONUNIQ | -+====================================+======+======+======+=========+============+ -| _init, _fini | yes | yes | yes | yes | yes | -+------------------------------------+------+------+------+---------+------------+ -| _first, _next, _next_safe, | yes | yes | yes | yes | yes | -| | | | | | | -| _const_first, _const_next | | | | | | -+------------------------------------+------+------+------+---------+------------+ -| _swap_all | yes | yes | yes | yes | yes | -+------------------------------------+------+------+------+---------+------------+ -| _anywhere | yes | -- | -- | -- | -- | -+------------------------------------+------+------+------+---------+------------+ -| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- | -+------------------------------------+------+------+------+---------+------------+ -| _add | -- | yes | yes | yes | yes | -+------------------------------------+------+------+------+---------+------------+ -| _member | yes | yes | yes | yes | yes | -+------------------------------------+------+------+------+---------+------------+ -| _del, _pop | yes | yes | yes | yes | yes | -+------------------------------------+------+------+------+---------+------------+ -| _find, _const_find | -- | -- | yes | yes | -- | -+------------------------------------+------+------+------+---------+------------+ -| _find_lt, _find_gteq, | -- | -- | -- | yes | yes | -| | | | | | | -| _const_find_lt, _const_find_gteq | | | | | | -+------------------------------------+------+------+------+---------+------------+ -| use with frr_each() macros | yes | yes | yes | yes | yes | -+------------------------------------+------+------+------+---------+------------+ ++------------------------------------+-------+------+------+---------+------------+ +| Function | LIST | HEAP | HASH | \*_UNIQ | \*_NONUNIQ | ++====================================+=======+======+======+=========+============+ +| _init, _fini | yes | yes | yes | yes | yes | ++------------------------------------+-------+------+------+---------+------------+ +| _first, _next, _next_safe, | yes | yes | yes | yes | yes | +| | | | | | | +| _const_first, _const_next | | | | | | ++------------------------------------+-------+------+------+---------+------------+ +| _last, _prev, _prev_safe, | DLIST | -- | -- | RB only | RB only | +| | only | | | | | +| _const_last, _const_prev | | | | | | ++------------------------------------+-------+------+------+---------+------------+ +| _swap_all | yes | yes | yes | yes | yes | ++------------------------------------+-------+------+------+---------+------------+ +| _anywhere | yes | -- | -- | -- | -- | ++------------------------------------+-------+------+------+---------+------------+ +| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- | ++------------------------------------+-------+------+------+---------+------------+ +| _add | -- | yes | yes | yes | yes | ++------------------------------------+-------+------+------+---------+------------+ +| _member | yes | yes | yes | yes | yes | ++------------------------------------+-------+------+------+---------+------------+ +| _del, _pop | yes | yes | yes | yes | yes | ++------------------------------------+-------+------+------+---------+------------+ +| _find, _const_find | -- | -- | yes | yes | -- | ++------------------------------------+-------+------+------+---------+------------+ +| _find_lt, _find_gteq, | -- | -- | -- | yes | yes | +| | | | | | | +| _const_find_lt, _const_find_gteq | | | | | | ++------------------------------------+-------+------+------+---------+------------+ +| use with frr_each() macros | yes | yes | yes | yes | yes | ++------------------------------------+-------+------+------+---------+------------+ @@ -136,7 +140,7 @@ Datastructure type setup ------------------------ Each of the data structures has a ``PREDECL_*`` and a ``DECLARE_*`` macro to -set up an "instantiation" of the list. This works somewhat similar to C++ +set up an "instantiation" of the container. This works somewhat similar to C++ templating, though much simpler. **In all following text, the Z prefix is replaced with a name choosen @@ -174,8 +178,8 @@ The common setup pattern will look like this: ``XXX`` is replaced with the name of the data structure, e.g. ``SKIPLIST`` or ``ATOMLIST``. The ``DECLARE_XXX`` invocation can either occur in a `.h` -file (if the list needs to be accessed from several C files) or it can be -placed in a `.c` file (if the list is only accessed from that file.) The +file (if the container needs to be accessed from several C files) or it can be +placed in a `.c` file (if the container is only accessed from that file.) The ``PREDECL_XXX`` invocation defines the ``struct Z_item`` and ``struct Z_head`` types and must therefore occur before these are used. @@ -196,7 +200,7 @@ The following iteration macros work across all data structures: for (item = Z_first(&head); item; item = Z_next(&head, item)) - Note that this will fail if the list is modified while being iterated + Note that this will fail if the container is modified while being iterated over. .. c:macro:: frr_each_safe(Z, head, item) @@ -220,8 +224,8 @@ The following iteration macros work across all data structures: .. c:macro:: frr_each_from(Z, head, item, from) - Iterates over the list, starting at item ``from``. This variant is "safe" - as in the previous macro. Equivalent to: + Iterates over the container, starting at item ``from``. This variant is + "safe" as in the previous macro. Equivalent to: .. code-block:: c @@ -236,6 +240,13 @@ The following iteration macros work across all data structures: resume iteration after breaking out of the loop by keeping the ``from`` value persistent and reusing it for the next loop. +.. c:macro:: frr_rev_each(Z, head, item) +.. c:macro:: frr_rev_each_safe(Z, head, item) +.. c:macro:: frr_rev_each_from(Z, head, item, from) + + Reverse direction variants of the above. Only supported on containers that + implement ``_last`` and ``_prev`` (i.e. ``RBTREE`` and ``DLIST``). + To iterate over ``const`` pointers, add ``_const`` to the name of the datastructure (``Z`` above), e.g. ``frr_each (mylist, head, item)`` becomes ``frr_each (mylist_const, head, item)``. @@ -243,24 +254,24 @@ datastructure (``Z`` above), e.g. ``frr_each (mylist, head, item)`` becomes Common API ---------- -The following documentation assumes that a list has been defined using -``Z`` as the name, and ``itemtype`` being the type of the list items (e.g. +The following documentation assumes that a container has been defined using +``Z`` as the name, and ``itemtype`` being the type of the items (e.g. ``struct item``.) .. c:function:: void Z_init(struct Z_head *) - Initializes the list for use. For most implementations, this just sets + Initializes the container for use. For most implementations, this just sets some values. Hash tables are the only implementation that allocates memory in this call. .. c:function:: void Z_fini(struct Z_head *) - Reverse the effects of :c:func:`Z_init()`. The list must be empty + Reverse the effects of :c:func:`Z_init()`. The container must be empty when this function is called. .. warning:: - This function may ``assert()`` if the list is not empty. + This function may ``assert()`` if the container is not empty. .. c:function:: size_t Z_count(const struct Z_head *) @@ -270,7 +281,7 @@ The following documentation assumes that a list has been defined using .. note:: - For atomic lists with concurrent access, the value will already be + For atomic containers with concurrent access, the value will already be outdated by the time this function returns and can therefore only be used as an estimate. @@ -291,6 +302,12 @@ The following documentation assumes that a list has been defined using empty. This is O(1) for all data structures except red-black trees where it is O(log n). +.. c:function:: const itemtype *Z_const_last(const struct Z_head *) +.. c:function:: itemtype *Z_last(struct Z_head *) + + Last item in the structure, or ``NULL``. Only available on containers + that support reverse iteration (i.e. ``RBTREE`` and ``DLIST``). + .. c:function:: itemtype *Z_pop(struct Z_head *) Remove and return the first item in the structure, or ``NULL`` if the @@ -300,7 +317,7 @@ The following documentation assumes that a list has been defined using This function can be used to build queues (with unsorted structures) or priority queues (with sorted structures.) - Another common pattern is deleting all list items: + Another common pattern is deleting all container items: .. code-block:: c @@ -329,16 +346,23 @@ The following documentation assumes that a list has been defined using Same as :c:func:`Z_next()`, except that ``NULL`` is returned if ``prev`` is ``NULL``. +.. c:function:: const itemtype *Z_const_prev(const struct Z_head *, const itemtype *next) +.. c:function:: itemtype *Z_prev(struct Z_head *, itemtype *next) +.. c:function:: itemtype *Z_prev_safe(struct Z_head *, itemtype *next) + + As above, but preceding item. Only available on structures that support + reverse iteration (i.e. ``RBTREE`` and ``DLIST``). + .. c:function:: itemtype *Z_del(struct Z_head *, itemtype *item) - Remove ``item`` from the list and return it. + Remove ``item`` from the container and return it. .. note:: This function's behaviour is undefined if ``item`` is not actually - on the list. Some structures return ``NULL`` in this case while others - return ``item``. The function may also call ``assert()`` (but most - don't.) + on the container. Some structures return ``NULL`` in this case while + others return ``item``. The function may also call ``assert()`` (but + most don't.) .. c:function:: itemtype *Z_swap_all(struct Z_head *, struct Z_head *) @@ -427,8 +451,8 @@ API for sorted structures ------------------------- Sorted data structures do not need to have an insertion position specified, -therefore the insertion calls are different from unsorted lists. Also, -sorted lists can be searched for a value. +therefore the insertion calls are different from unsorted containers. Also, +sorted containers can be searched for a value. .. c:macro:: DECLARE_XXX_UNIQ(Z, type, field, compare_func) @@ -439,7 +463,7 @@ sorted lists can be searched for a value. created for this instantiation. ``DECLARE_XXX(foo, ...)`` gives ``struct foo_item``, ``foo_add()``, ``foo_count()``, etc. Note that this must match the value given in ``PREDECL_XXX(foo)``. - :param typename type: Specifies the data type of the list items, e.g. + :param typename type: Specifies the data type of the items, e.g. ``struct item``. Note that ``struct`` must be added here, it is not automatically added. :param token field: References a struct member of ``type`` that must be @@ -448,29 +472,29 @@ sorted lists can be searched for a value. :param funcptr compare_func: Item comparison function, must have the following function signature: ``int function(const itemtype *, const itemtype*)``. This function - may be static if the list is only used in one file. + may be static if the container is only used in one file. .. c:macro:: DECLARE_XXX_NONUNIQ(Z, type, field, compare_func) - Same as above, but allow adding multiple items to the list that compare + Same as above, but allow adding multiple items to the container that compare as equal in ``compare_func``. Ordering between these items is undefined - and depends on the list implementation. + and depends on the container implementation. .. c:function:: itemtype *Z_add(struct Z_head *, itemtype *item) Insert an item at the appropriate sorted position. If another item exists - in the list that compares as equal (``compare_func()`` == 0), ``item`` is - not inserted into the list and the already-existing item in the list is + in the container that compares as equal (``compare_func()`` == 0), ``item`` + is not inserted and the already-existing item in the container is returned. Otherwise, on successful insertion, ``NULL`` is returned. - For ``_NONUNIQ`` lists, this function always returns NULL since ``item`` - can always be successfully added to the list. + For ``_NONUNIQ`` containers, this function always returns NULL since + ``item`` can always be successfully added to the container. .. c:function:: const itemtype *Z_const_find(const struct Z_head *, const itemtype *ref) .. c:function:: itemtype *Z_find(struct Z_head *, const itemtype *ref) - Search the list for an item that compares equal to ``ref``. If no equal - item is found, return ``NULL``. + Search the container for an item that compares equal to ``ref``. If no + equal item is found, return ``NULL``. This function is likely used with a temporary stack-allocated value for ``ref`` like so: @@ -483,21 +507,21 @@ sorted lists can be searched for a value. .. note:: - The ``Z_find()`` function is only available for lists that contain - unique items (i.e. ``DECLARE_XXX_UNIQ``.) This is because on a list - containing non-unique items, more than one item may compare as equal to + The ``Z_find()`` function is only available for containers that contain + unique items (i.e. ``DECLARE_XXX_UNIQ``.) This is because on a container + with non-unique items, more than one item may compare as equal to the item that is searched for. .. c:function:: const itemtype *Z_const_find_gteq(const struct Z_head *, const itemtype *ref) .. c:function:: itemtype *Z_find_gteq(struct Z_head *, const itemtype *ref) - Search the list for an item that compares greater or equal to + Search the container for an item that compares greater or equal to ``ref``. See :c:func:`Z_find()` above. .. c:function:: const itemtype *Z_const_find_lt(const struct Z_head *, const itemtype *ref) .. c:function:: itemtype *Z_find_lt(struct Z_head *, const itemtype *ref) - Search the list for an item that compares less than + Search the container for an item that compares less than ``ref``. See :c:func:`Z_find()` above. @@ -511,7 +535,7 @@ API for hash tables created for this instantiation. ``DECLARE_XXX(foo, ...)`` gives ``struct foo_item``, ``foo_add()``, ``foo_count()``, etc. Note that this must match the value given in ``PREDECL_XXX(foo)``. - :param typename type: Specifies the data type of the list items, e.g. + :param typename type: Specifies the data type of the items, e.g. ``struct item``. Note that ``struct`` must be added here, it is not automatically added. :param token field: References a struct member of ``type`` that must be @@ -520,7 +544,7 @@ API for hash tables :param funcptr compare_func: Item comparison function, must have the following function signature: ``int function(const itemtype *, const itemtype*)``. This function - may be static if the list is only used in one file. For hash tables, + may be static if the container is only used in one file. For hash tables, this function is only used to check for equality, the ordering is ignored. :param funcptr hash_func: Hash calculation function, must have the @@ -725,13 +749,9 @@ Head removal (pop) and deallocation: FAQ --- -What are the semantics of ``const`` in the list APIs? +What are the semantics of ``const`` in the container APIs? ``const`` pointers to list heads and/or items are interpreted to mean that - both the list itself as well as the data items are read-only. - -Why is there no "is this item on a/the list" test? - It's slow for several of the data structures, and the work of adding it - just hasn't been done. It can certainly be added if it's needed. + both the container itself as well as the data items are read-only. Why is it ``PREDECL`` + ``DECLARE`` instead of ``DECLARE`` + ``DEFINE``? The rule is that a ``DEFINE`` must be in a ``.c`` file, and linked exactly diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index 4e6fc0420..704636120 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -163,6 +163,10 @@ Networking data types - :c:union:`prefixptr` (dereference to get :c:struct:`prefix`) - :c:union:`prefixconstptr` (dereference to get :c:struct:`prefix`) + Options: + + ``%pFXh``: (address only) :frrfmtout:`1.2.3.0` / :frrfmtout:`fe80::1234` + .. frrfmt:: %pPSG4 (struct prefix_sg *) :frrfmtout:`(*,1.2.3.4)` diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index fa1fd2006..b41181f4e 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -1088,6 +1088,9 @@ Requirements: a pull request. This ensures we have a unified code style. - Mark test modules with pytest markers depending on the daemons used during the tests (see :ref:`topotests-markers`) +- Always use IPv4 :rfc:`5737` (``192.0.2.0/24``, ``198.51.100.0/24``, + ``203.0.113.0/24``) and IPv6 :rfc:`3849` (``2001:db8::/32``) ranges reserved + for documentation. Tips: diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 54561d3b4..af8756a90 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -95,8 +95,8 @@ March/July/November. Walking backwards from this date: are considered lowest priority (regardless of when they were opened.) - 4 weeks earlier, the stable branch separates from master (named - ``dev/MAJOR.MINOR`` at this point) and a ``rc1`` release candidate is - tagged. Master is unfrozen and new features may again proceed. + ``dev/MAJOR.MINOR`` at this point) and tagged as ```base_X.Y``. + Master is unfrozen and new features may again proceed. Part of unfreezing master is editing the ``AC_INIT`` statement in :file:`configure.ac` to reflect the new development version that master @@ -108,7 +108,48 @@ March/July/November. Walking backwards from this date: (The :file:`configure.ac` edit and tag push are considered git housekeeping and are pushed directly to ``master``, not through a PR.) - - 2 weeks earlier, a ``rc2`` release candidate is tagged. + Below is the snippet of the commands to use in this step. + + .. code-block:: console + + % git remote --verbose + upstream git@github.com:frrouting/frr (fetch) + upstream git@github.com:frrouting/frr (push) + + % git checkout master + % git pull upstream master + % git checkout -b dev/8.2 + % git tag base_8.2 + % git push upstream base_8.2 + % git push upstream dev/8.2 + % git checkout master + % sed -i 's/8.2-dev/8.3-dev/' configure.ac + % git add configure.ac + % git commit -s -m "build: FRR 8.3 development version" + % git tag -a frr-8.3-dev -m "frr-8.3-dev" + % git push upstream master + % git push upstream frr-8.3-dev + + In this step, we also have to update package versions to reflect + the development version. Versions need to be updated using + a standard way of development (Pull Requests) based on master branch. + + Only change the version number with no other changes. This will produce + packages with the a version number that is higher than any previous + version. Once the release is done, whatever updates we make to changelog + files on the release branch need to be cherry-picked to the master branch. + + - 2 weeks earlier, a ``frr-X.Y-rc`` release candidate is tagged. + + .. code-block:: console + + % git remote --verbose + upstream git@github.com:frrouting/frr (fetch) + upstream git@github.com:frrouting/frr (push) + + % git checkout dev/8.2 + % git tag frr-8.2-rc + % git push upstream frr-8.2-rc - on release date, the branch is renamed to ``stable/MAJOR.MINOR``. @@ -121,26 +162,29 @@ as early as possible, i.e. the first 2-week window. For reference, the expected release schedule according to the above is: -+------------+------------+------------+------------+------------+------------+ -| Release | 2021-11-02 | 2022-03-01 | 2022-07-05 | 2022-11-01 | 2023-03-07 | -+------------+------------+------------+------------+------------+------------+ -| rc2 | 2021-10-19 | 2022-02-15 | 2022-06-21 | 2022-10-18 | 2023-02-21 | -+------------+------------+------------+------------+------------+------------+ -| rc1/branch | 2021-10-05 | 2022-02-01 | 2022-06-07 | 2022-10-04 | 2023-02-07 | -+------------+------------+------------+------------+------------+------------+ -| freeze | 2021-09-21 | 2022-01-18 | 2022-05-24 | 2022-09-20 | 2023-01-24 | -+------------+------------+------------+------------+------------+------------+ ++---------+------------+------------+------------+------------+------------+ +| Release | 2021-11-02 | 2022-03-01 | 2022-07-05 | 2022-11-01 | 2023-03-07 | ++---------+------------+------------+------------+------------+------------+ +| RC | 2021-10-19 | 2022-02-15 | 2022-06-21 | 2022-10-18 | 2023-02-21 | ++---------+------------+------------+------------+------------+------------+ +| dev/X.Y | 2021-10-05 | 2022-02-01 | 2022-06-07 | 2022-10-04 | 2023-02-07 | ++---------+------------+------------+------------+------------+------------+ +| freeze | 2021-09-21 | 2022-01-18 | 2022-05-24 | 2022-09-20 | 2023-01-24 | ++---------+------------+------------+------------+------------+------------+ Each release is managed by one or more volunteer release managers from the FRR -community. To spread and distribute this workload, this should be rotated for +community. These release managers are expected to handle the branch for a period +of one year. To spread and distribute this workload, this should be rotated for subsequent releases. The release managers are currently assumed/expected to run a release management meeting during the weeks listed above. Barring other constraints, this would be scheduled before the regular weekly FRR community call such that important items can be carried over into that call. -Bugfixes are applied to the two most recent releases. However, backporting of bug -fixes to older than the two most recent releases will not be prevented, if acked -under the classical development workflow applying for a pull request. +Bugfixes are applied to the two most recent releases. It is expected that +each bugfix backported should include some reasoning for its inclusion +as well as receiving approval by the release managers for that release before +accepted into the release branch. This does not necessarily preclude backporting of +bug fixes to older than the two most recent releases. Security fixes are backported to all releases less than or equal to at least one year old. Security fixes may also be backported to older releases depending on @@ -302,6 +346,13 @@ Pre-submission Checklist the new feature within our existing CI infrastructure. Also the addition of automated testing to cover any pull request is encouraged. +- All new code must use the current latest version of acceptable code. + + - If a daemon is converted to YANG, then new code must use YANG. + - DEFPY's must be used for new cli + - Typesafe lists must be used + - printf formatting changes must be used + .. _signing-off: Signing Off @@ -1206,8 +1257,8 @@ CLI changes ----------- CLI's are a complicated ugly beast. Additions or changes to the CLI should use -a DEFUN to encapsulate one setting as much as is possible. Additionally as new -DEFUN's are added to the system, documentation should be provided for the new +a DEFPY to encapsulate one setting as much as is possible. Additionally as new +DEFPY's are added to the system, documentation should be provided for the new commands. Backwards Compatibility diff --git a/doc/manpages/vtysh.rst b/doc/manpages/vtysh.rst index b930cb915..af527bea4 100644 --- a/doc/manpages/vtysh.rst +++ b/doc/manpages/vtysh.rst @@ -74,7 +74,7 @@ VTYSH_PAGER VTYSH_HISTFILE Override the history file for vtysh commands. Logging can be turned off using ``VTYSH_HISTFILE=/dev/null vtysh``. - Environment is prefered way to override the history file path over command line argument (-H/--histfile). + Environment is preferred way to override the history file path over command line argument (-H/--histfile). FILES ===== diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 3b119d623..4c196cfcf 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -130,6 +130,11 @@ Basic Config Commands debugging. Note that the existing code logs its most important messages with severity ``errors``. + .. note:: + + If ``systemd`` is in use and stdout is connected to systemd, FRR will + automatically switch to ``journald`` extended logging for this target. + .. warning:: FRRouting uses the ``writev()`` system call to write log messages. This @@ -160,15 +165,24 @@ Basic Config Commands debugging, but can be changed using the deprecated ``log trap`` command) will be used. The ``no`` form of the command disables logging to syslog. + .. note:: + + This uses the system's ``syslog()`` API, which does not support message + batching or structured key/value data pairs. If possible, use + :clicmd:`log extended EXTLOGNAME` with + :clicmd:`destination syslog [supports-rfc5424]` instead of this. + +.. clicmd:: log extended EXTLOGNAME + + Create an extended logging target with the specified name. The name has + no further meaning and is only used to identify the target. Multiple + targets can be created and deleted with the ``no`` form. + + Refer to :ref:`ext-log-target` for further details and suboptions. + .. clicmd:: log monitor [LEVEL] - Enable logging output to vty terminals that have enabled logging using the - ``terminal monitor`` command. By default, monitor logging is enabled at the - debugging level, but this command (or the deprecated ``log trap`` command) - can be used to change the monitor logging level. If the optional second - argument specifying the logging level is not present, the default logging - level (typically debugging) will be used. The ``no`` form of the command - disables logging to terminal monitors. + This command is deprecated and does nothing. .. clicmd:: log facility [FACILITY] @@ -659,6 +673,11 @@ Terminal Mode Commands we are setting each individual fd for the poll command at that point in time. +.. clicmd:: show thread timers + + This command displays FRR's timer data for timers that will pop in + the future. + .. _common-invocation-options: Common Invocation Options diff --git a/doc/user/extlog.rst b/doc/user/extlog.rst new file mode 100644 index 000000000..bb872c629 --- /dev/null +++ b/doc/user/extlog.rst @@ -0,0 +1,189 @@ +.. _ext-log-target: + +*********************** +Extended Logging Target +*********************** + +After creating one or more extended logging targets with the +:clicmd:`log extended EXTLOGNAME` command, the target(s) must be configured +for the desired logging output. + +Each extended log target supports emitting log messages in one of the following +formats: + +- ``rfc5424`` - :rfc:`5424` - modern syslog with ISO 8601 timestamps, time zone and + structured data (key/value pairs) support +- ``rfc3164`` - :rfc:`3164` - legacy BSD syslog, timestamps with 1 second granularity +- ``local-syslog`` - same as :rfc:`3164`, but without the hostname field +- ``journald`` - systemd's `native journald protocol `_. + This protocol also supports structured data (key/value pairs). + +Destinations +------------ + +The output location is configured with the following subcommands: + +.. clicmd:: destination none + + Disable the target while retaining its remaining configuration. + +.. clicmd:: destination syslog [supports-rfc5424] + + Send log messages to the system's standard log destination + (``/dev/log``). This does not use the C library's ``syslog()`` function, + instead writing directly to ``/dev/log``. + + On NetBSD and FreeBSD, the RFC5424 format is automatically used when + the OS version is recent enough (5.0 for NetBSD, 12.0 for FreeBSD). + Unfortunately, support for this format cannot be autodetected otherwise, + and particularly on Linux systems must be enabled manually. + +.. clicmd:: destination journald + + Send log messages to systemd's journald. + +.. clicmd:: destination > \ + [format FORMAT] + + Send log messages to one of the daemon's file descriptors. The + ``fd (0-63)`` and ``fd envvar WORD`` variants are intended to work with + the shell's ``command 3>something`` and bash's + ``command {ENVVAR}>something`` I/O redirection specifiers. + + Only file descriptors open at a daemon's startup time can be used for + this; accidental misuse of a file descriptor that has been opened by + FRR itself is prevented. + + Using FIFOs with this option will work but is unsupported and can cause + daemons to hang or crash depending on reader behavior. + + Format defaults to RFC5424 if none is specified. + + .. note:: + + When starting FRR daemons from custom shell scripts, make sure not + to leak / leave extraneous file descriptors open. FRR daemons do not + close these. + +.. clicmd:: destination file PATH \ + [create [{user WORD|group WORD|mode PERMS}]|no-create] \ + [format FORMAT] + + Log to a regular file. File permissions can be specified when FRR creates + the file itself. + + Format defaults to RFC5424 if none is specified. + + .. note:: + + FRR will never change permissions or ownership on an existing log file. + In many cases, FRR will also not have permissions to set user and group + arbitrarily. + +.. clicmd:: destination unix PATH [format FORMAT] + + Connect to a UNIX domain socket and send log messages there. This will + autodetect ``SOCK_STREAM``, ``SOCK_SEQPACKET`` and ``SOCK_DGRAM`` and + adjust behavior appropriately. + +Options +------- + +.. clicmd:: priority PRIORITY + + Select minimum priority of messages to send to this target. Defaults to + `debugging`. + +.. clicmd:: facility FACILITY + + Select syslog facility for messages on this target. Defaults to `daemon`. + The :clicmd:`log facility [FACILITY]` command does not affect extended + targets. + +.. clicmd:: timestamp precision (0-9) + + Set desired number of sub-second timestamp digits. This only has an effect + for RFC5424 and journald format targets; the RFC3164 and local-syslogd + formats do not support any sub-second digits. + +.. clicmd:: timestamp local-time + + Use the local system timezone for timestamps rather than UTC (the default.) + + RFC5424 and journald formats include zone information (``Z`` or ``+-NN:NN`` + suffix in ISO8601). RFC3164 and local-syslogd offer no way of identifying + the time zone used, care must be taken that this option and the receiver + are configured identically, or the timestamp is replaced at the receiver. + + .. note:: + + FRR includes a timestamp in journald messages, but journald always + provides its own timestamp. + +.. clicmd:: structured-data + + Select additional key/value data to be included for the RFC5424 and journald + formats. Refer to the next section for details. + + ``unique-id`` and ``error-category`` are enabled by default. + + .. warning:: + + Log messages can grow in size significantly when enabling additional + data. + + +Structured data +--------------- + +When using the RFC5424 or journald formats, FRR can provide additional metadata +for log messages as key/value pairs. The following information can be added +in this way: + ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| Switch | 5424 group | 5424 item(s) | journald field | Contents | ++====================+====================+==============+==================+=============================================+ +| always active | ``location@50145`` | ``tid`` | ``TID`` | Thread ID | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| always active | ``location@50145`` | ``instance`` | ``FRR_INSTANCE`` | Multi-instance number | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| ``unique-id`` | ``location@50145`` | ``id`` | ``FRR_ID`` | ``XXXXX-XXXXX`` unique message identifier | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| ``error-category`` | ``location@50145`` | ``ec`` | ``FRR_EC`` | Integer error category number | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| ``code-location`` | ``location@50145`` | ``file`` | ``CODE_FILE`` | Source code file name | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| ``code-location`` | ``location@50145`` | ``line`` | ``CODE_LINE`` | Source code line number | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| ``code-location`` | ``location@50145`` | ``func`` | ``CODE_FUNC`` | Source code function name | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| ``format-args`` | ``args@50145`` | ``argN`` | ``FRR_ARGn`` | Message printf format arguments (n = 1..16) | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ +| ``version`` | ``origin`` | multiple | n/a | FRR version information (IETF format) | ++--------------------+--------------------+--------------+------------------+---------------------------------------------+ + +The information added by ``version`` is +``[origin enterpriseId="50145" software="FRRouting" swVersion="..."]`` +and is the same for all log messages. (Hence makes little sense to include in +most scenarios.) 50145 is the FRRouting IANA Enterprise Number. + +Crashlogs / backtraces do not include any additional information since it +cannot safely be retrieved from a crash handler. However, all of the above +destinations will deliver crashlogs. + + +Restart and Reconfiguration caveats +----------------------------------- + +FRR uses "add-delete" semantics when reconfiguring log targets of any type +(including both extended targets mentioned here as well as the global +:clicmd:`log stdout LEVEL` and :clicmd:`log syslog [LEVEL]` variants.) This +means that when changing logging configuration, log messages from threads +executing in parallel may be duplicated for a brief window of time. + +For the ``unix``, ``syslog`` and ``journald`` extended destinations, messages +can be lost when the receiver is restarted without the use of socket +activation (i.e. keeping the receiver socket open.) FRR does not buffer +log messages for later delivery, meaning anything logged while the receiver +is unavailable is lost. Since systemd provides socket activation for +journald, no messages will be lost on the ``journald`` target. diff --git a/doc/user/index.rst b/doc/user/index.rst index 7b9464668..5a018a558 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -22,6 +22,7 @@ Basics :maxdepth: 2 basic + extlog vtysh grpc filter @@ -53,6 +54,7 @@ Protocols ospf6d pathd pim + pimv6 pbr ripd ripngd diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 5d53f60f9..d2859670d 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -272,7 +272,7 @@ ISIS interface Showing ISIS information ======================== -.. clicmd:: show isis summary +.. clicmd:: show isis [vrf ] summary [json] Show summary information about ISIS. @@ -280,17 +280,17 @@ Showing ISIS information Show information about ISIS node. -.. clicmd:: show isis interface [detail] [IFNAME] +.. clicmd:: show isis [vrf ] interface [detail] [IFNAME] [json] Show state and configuration of ISIS specified interface, or all interfaces if no interface is given with or without details. -.. clicmd:: show isis neighbor [detail] [SYSTEMID] +.. clicmd:: show isis [vrf ] neighbor [detail] [SYSTEMID] [json] Show state and information of ISIS specified neighbor, or all neighbors if no system id is given with or without details. -.. clicmd:: show isis database [detail] [LSPID] +.. clicmd:: show isis [vrf ] database [detail] [LSPID] [json] Show the ISIS database globally, for a specific LSP id without or with details. @@ -396,13 +396,6 @@ Known limitations: may not exceed 65535. Optionally sets also the Segment Routing Local Block. The negative command always unsets both. -.. clicmd:: segment-routing local-block (16-1048575) (16-1048575) - - Set the Segment Routing Local Block i.e. the label range used by MPLS - to store label in the MPLS FIB for Adjacency SID. Note that the block size - may not exceed 65535. This command is deprecated in favor of the combined - 'segment-routing global-block A B local-block C D' command. - .. clicmd:: segment-routing node-msd (1-16) Set the Maximum Stack Depth supported by the router. The value depend of the diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 624510323..8dacb9c9d 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -383,6 +383,256 @@ Graceful Restart This is an EXEC-level command. +.. _Authentication-trailer: + +Authentication trailer support: +=============================== +IPv4 version of OSPF supports authentication as part of the base RFC. +When IPv6 version of OSPF was developed there was IPSec support for IPv6, +Hence OSPFv3(IPv6 version of OSPF) suggest to use IPSec as authentication +and encryption mechanism. IPSec supports authentication using AH header and +Encryption using ESP. + +There are few disadvantages of using IPSec with OSPFv3. + 1. If encryption is enabled for OSPFv3 packets, then its not + possible to give priority to control packets. + 2. IPSec has platform dependency and may not be supported + in all platforms. + 3. It is performance intensive. + 4. Its difficult to configure. + + +Some advantages of OSPFv3 authentication trailer feature. + 1. It provides replay protection via sequence number. + 2. It provides IPv6 source address protection. + 3. No platform dependency. + 4. Easy to implement and maintain. + + +This feature is support for ``RFC7166``. + +FRR supports MD5 and SHA256 internally and relays on openssl for other hash +algorithms. If user wants to use only MD5 and SHA256, no special action is +required. If user wants complete support of authentication trailer with all +hash algorithms follow below steps. + + +Installing Dependencies: +------------------------ + +.. code-block:: console + + sudo apt update + sudo apt-get install openssl + + +Compile: +-------- +Follow normal compilation as mentioned in the build page. If you want to +use all the hash algorithms then follow the steps mentioned in note before +compiling. + + +.. note:: + + If your platform supports ``openssl``, please make sure to add + ``--with-crypto=openssl`` to your configure options. + Default value is ``--with-crypto=internal`` + + +CLI Configuration: +------------------ +There are two ways in which authentication trailer can be configured for +OSPFv3. These commands are mutually exclusive, only one can be configured +at any time. + + 1. Using manual key configuration. + 2. Using keychain. + + +List of hash algorithms supported: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Without openssl: +++++++++++++++++ + ``MD5`` + ``HMAC-SHA-256`` + + +With openssl: ++++++++++++++ + ``MD5`` + ``HMAC-SHA-1`` + ``HMAC-SHA-256`` + ``HMAC-SHA-384`` + ``HMAC-SHA-512`` + + +Example configuration of manual key: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Without openssl: +++++++++++++++++ + +.. clicmd:: ipv6 ospf6 authentication key-id (1-65535) hash-algo key WORD + +With openssl: ++++++++++++++ + +.. clicmd:: ipv6 ospf6 authentication key-id (1-65535) hash-algo key WORD + + +Example configuration of keychain: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. clicmd:: ipv6 ospf6 authentication keychain KEYCHAIN_NAME + + +Running configuration: +---------------------- + +Manual key: +^^^^^^^^^^^ + +.. code-block:: frr + + frr# show running-config + Building configuration... + + Current configuration: + ! + interface ens192 + ipv6 address 2001:DB8::2/64 + ipv6 ospf6 authentication key-id 10 hash-algo hmac-sha-256 key abhinay + +Keychain: +^^^^^^^^^ + +.. code-block:: frr + + frr# show running-config + Building configuration... + + Current configuration: + ! + interface ens192 + ipv6 address 2001:DB8::2/64 + ipv6 ospf6 authentication keychain abhinay + + +Example keychain config: +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: frr + + frr#show running-config + Building configuration... + + Current configuration: + ! + key chain abcd + key 100 + key-string password + cryptographic-algorithm sha1 + exit + key 200 + key-string password + cryptographic-algorithm sha256 + exit + ! + key chain pqr + key 300 + key-string password + cryptographic-algorithm sha384 + exit + key 400 + key-string password + cryptographic-algorithm sha384 + exit + ! + +Show commands: +-------------- +There is an interface show command that displays if authentication trailer +is enabled or not. json output is also supported. + +There is support for drop counters, which will help in debugging the feature. + +.. code-block:: frr + + frr# show ipv6 ospf6 interface ens192 + ens192 is up, type BROADCAST + Interface ID: 5 + Number of I/F scoped LSAs is 2 + 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off] + 0 Pending LSAs for LSAck in Time 00:00:00 [thread off] + Authentication trailer is enabled with manual key ==> new info added + Packet drop Tx 0, Packet drop Rx 0 + + +OSPFv3 supports options in hello and database description packets hence +the presence of authentication trailer needs to be stored in OSPFv3 +neighbor info. Since RFC specifies that we need to handled sequence number +for every ospf6 packet type, sequence number recvd in authentication header +from the neighbor is stored in neighbor to validate the packet. +json output is also supported. + +.. code-block:: frr + + frr# show ipv6 ospf6 neighbor 2.2.2.2 detail + Neighbor 2.2.2.2%ens192 + Area 1 via interface ens192 (ifindex 3) + 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off] + 0 Pending LSAs for LSAck in Time 00:00:00 [thread off] + Authentication header present ==> new info added + hello DBDesc LSReq LSUpd LSAck + Higher sequence no 0x0 0x0 0x0 0x0 0x0 + Lower sequence no 0x242E 0x1DC4 0x1DC3 0x23CC 0x1DDA + +Sent packet sequence number is maintained per ospf6 router for every packet +that is sent out of router, so sequence number is maintained per ospf6 process. + +.. code-block:: frr + + frr# show ipv6 ospf6 + OSPFv3 Routing Process (0) with Router-ID 2.2.2.2 + Number of areas in this router is 1 + Authentication Sequence number info + Higher sequence no 3, Lower sequence no 1656 + +Debug command: +-------------- +Below command can be used to enable ospfv3 authentication trailer +specific logs if you have to debug the feature. + +.. clicmd:: debug ospf6 authentication [] + +Feature supports authentication trailer tx/rx drop counters for debugging, +which can be used to see if packets are getting dropped due to error in +processing authentication trailer information in OSPFv3 packet. +json output is also supported. + +.. code-block:: frr + + frr# show ipv6 ospf6 interface ens192 + ens192 is up, type BROADCAST + Interface ID: 5 + Number of I/F scoped LSAs is 2 + 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off] + 0 Pending LSAs for LSAck in Time 00:00:00 [thread off] + Authentication trailer is enabled with manual key + Packet drop Tx 0, Packet drop Rx 0 ==> new counters + +Clear command: +-------------- +Below command can be used to clear the tx/rx drop counters in interface. +Below command can be used to clear all ospfv3 interface or specific +interface by specifying the interface name. + +.. clicmd:: clear ipv6 ospf6 auth-counters interface [IFNAME] + + + .. _showing-ospf6-information: Showing OSPF6 information @@ -431,7 +681,7 @@ Showing OSPF6 information .. clicmd:: show ipv6 ospf6 [vrf ] interface traffic [json] - Shows counts of different packets that have been recieved and transmitted + Shows counts of different packets that have been received and transmitted by the interfaces. JSON output can be obtained by appending "json" at the end. diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 91e823e7a..d1a0bb6f7 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -268,8 +268,10 @@ To start OSPF process you have to specify the OSPF router. the destination prefix. Otherwise, we test whether the network command prefix contains the local address prefix of the interface. - In some cases it may be more convenient to enable OSPF on a per - interface/subnet basis (:clicmd:`ip ospf area AREA [ADDR]`). + It is also possible to enable OSPF on a per interface/subnet basis + using the interface command (:clicmd:`ip ospf area AREA [ADDR]`). + However, mixing both network commands (:clicmd:`network`) and interface + commands (:clicmd:`ip ospf`) on the same router is not supported. .. clicmd:: proactive-arp @@ -313,9 +315,9 @@ To start OSPF process you have to specify the OSPF router. Areas ----- -.. clicmd:: area A.B.C.D range A.B.C.D/M +.. clicmd:: area A.B.C.D range A.B.C.D/M [advertise [cost (0-16777215)]] -.. clicmd:: area (0-4294967295) range A.B.C.D/M +.. clicmd:: area (0-4294967295) range A.B.C.D/M [advertise [cost (0-16777215)]] @@ -337,14 +339,18 @@ Areas announced into backbone area if area 0.0.0.10 contains at least one intra-area network (i.e. described with router or network LSA) from this range. -.. clicmd:: area A.B.C.D range IPV4_PREFIX not-advertise +.. clicmd:: area A.B.C.D range A.B.C.D/M not-advertise + +.. clicmd:: area (0-4294967295) range A.B.C.D/M not-advertise Instead of summarizing intra area paths filter them - i.e. intra area paths from this range are not advertised into other areas. This command makes sense in ABR only. -.. clicmd:: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX +.. clicmd:: area A.B.C.D range A.B.C.D/M {substitute A.B.C.D/M|cost (0-16777215)} + +.. clicmd:: area (0-4294967295) range A.B.C.D/M {substitute A.B.C.D/M|cost (0-16777215)} Substitute summarized prefix with another prefix. @@ -360,6 +366,11 @@ Areas One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (i.e. described with router-LSA or network-LSA) from range 10.0.0.0/8. + + By default, the metric of the summary route is calculated as the highest + metric among the summarized routes. The `cost` option, however, can be used + to set an explicit metric. + This command makes sense in ABR only. .. clicmd:: area A.B.C.D virtual-link A.B.C.D @@ -506,12 +517,14 @@ Interfaces Enable OSPF on the interface, optionally restricted to just the IP address - given by `ADDR`, putting it in the `AREA` area. Per interface area settings - take precedence to network commands - (:clicmd:`network A.B.C.D/M area A.B.C.D`). - - If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF - via this command may result in a slight performance improvement. + given by `ADDR`, putting it in the `AREA` area. If you have a lot of + interfaces, and/or a lot of subnets, then enabling OSPF via this command + instead of (:clicmd:`network A.B.C.D/M area A.B.C.D`) may result in a + slight performance improvement. + + Notice that, mixing both network commands (:clicmd:`network`) and interface + commands (:clicmd:`ip ospf`) on the same router is not supported. + If (:clicmd:`ip ospf`) is present, (:clicmd:`network`) commands will fail. .. clicmd:: ip ospf authentication-key AUTH_KEY diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 1b418a434..30363dfdf 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -176,7 +176,7 @@ Certain signals have special meanings to *pimd*. Generate IGMP query (v2/v3) on user requirement. This will not depend on the existing IGMP general query timer.If no version is provided in the cli, - it will be considered as default v2 query.This is a hidden command. + the default will be the igmp version enabled on that interface. .. clicmd:: ip igmp watermark-warn (1-65535) @@ -393,7 +393,7 @@ cause great confusion. Display IGMP group retransmission information. -.. clicmd:: show ip igmp sources +.. clicmd:: show ip igmp [vrf NAME] sources [json] Display IGMP sources information. @@ -452,6 +452,7 @@ cause great confusion. .. clicmd:: show ip pim assert Display information about asserts in the PIM system for S,G mroutes. + This command does not show S,G Channel states that in a NOINFO state. .. clicmd:: show ip pim assert-internal @@ -504,10 +505,12 @@ cause great confusion. Display information about a S,G pair and how the RPF would be chosen. This is especially useful if there are ECMP's available from the RPF lookup. -.. clicmd:: show ip pim rp-info +.. clicmd:: show ip pim [vrf NAME] rp-info [A.B.C.D/M] [json] Display information about RP's that are configured on this router. + You can filter the output by specifying an arbitrary group. + .. clicmd:: show ip pim rpf Display information about currently being used S,G's and their RPF lookup diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst new file mode 100644 index 000000000..e71cf4631 --- /dev/null +++ b/doc/user/pimv6.rst @@ -0,0 +1,288 @@ +.. _pimv6: + +***** +PIMv6 +***** + +PIMv6 -- Protocol Independent Multicast for IPv6 + +*pim6d* supports pim-sm as well as MLD v1 and v2. PIMv6 is +vrf aware and can work within the context of vrf's in order to +do S,G mrouting. + +.. _starting-and-stopping-pim6d: + +Starting and Stopping pim6d +=========================== + +The default configuration file name of *pim6d*'s is :file:`pim6d.conf`. When +invoked *pim6d* searches directory |INSTALL_PREFIX_ETC|. If +:file:`pim6d.conf` is not there then next search current directory. + +*pim6d* requires zebra for proper operation. Additionally *pim6d* depends on +routing properly setup and working in the network that it is working on. + +:: + + # zebra -d + # pim6d -d + + +Please note that *zebra* must be invoked before *pim6d*. + +To stop *pim6d* please use:: + + kill `cat /var/run/pim6d.pid` + +Certain signals have special meanings to *pim6d*. + ++---------+---------------------------------------------------------------------+ +| Signal | Meaning | ++=========+=====================================================================+ +| SIGUSR1 | Rotate the *pim6d* logfile | ++---------+---------------------------------------------------------------------+ +| SIGINT | *pim6d* sweeps all installed PIM mroutes then terminates gracefully.| +| SIGTERM | | ++---------+---------------------------------------------------------------------+ + +*pim6d* invocation options. Common options that can be specified +(:ref:`common-invocation-options`). + +.. clicmd:: ipv6 pim rp X:X::X:X Y:Y::Y:Y/M + + In order to use pimv6, it is necessary to configure a RP for join messages to + be sent to. Currently the only methodology to do this is via static rp + commands. All routers in the pimv6 network must agree on these values. The + first ipv6 address is the RP's address and the second value is the matching + prefix of group ranges covered. This command is vrf aware, to configure for + a vrf, enter the vrf submode. + +.. clicmd:: ipv6 pim rp X:X::X:X prefix-list WORD + + This CLI helps in configuring RP address for a range of groups specified + by the prefix-list. + +.. clicmd:: ipv6 pim rp keep-alive-timer (1-65535) + + Modify the time out value for a S,G flow from 1-65535 seconds at RP. + The normal keepalive period for the KAT(S,G) defaults to 210 seconds. + However, at the RP, the keepalive period must be at least the + Register_Suppression_Time, or the RP may time out the (S,G) state + before the next Null-Register arrives. Thus, the KAT(S,G) is set to + max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. + If choosing a value below 31 seconds be aware that some hardware platforms + cannot see data flowing in better than 30 second chunks. This command is + vrf aware, to configure for a vrf, enter the vrf submode. + +.. clicmd:: ipv6 pim spt-switchover infinity-and-beyond [prefix-list PLIST] + + On the last hop router if it is desired to not switch over to the SPT tree + configure this command. Optional parameter prefix-list can be use to control + which groups to switch or not switch. If a group is PERMIT as per the + PLIST, then the SPT switchover does not happen for it and if it is DENY, + then the SPT switchover happens. + This command is vrf aware, to configure for a vrf, + enter the vrf submode. + +.. clicmd:: ipv6 pim join-prune-interval (1-65535) + + Modify the join/prune interval that pim uses to the new value. Time is + specified in seconds. This command is vrf aware, to configure for a vrf, + enter the vrf submode. The default time is 60 seconds. If you enter + a value smaller than 60 seconds be aware that this can and will affect + convergence at scale. + +.. clicmd:: ipv6 pim keep-alive-timer (1-65535) + + Modify the time out value for a S,G flow from 1-65535 seconds. If choosing + a value below 31 seconds be aware that some hardware platforms cannot see data + flowing in better than 30 second chunks. This command is vrf aware, to + configure for a vrf, enter the vrf submode. + +.. clicmd:: ipv6 pim packets (1-255) + + When processing packets from a neighbor process the number of packets + incoming at one time before moving on to the next task. The default value is + 3 packets. This command is only useful at scale when you can possibly have + a large number of pim control packets flowing. This command is vrf aware, to + configure for a vrf, enter the vrf submode. + +.. clicmd:: ipv6 pim register-suppress-time (1-65535) + + Modify the time that pim will register suppress a FHR will send register + notifications to the kernel. This command is vrf aware, to configure for a + vrf, enter the vrf submode. + +.. _pimv6-interface-configuration: + +PIMv6 Interface Configuration +============================= + +PIMv6 interface commands allow you to configure an interface as either a Receiver +or a interface that you would like to form pimv6 neighbors on. If the interface +is in a vrf, enter the interface command with the vrf keyword at the end. + +.. clicmd:: ipv6 pim active-active + + Turn on pim active-active configuration for a Vxlan interface. This + command will not do anything if you do not have the underlying ability + of a mlag implementation. + +.. clicmd:: ipv6 pim drpriority (1-4294967295) + + Set the DR Priority for the interface. This command is useful to allow the + user to influence what node becomes the DR for a lan segment. + +.. clicmd:: ipv6 pim hello (1-65535) (1-65535) + + Set the pim hello and hold interval for a interface. + +.. clicmd:: ipv6 pim + + Tell pim that we would like to use this interface to form pim neighbors + over. Please note that this command does not enable the reception of MLD + reports on the interface. Refer to the next ``ipv6 mld`` command for MLD + management. + +.. clicmd:: ipv6 pim use-source X:X::X:X + + If you have multiple addresses configured on a particular interface + and would like pim to use a specific source address associated with + that interface. + +.. clicmd:: ipv6 mld + + Tell pim to receive MLD reports and Query on this interface. The default + version is v2. This command is useful on a LHR. + +.. clicmd:: ipv6 mld join X:X::X:X [Y:Y::Y:Y] + + Join multicast group or source-group on an interface. + +.. clicmd:: ipv6 mld query-interval (1-65535) + + Set the MLD query interval that PIM will use. + +.. clicmd:: ipv6 mld query-max-response-time (1-65535) + + Set the MLD query response timeout value. If an report is not returned in + the specified time we will assume the S,G or \*,G has timed out. + +.. clicmd:: ipv6 mld version (1-2) + + Set the MLD version used on this interface. The default value is 2. + +.. clicmd:: ipv6 multicast boundary oil WORD + + Set a PIMv6 multicast boundary, based upon the WORD prefix-list. If a PIMv6 + join or MLD report is received on this interface and the Group is denied by + the prefix-list, PIMv6 will ignore the join or report. + +.. clicmd:: ipv6 mld last-member-query-count (1-255) + + Set the MLD last member query count. The default value is 2. 'no' form of + this command is used to configure back to the default value. + +.. clicmd:: ipv6 MLD last-member-query-interval (1-65535) + + Set the MLD last member query interval in deciseconds. The default value is + 10 deciseconds. 'no' form of this command is used to to configure back to the + default value. + +.. clicmd:: ipv6 mroute INTERFACE X:X::X:X [Y:Y::Y:Y] + + Set a static multicast route for a traffic coming on the current interface to + be forwarded on the given interface if the traffic matches the group address + and optionally the source address. + +.. _show-pimv6-information: + +Show PIMv6 Information +====================== + +All PIMv6 show commands are vrf aware and typically allow you to insert a +specified vrf command if information is desired about a specific vrf. If no +vrf is specified then the default vrf is assumed. Finally the special keyword +'all' allows you to look at all vrfs for the command. Naming a vrf 'all' will +cause great confusion. + +.. clicmd:: show ipv6 pim [vrf NAME] group-type [json] + + Display SSM group ranges. + +.. clicmd:: show ipv6 pim interface + + Display information about interfaces PIM is using. + +.. clicmd:: show ipv6 pim [vrf NAME] join [X:X::X:X [X:X::X:X]] [json] +.. clicmd:: show ipv6 pim vrf all join [json] + + Display information about PIM joins received. If one address is specified + then we assume it is the Group we are interested in displaying data on. + If the second address is specified then it is Source Group. + +.. clicmd:: show ipv6 pim [vrf NAME] local-membership [json] + + Display information about PIM interface local-membership. + +.. clicmd:: show ipv6 pim [vrf NAME] neighbor [detail|WORD] [json] +.. clicmd:: show ipv6 pim vrf all neighbor [detail|WORD] [json] + + Display information about PIM neighbors. + +.. clicmd:: show ipv6 pim [vrf NAME] nexthop + + Display information about pim nexthops that are being used. + +.. clicmd:: show ipv6 pim [vrf NAME] nexthop-lookup X:X::X:X X:X::X:X + + Display information about a S,G pair and how the RPF would be chosen. This + is especially useful if there are ECMP's available from the RPF lookup. + +.. clicmd:: show ipv6 pim [vrf NAME] rp-info [json] +.. clicmd:: show ipv6 pim vrf all rp-info [json] + + Display information about RP's that are configured on this router. + +.. clicmd:: show ipv6 pim [vrf NAME] rpf [json] +.. clicmd:: show ipv6 pim vrf all rpf [json] + + Display information about currently being used S,G's and their RPF lookup + information. Additionally display some statistics about what has been + happening on the router. + +.. clicmd:: show ipv6 pim [vrf NAME] secondary + + Display information about an interface and all the secondary addresses + associated with it. + +.. clicmd:: show ipv6 pim [vrf NAME] state [X:X::X:X [X:X::X:X]] [json] +.. clicmd:: show ipv6 pim vrf all state [X:X::X:X [X:X::X:X]] [json] + + Display information about known S,G's and incoming interface as well as the + OIL and how they were chosen. + +.. clicmd:: show ipv6 pim [vrf NAME] upstream [X:X::X:X [Y:Y::Y:Y]] [json] +.. clicmd:: show ipv6 pim vrf all upstream [json] + + Display upstream information about a S,G mroute. Allow the user to + specify sub Source and Groups that we are interested in. + +.. clicmd:: show ipv6 pim [vrf NAME] upstream-join-desired [json] + + Display upstream information for S,G's and if we desire to + join the multicast tree + +.. clicmd:: show ipv6 pim [vrf NAME] upstream-rpf [json] + + Display upstream information for S,G's and the RPF data associated with them. + +PIMv6 Debug Commands +==================== + +The debugging subsystem for PIMv6 behaves in accordance with how FRR handles +debugging. You can specify debugging at the enable CLI mode as well as the +configure CLI mode. If you specify debug commands in the configuration cli +mode, the debug commands can be persistent across restarts of the FRR pim6d if +the config was written out. + diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index a7f22cd40..ef7aef9c5 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -215,6 +215,18 @@ Route Map Match Command This is a ZEBRA specific match command. The number is a range from (0-255). Matches the originating protocols instance specified. +.. clicmd:: match evpn route-type ROUTE_TYPE_NAME + + This is a BGP EVPN specific match command. It matches to EVPN route-type + from type-1 (EAD route-type) to type-5 (Prefix route-type). + User can provide in an integral form (1-5) or string form of route-type + (i.e ead, macip, multicast, es, prefix). + +.. clicmd:: match evpn vni NUMBER + + This is a BGP EVPN specific match command which matches to EVPN VNI id. + The number is a range from (1-6777215). + .. _route-map-set-command: Route Map Set Command diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index e088c2f75..e9d4e2763 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -139,7 +139,7 @@ keyword. At present, no sharp commands will be preserved in the config. .. clicmd:: sharp import-te - Import Traffic Engineering Database produce by OSPF or IS-IS. + Import Traffic Engineering Database produced by OSPF or IS-IS. .. clicmd:: show sharp ted [verbose|json] @@ -147,6 +147,15 @@ keyword. At present, no sharp commands will be preserved in the config. Show imported Traffic Engineering Data Base +.. clicmd:: show sharp cspf source destination (0-16777215) [rsv-bw (0-7) BANDWIDTH] + + Show the result of a call to the Constraint Shortest Path First (CSPF) + algorithm that allows to compute a path between a source and a + destination under various constraints. Standard Metric, TE Metric, Delay + and Bandwidth are supported constraints. Prior to use this function, it is + necessary to import a Traffic Engineering Database with `sharp import-te` + command (see above). + .. clicmd:: sharp install seg6-routes [vrf NAME] nexthop-seg6 X:X::X:X encap X:X::X:X (1-1000000) This command installs a route for SRv6 Transit behavior (on Linux it is diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 3585245e8..14ace2c85 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -11,6 +11,7 @@ user_RSTFILES = \ doc/user/bugs.rst \ doc/user/conf.py \ doc/user/eigrpd.rst \ + doc/user/extlog.rst \ doc/user/fabricd.rst \ doc/user/filter.rst \ doc/user/frr-reload.rst \ @@ -29,6 +30,7 @@ user_RSTFILES = \ doc/user/packet-dumps.rst \ doc/user/pathd.rst \ doc/user/pim.rst \ + doc/user/pimv6.rst \ doc/user/ripd.rst \ doc/user/pbr.rst \ doc/user/ripngd.rst \ diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst index ec674e377..97b3863ef 100644 --- a/doc/user/vtysh.rst +++ b/doc/user/vtysh.rst @@ -29,6 +29,30 @@ administrator with an external editor. vtysh. +Live logs +========= + +.. clicmd:: terminal monitor [DAEMON] + + Receive and display log messages. + + It is not currently possible to change the minimum message priority (fixed + to debug) or output formatting. These will likely be made configurable in + the future. + + Log messages are received asynchronously and may be printed both during + command execution as well as while on the prompt. They are printed to + stderr, unlike regular CLI output which is printed to stdout. The intent is + that stdin/stdout might be driven by some script while log messages are + visible on stderr. If stdout and stderr are the same file, the prompt and + pending input will be cleared and reprinted appropriately. + + .. note:: + + If ``vtysh`` cannot keep up, some log messages may be lost. The daemons + do **not** wait for, get blocked by, or buffer messages for ``vtysh``. + + Pager usage =========== diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 9ed6b6dd7..221e9c6fe 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -29,6 +29,9 @@ Besides the common invocation options (:ref:`common-invocation-options`), the Zebra, when started, will read in routes. Those routes that Zebra identifies that it was the originator of will be swept in TIME seconds. If no time is specified then we will sweep those routes immediately. + Under the \*BSD's, there is no way to properly store the originating + route and the route types in this case will show up as a static route + with an admin distance of 255. .. option:: -r, --retain @@ -78,6 +81,11 @@ Besides the common invocation options (:ref:`common-invocation-options`), the protocols about route installation/update on ack received from the linux kernel or from offload notification. +.. option:: -s , --nl-bufsize + + Allow zebra to modify the default receive buffer size to SIZE + in bytes. Under \*BSD only the -s option is available. + .. _interface-commands: Configuration Addresses behaviour @@ -1155,7 +1163,9 @@ zebra Terminal Mode Commands .. clicmd:: show zebra Display various statistics related to the installation and deletion - of routes, neighbor updates, and LSP's into the kernel. + of routes, neighbor updates, and LSP's into the kernel. In addition + show various zebra state that is useful when debugging an operator's + setup. .. clicmd:: show zebra client [summary] diff --git a/eigrpd/eigrp_filter.c b/eigrpd/eigrp_filter.c index 69c0d22ae..8d50ed689 100644 --- a/eigrpd/eigrp_filter.c +++ b/eigrpd/eigrp_filter.c @@ -251,13 +251,13 @@ void eigrp_distribute_update_all_wrapper(struct access_list *notused) * * @param[in] thread current execution thread timer is associated with * - * @return int always returns 0 + * @return void * * @par * Called when 10sec waiting time expire and * executes Graceful restart for whole process */ -int eigrp_distribute_timer_process(struct thread *thread) +void eigrp_distribute_timer_process(struct thread *thread) { struct eigrp *eigrp; @@ -265,8 +265,6 @@ int eigrp_distribute_timer_process(struct thread *thread) /* execute GR for whole process */ eigrp_update_send_process_GR(eigrp, EIGRP_GR_FILTER, NULL); - - return 0; } /* @@ -274,13 +272,13 @@ int eigrp_distribute_timer_process(struct thread *thread) * * @param[in] thread current execution thread timer is associated with * - * @return int always returns 0 + * @return void * * @par * Called when 10sec waiting time expire and * executes Graceful restart for interface */ -int eigrp_distribute_timer_interface(struct thread *thread) +void eigrp_distribute_timer_interface(struct thread *thread) { struct eigrp_interface *ei; @@ -289,6 +287,4 @@ int eigrp_distribute_timer_interface(struct thread *thread) /* execute GR for interface */ eigrp_update_send_interface_GR(ei, EIGRP_GR_FILTER, NULL); - - return 0; } diff --git a/eigrpd/eigrp_filter.h b/eigrpd/eigrp_filter.h index 03f45cedb..4dbfe276d 100644 --- a/eigrpd/eigrp_filter.h +++ b/eigrpd/eigrp_filter.h @@ -38,7 +38,7 @@ extern void eigrp_distribute_update(struct distribute_ctx *ctx, extern void eigrp_distribute_update_interface(struct interface *ifp); extern void eigrp_distribute_update_all(struct prefix_list *plist); extern void eigrp_distribute_update_all_wrapper(struct access_list *alist); -extern int eigrp_distribute_timer_process(struct thread *thread); -extern int eigrp_distribute_timer_interface(struct thread *thread); +extern void eigrp_distribute_timer_process(struct thread *thread); +extern void eigrp_distribute_timer_interface(struct thread *thread); #endif /* EIGRPD_EIGRP_FILTER_H_ */ diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c index 2ff8fc5f3..717d8c095 100644 --- a/eigrpd/eigrp_hello.c +++ b/eigrpd/eigrp_hello.c @@ -74,14 +74,14 @@ static const struct message eigrp_general_tlv_type_str[] = { * * @param[in] thread current execution thread timer is associated with * - * @return int always returns 0 + * @return void * * @par * Called once per "hello" time interval, default 5 seconds * Sends hello packet via multicast for all interfaces eigrp * is configured for */ -int eigrp_hello_timer(struct thread *thread) +void eigrp_hello_timer(struct thread *thread) { struct eigrp_interface *ei; @@ -97,8 +97,6 @@ int eigrp_hello_timer(struct thread *thread) /* Hello timer set. */ thread_add_timer(master, eigrp_hello_timer, ei, ei->params.v_hello, &ei->t_hello); - - return 0; } /** diff --git a/eigrpd/eigrp_metric.c b/eigrpd/eigrp_metric.c index ea62f9d1b..7ccafd4fa 100644 --- a/eigrpd/eigrp_metric.c +++ b/eigrpd/eigrp_metric.c @@ -86,19 +86,24 @@ eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp, */ if (eigrp->k_values[0]) - composite += (eigrp->k_values[0] * metric.bandwidth); + composite += ((eigrp_metric_t)eigrp->k_values[0] * + (eigrp_metric_t)metric.bandwidth); if (eigrp->k_values[1]) - composite += ((eigrp->k_values[1] * metric.bandwidth) - / (256 - metric.load)); + composite += (((eigrp_metric_t)eigrp->k_values[1] * + (eigrp_metric_t)metric.bandwidth) / + (256 - metric.load)); if (eigrp->k_values[2]) - composite += (eigrp->k_values[2] * metric.delay); + composite += ((eigrp_metric_t)eigrp->k_values[2] * + (eigrp_metric_t)metric.delay); if (eigrp->k_values[3] && !eigrp->k_values[4]) - composite *= eigrp->k_values[3]; + composite *= (eigrp_metric_t)eigrp->k_values[3]; if (!eigrp->k_values[3] && eigrp->k_values[4]) - composite *= (eigrp->k_values[4] / metric.reliability); + composite *= ((eigrp_metric_t)eigrp->k_values[4] / + (eigrp_metric_t)metric.reliability); if (eigrp->k_values[3] && eigrp->k_values[4]) - composite *= ((eigrp->k_values[4] / metric.reliability) - + eigrp->k_values[3]); + composite *= (((eigrp_metric_t)eigrp->k_values[4] / + (eigrp_metric_t)metric.reliability) + + (eigrp_metric_t)eigrp->k_values[3]); composite = (composite <= EIGRP_METRIC_MAX) ? composite : EIGRP_METRIC_MAX; diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c index f2d5217eb..0ed8927d4 100644 --- a/eigrpd/eigrp_neighbor.c +++ b/eigrpd/eigrp_neighbor.c @@ -189,7 +189,7 @@ void eigrp_nbr_delete(struct eigrp_neighbor *nbr) XFREE(MTYPE_EIGRP_NEIGHBOR, nbr); } -int holddown_timer_expired(struct thread *thread) +void holddown_timer_expired(struct thread *thread) { struct eigrp_neighbor *nbr = THREAD_ARG(thread); struct eigrp *eigrp = nbr->ei->eigrp; @@ -198,8 +198,6 @@ int holddown_timer_expired(struct thread *thread) ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id)); nbr->state = EIGRP_NEIGHBOR_DOWN; eigrp_nbr_delete(nbr); - - return 0; } uint8_t eigrp_nbr_state_get(struct eigrp_neighbor *nbr) diff --git a/eigrpd/eigrp_neighbor.h b/eigrpd/eigrp_neighbor.h index 80ab1eded..693d780f0 100644 --- a/eigrpd/eigrp_neighbor.h +++ b/eigrpd/eigrp_neighbor.h @@ -39,7 +39,7 @@ extern struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *ei, extern struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *ei); extern void eigrp_nbr_delete(struct eigrp_neighbor *neigh); -extern int holddown_timer_expired(struct thread *thread); +extern void holddown_timer_expired(struct thread *thread); extern int eigrp_neighborship_check(struct eigrp_neighbor *neigh, struct TLV_Parameter_Type *tlv); diff --git a/eigrpd/eigrp_network.h b/eigrpd/eigrp_network.h index eeb32ba35..912a9248c 100644 --- a/eigrpd/eigrp_network.h +++ b/eigrpd/eigrp_network.h @@ -35,7 +35,7 @@ extern int eigrp_if_ipmulticast(struct eigrp *, struct prefix *, unsigned int); extern int eigrp_network_set(struct eigrp *eigrp, struct prefix *p); extern int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p); -extern int eigrp_hello_timer(struct thread *); +extern void eigrp_hello_timer(struct thread *thread); extern void eigrp_if_update(struct interface *); extern int eigrp_if_add_allspfrouters(struct eigrp *, struct prefix *, unsigned int); diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index 529d94567..491b2994b 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -320,7 +320,7 @@ int eigrp_check_sha256_digest(struct stream *s, return 1; } -int eigrp_write(struct thread *thread) +void eigrp_write(struct thread *thread) { struct eigrp *eigrp = THREAD_ARG(thread); struct eigrp_header *eigrph; @@ -471,12 +471,10 @@ out: thread_add_write(master, eigrp_write, eigrp, eigrp->fd, &eigrp->t_write); } - - return 0; } /* Starting point of packet process function. */ -int eigrp_read(struct thread *thread) +void eigrp_read(struct thread *thread) { int ret; struct stream *ibuf; @@ -500,7 +498,7 @@ int eigrp_read(struct thread *thread) if (!(ibuf = eigrp_recv_packet(eigrp, eigrp->fd, &ifp, eigrp->ibuf))) { /* This raw packet is known to be at least as big as its IP * header. */ - return -1; + return; } /* Note that there should not be alignment problems with this assignment @@ -531,7 +529,7 @@ int eigrp_read(struct thread *thread) eigrp->vrf_id); if (c == NULL) - return 0; + return; ifp = c->ifp; } @@ -546,7 +544,7 @@ int eigrp_read(struct thread *thread) must remain very accurate in doing this. */ if (!ei) - return 0; + return; /* Self-originated packet should be discarded silently. */ if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) @@ -555,7 +553,7 @@ int eigrp_read(struct thread *thread) zlog_debug( "eigrp_read[%pI4]: Dropping self-originated packet", &srcaddr); - return 0; + return; } /* Advance from IP header to EIGRP header (iph->ip_hl has been verified @@ -574,7 +572,7 @@ int eigrp_read(struct thread *thread) "ignoring packet from router %u sent to %pI4, wrong AS Number received: %u", ntohs(eigrph->vrid), &iph->ip_dst, ntohs(eigrph->ASNumber)); - return 0; + return; } /* If incoming interface is passive one, ignore it. */ @@ -588,7 +586,7 @@ int eigrp_read(struct thread *thread) if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) { eigrp_if_set_multicast(ei); } - return 0; + return; } /* else it must be a local eigrp interface, check it was received on @@ -599,7 +597,7 @@ int eigrp_read(struct thread *thread) zlog_warn( "Packet from [%pI4] received on wrong link %s", &iph->ip_src, ifp->name); - return 0; + return; } /* Verify more EIGRP header fields. */ @@ -609,7 +607,7 @@ int eigrp_read(struct thread *thread) zlog_debug( "eigrp_read[%pI4]: Header check failed, dropping.", &iph->ip_src); - return ret; + return; } /* calcualte the eigrp packet length, and move the pounter to the @@ -700,8 +698,6 @@ int eigrp_read(struct thread *thread) IF_NAME(ei), opcode); break; } - - return 0; } static struct stream *eigrp_recv_packet(struct eigrp *eigrp, @@ -989,7 +985,7 @@ static int eigrp_check_network_mask(struct eigrp_interface *ei, return 0; } -int eigrp_unack_packet_retrans(struct thread *thread) +void eigrp_unack_packet_retrans(struct thread *thread) { struct eigrp_neighbor *nbr; nbr = (struct eigrp_neighbor *)THREAD_ARG(thread); @@ -1005,8 +1001,10 @@ int eigrp_unack_packet_retrans(struct thread *thread) eigrp_fifo_push(nbr->ei->obuf, duplicate); ep->retrans_counter++; - if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) - return eigrp_retrans_count_exceeded(ep, nbr); + if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) { + eigrp_retrans_count_exceeded(ep, nbr); + return; + } /*Start retransmission timer*/ thread_add_timer(master, eigrp_unack_packet_retrans, nbr, @@ -1021,11 +1019,9 @@ int eigrp_unack_packet_retrans(struct thread *thread) thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write); } - - return 0; } -int eigrp_unack_multicast_packet_retrans(struct thread *thread) +void eigrp_unack_multicast_packet_retrans(struct thread *thread) { struct eigrp_neighbor *nbr; nbr = (struct eigrp_neighbor *)THREAD_ARG(thread); @@ -1040,8 +1036,10 @@ int eigrp_unack_multicast_packet_retrans(struct thread *thread) eigrp_fifo_push(nbr->ei->obuf, duplicate); ep->retrans_counter++; - if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) - return eigrp_retrans_count_exceeded(ep, nbr); + if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) { + eigrp_retrans_count_exceeded(ep, nbr); + return; + } /*Start retransmission timer*/ thread_add_timer(master, eigrp_unack_multicast_packet_retrans, @@ -1056,8 +1054,6 @@ int eigrp_unack_multicast_packet_retrans(struct thread *thread) thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write); } - - return 0; } /* Get packet from tail of fifo. */ diff --git a/eigrpd/eigrp_packet.h b/eigrpd/eigrp_packet.h index cb69bc26b..f65917666 100644 --- a/eigrpd/eigrp_packet.h +++ b/eigrpd/eigrp_packet.h @@ -33,8 +33,8 @@ #define _ZEBRA_EIGRP_PACKET_H /*Prototypes*/ -extern int eigrp_read(struct thread *); -extern int eigrp_write(struct thread *); +extern void eigrp_read(struct thread *thread); +extern void eigrp_write(struct thread *thread); extern struct eigrp_packet *eigrp_packet_new(size_t size, struct eigrp_neighbor *nbr); @@ -66,8 +66,8 @@ extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s, extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s, struct eigrp_interface *ei); -extern int eigrp_unack_packet_retrans(struct thread *thread); -extern int eigrp_unack_multicast_packet_retrans(struct thread *thread); +extern void eigrp_unack_packet_retrans(struct thread *thread); +extern void eigrp_unack_multicast_packet_retrans(struct thread *thread); /* * untill there is reason to have their own header, these externs are found in @@ -80,7 +80,7 @@ extern void eigrp_hello_send_ack(struct eigrp_neighbor *nbr); extern void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, struct stream *s, struct eigrp_interface *ei, int size); -extern int eigrp_hello_timer(struct thread *thread); +extern void eigrp_hello_timer(struct thread *thread); /* * These externs are found in eigrp_update.c @@ -96,7 +96,7 @@ extern void eigrp_update_send_all(struct eigrp *eigrp, struct eigrp_interface *exception); extern void eigrp_update_send_init(struct eigrp_neighbor *nbr); extern void eigrp_update_send_EOT(struct eigrp_neighbor *nbr); -extern int eigrp_update_send_GR_thread(struct thread *thread); +extern void eigrp_update_send_GR_thread(struct thread *thread); extern void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type, struct vty *vty); extern void eigrp_update_send_interface_GR(struct eigrp_interface *ei, diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c index 8a9eea8a7..5848632d8 100644 --- a/eigrpd/eigrp_update.c +++ b/eigrpd/eigrp_update.c @@ -910,7 +910,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) * * Uses nbr_gr_packet_type and t_nbr_send_gr from neighbor. */ -int eigrp_update_send_GR_thread(struct thread *thread) +void eigrp_update_send_GR_thread(struct thread *thread) { struct eigrp_neighbor *nbr; @@ -923,7 +923,7 @@ int eigrp_update_send_GR_thread(struct thread *thread) if (nbr->retrans_queue->count > 0) { thread_add_timer_msec(master, eigrp_update_send_GR_thread, nbr, 10, &nbr->t_nbr_send_gr); - return 0; + return; } /* send GR EIGRP packet chunk */ @@ -933,8 +933,6 @@ int eigrp_update_send_GR_thread(struct thread *thread) if (nbr->nbr_gr_packet_type != EIGRP_PACKET_PART_LAST) { thread_execute(master, eigrp_update_send_GR_thread, nbr, 0); } - - return 0; } /** diff --git a/include/linux/netconf.h b/include/linux/netconf.h new file mode 100644 index 000000000..fac4edd55 --- /dev/null +++ b/include/linux/netconf.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_NETCONF_H_ +#define _UAPI_LINUX_NETCONF_H_ + +#include +#include + +struct netconfmsg { + __u8 ncm_family; +}; + +enum { + NETCONFA_UNSPEC, + NETCONFA_IFINDEX, + NETCONFA_FORWARDING, + NETCONFA_RP_FILTER, + NETCONFA_MC_FORWARDING, + NETCONFA_PROXY_NEIGH, + NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, + NETCONFA_INPUT, + NETCONFA_BC_FORWARDING, + __NETCONFA_MAX +}; +#define NETCONFA_MAX (__NETCONFA_MAX - 1) +#define NETCONFA_ALL -1 + +#define NETCONFA_IFINDEX_ALL -1 +#define NETCONFA_IFINDEX_DEFAULT -2 + +#endif /* _UAPI_LINUX_NETCONF_H_ */ diff --git a/include/linux/seg6_local.h b/include/linux/seg6_local.h index 5312de80b..bb5c8ddfc 100644 --- a/include/linux/seg6_local.h +++ b/include/linux/seg6_local.h @@ -26,6 +26,7 @@ enum { SEG6_LOCAL_IIF, SEG6_LOCAL_OIF, SEG6_LOCAL_BPF, + SEG6_LOCAL_VRFTABLE, __SEG6_LOCAL_MAX, }; #define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1) diff --git a/include/subdir.am b/include/subdir.am index 86129c4d6..a06a8e564 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -5,6 +5,7 @@ noinst_HEADERS += \ include/linux/lwtunnel.h \ include/linux/mpls_iptunnel.h \ include/linux/neighbour.h \ + include/linux/netconf.h \ include/linux/netlink.h \ include/linux/nexthop.h \ include/linux/rtnetlink.h \ diff --git a/isisd/fabricd.c b/isisd/fabricd.c index 2937df992..3e0d4ba54 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -250,7 +250,7 @@ void fabricd_finish(struct fabricd *f) hash_free(f->neighbors_neighbors); } -static int fabricd_initial_sync_timeout(struct thread *thread) +static void fabricd_initial_sync_timeout(struct thread *thread) { struct fabricd *f = THREAD_ARG(thread); @@ -258,7 +258,6 @@ static int fabricd_initial_sync_timeout(struct thread *thread) f->initial_sync_circuit->interface->name); f->initial_sync_state = FABRICD_SYNC_PENDING; f->initial_sync_circuit = NULL; - return 0; } void fabricd_initial_sync_hello(struct isis_circuit *circuit) @@ -399,22 +398,21 @@ static uint8_t fabricd_calculate_fabric_tier(struct isis_area *area) return tier; } -static int fabricd_tier_set_timer(struct thread *thread) +static void fabricd_tier_set_timer(struct thread *thread) { struct fabricd *f = THREAD_ARG(thread); fabricd_set_tier(f, f->tier_pending); - return 0; } -static int fabricd_tier_calculation_cb(struct thread *thread) +static void fabricd_tier_calculation_cb(struct thread *thread) { struct fabricd *f = THREAD_ARG(thread); uint8_t tier = ISIS_TIER_UNDEFINED; tier = fabricd_calculate_fabric_tier(f->area); if (tier == ISIS_TIER_UNDEFINED) - return 0; + return; zlog_info("OpenFabric: Got tier %hhu from algorithm. Arming timer.", tier); @@ -423,7 +421,6 @@ static int fabricd_tier_calculation_cb(struct thread *thread) f->area->lsp_gen_interval[ISIS_LEVEL2 - 1], &f->tier_set_timer); - return 0; } static void fabricd_bump_tier_calculation_timer(struct fabricd *f) diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index d75613f30..2729dce38 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -448,7 +448,7 @@ const char *isis_adj_yang_state(enum isis_adj_state state) } } -int isis_adj_expire(struct thread *thread) +void isis_adj_expire(struct thread *thread) { struct isis_adjacency *adj; @@ -461,8 +461,220 @@ int isis_adj_expire(struct thread *thread) /* trigger the adj expire event */ isis_adj_state_change(&adj, ISIS_ADJ_DOWN, "holding time expired"); +} - return 0; +/* + * show isis neighbor [detail] json + */ +void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json, + char detail) +{ + json_object *iface_json, *ipv4_addr_json, *ipv6_link_json, + *ipv6_non_link_json, *topo_json, *dis_flaps_json, + *area_addr_json, *adj_sid_json; + time_t now; + struct isis_dynhn *dyn; + int level; + char buf[256]; + + json_object_string_add(json, "adj", isis_adj_name(adj)); + + if (detail == ISIS_UI_LEVEL_BRIEF) { + if (adj->circuit) + json_object_string_add(json, "interface", + adj->circuit->interface->name); + else + json_object_string_add(json, "interface", + "NULL circuit!"); + json_object_int_add(json, "level", adj->level); + json_object_string_add(json, "state", + adj_state2string(adj->adj_state)); + now = time(NULL); + if (adj->last_upd) { + if (adj->last_upd + adj->hold_time < now) + json_object_string_add(json, "last-upd", + "expiring"); + else + json_object_string_add( + json, "expires-in", + time2string(adj->last_upd + + adj->hold_time - now)); + } + json_object_string_add(json, "snpa", snpa_print(adj->snpa)); + } + + if (detail == ISIS_UI_LEVEL_DETAIL) { + struct sr_adjacency *sra; + struct listnode *anode; + + level = adj->level; + iface_json = json_object_new_object(); + json_object_object_add(json, "interface", iface_json); + if (adj->circuit) + json_object_string_add(iface_json, "name", + adj->circuit->interface->name); + else + json_object_string_add(iface_json, "name", + "null-circuit"); + json_object_int_add(json, "level", adj->level); + json_object_string_add(iface_json, "state", + adj_state2string(adj->adj_state)); + now = time(NULL); + if (adj->last_upd) { + if (adj->last_upd + adj->hold_time < now) + json_object_string_add(iface_json, "last-upd", + "expiring"); + else + json_object_string_add( + json, "expires-in", + time2string(adj->last_upd + + adj->hold_time - now)); + } else + json_object_string_add(json, "expires-in", + time2string(adj->hold_time)); + json_object_int_add(iface_json, "adj-flaps", adj->flaps); + json_object_string_add(iface_json, "last-ago", + time2string(now - adj->last_flap)); + json_object_string_add(iface_json, "circuit-type", + circuit_t2string(adj->circuit_t)); + json_object_string_add(iface_json, "speaks", + nlpid2string(&adj->nlpids)); + if (adj->mt_count != 1 || + adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) { + topo_json = json_object_new_object(); + json_object_object_add(iface_json, "topologies", + topo_json); + for (unsigned int i = 0; i < adj->mt_count; i++) { + snprintfrr(buf, sizeof(buf), "topo-%d", i); + json_object_string_add( + topo_json, buf, + isis_mtid2str(adj->mt_set[i])); + } + } + json_object_string_add(iface_json, "snpa", + snpa_print(adj->snpa)); + if (adj->circuit && + (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) { + dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid); + if (dyn) { + snprintfrr(buf, sizeof(buf), "%s-%02x", + dyn->hostname, + adj->lanid[ISIS_SYS_ID_LEN]); + json_object_string_add(iface_json, "lan-id", + buf); + } else { + snprintfrr(buf, sizeof(buf), "%s-%02x", + sysid_print(adj->lanid), + adj->lanid[ISIS_SYS_ID_LEN]); + json_object_string_add(iface_json, "lan-id", + buf); + } + + json_object_int_add(iface_json, "lan-prio", + adj->prio[adj->level - 1]); + + dis_flaps_json = json_object_new_object(); + json_object_object_add(iface_json, "dis-flaps", + dis_flaps_json); + json_object_string_add( + dis_flaps_json, "dis-record", + isis_disflag2string( + adj->dis_record[ISIS_LEVELS + level - 1] + .dis)); + json_object_int_add(dis_flaps_json, "last", + adj->dischanges[level - 1]); + json_object_string_add( + dis_flaps_json, "ago", + time2string(now - (adj->dis_record[ISIS_LEVELS + + level - 1] + .last_dis_change))); + } + + if (adj->area_address_count) { + area_addr_json = json_object_new_object(); + json_object_object_add(iface_json, "area-address", + area_addr_json); + for (unsigned int i = 0; i < adj->area_address_count; + i++) { + json_object_string_add( + area_addr_json, "isonet", + isonet_print(adj->area_addresses[i] + .area_addr, + adj->area_addresses[i] + .addr_len)); + } + } + if (adj->ipv4_address_count) { + ipv4_addr_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv4-address", + ipv4_addr_json); + for (unsigned int i = 0; i < adj->ipv4_address_count; + i++){ + inet_ntop(AF_INET, &adj->ipv4_addresses[i], buf, + sizeof(buf)); + json_object_string_add(ipv4_addr_json, "ipv4", buf); + } + } + if (adj->ll_ipv6_count) { + ipv6_link_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv6-link-local", + ipv6_link_json); + for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf, + sizeof(buf)); + json_object_string_add(ipv6_link_json, "ipv6", + buf); + } + } + if (adj->global_ipv6_count) { + ipv6_non_link_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv6-global", + ipv6_non_link_json); + for (unsigned int i = 0; i < adj->global_ipv6_count; + i++) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i], + buf, sizeof(buf)); + json_object_string_add(ipv6_non_link_json, + "ipv6", buf); + } + } + + adj_sid_json = json_object_new_object(); + json_object_object_add(iface_json, "adj-sid", adj_sid_json); + for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) { + const char *adj_type; + const char *backup; + uint32_t sid; + + switch (sra->adj->circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + adj_type = "LAN Adjacency-SID"; + sid = sra->u.ladj_sid->sid; + break; + case CIRCUIT_T_P2P: + adj_type = "Adjacency-SID"; + sid = sra->u.adj_sid->sid; + break; + default: + continue; + } + backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)" + : ""; + + json_object_string_add(adj_sid_json, "nexthop", + (sra->nexthop.family == AF_INET) + ? "IPv4" + : "IPv6"); + json_object_string_add(adj_sid_json, "adj-type", + adj_type); + json_object_string_add(adj_sid_json, "is-backup", + backup); + json_object_int_add(adj_sid_json, "sid", sid); + } + } + return; } /* diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index af70775a8..7467a619c 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -141,13 +141,15 @@ void isis_adj_state_change(struct isis_adjacency **adj, enum isis_adj_state state, const char *reason); void isis_adj_print(struct isis_adjacency *adj); const char *isis_adj_yang_state(enum isis_adj_state state); -int isis_adj_expire(struct thread *thread); +void isis_adj_expire(struct thread *thread); void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, char detail); +void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json, + char detail); void isis_adj_build_neigh_list(struct list *adjdb, struct list *list); void isis_adj_build_up_list(struct list *adjdb, struct list *list); int isis_adj_usage2levels(enum isis_adj_usage usage); -int isis_bfd_startup_timer(struct thread *thread); +void isis_bfd_startup_timer(struct thread *thread); const char *isis_adj_name(const struct isis_adjacency *adj); #endif /* ISIS_ADJACENCY_H */ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 1b0447226..da75f196b 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -933,6 +933,151 @@ void circuit_update_nlpids(struct isis_circuit *circuit) return; } +void isis_circuit_print_json(struct isis_circuit *circuit, + struct json_object *json, char detail) +{ + int level; + json_object *iface_json, *ipv4_addr_json, *ipv6_link_json, + *ipv6_non_link_json, *hold_json, *lan_prio_json, *levels_json, + *level_json; + char buf_prx[INET6_BUFSIZ]; + char buf[255]; + + snprintfrr(buf, sizeof(buf), "0x%x", circuit->circuit_id); + if (detail == ISIS_UI_LEVEL_BRIEF) { + iface_json = json_object_new_object(); + json_object_object_add(json, "interface", iface_json); + json_object_string_add(iface_json, "name", + circuit->interface->name); + json_object_string_add(iface_json, "circuit-id", buf); + json_object_string_add(iface_json, "state", + circuit_state2string(circuit->state)); + json_object_string_add(iface_json, "type", + circuit_type2string(circuit->circ_type)); + json_object_string_add(iface_json, "level", + circuit_t2string(circuit->is_type)); + } + + if (detail == ISIS_UI_LEVEL_DETAIL) { + struct listnode *node; + struct prefix *ip_addr; + + iface_json = json_object_new_object(); + json_object_object_add(json, "interface", iface_json); + json_object_string_add(iface_json, "name", + circuit->interface->name); + json_object_string_add(iface_json, "state", + circuit_state2string(circuit->state)); + if (circuit->is_passive) + json_object_string_add(iface_json, "is-passive", + "passive"); + else + json_object_string_add(iface_json, "is-passive", + "active"); + json_object_string_add(iface_json, "circuit-id", buf); + json_object_string_add(iface_json, "type", + circuit_type2string(circuit->circ_type)); + json_object_string_add(iface_json, "level", + circuit_t2string(circuit->is_type)); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + json_object_string_add(iface_json, "snpa", + snpa_print(circuit->u.bc.snpa)); + + + levels_json = json_object_new_array(); + json_object_object_add(iface_json, "levels", levels_json); + for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + if ((circuit->is_type & level) == 0) + continue; + level_json = json_object_new_object(); + json_object_string_add(level_json, "level", + circuit_t2string(level)); + if (circuit->area->newmetric) + json_object_int_add(level_json, "metric", + circuit->te_metric[0]); + else + json_object_int_add(level_json, "metric", + circuit->metric[0]); + if (!circuit->is_passive) { + json_object_int_add(level_json, + "active-neighbors", + circuit->upadjcount[0]); + json_object_int_add(level_json, + "hello-interval", + circuit->hello_interval[0]); + hold_json = json_object_new_object(); + json_object_object_add(level_json, "holddown", + hold_json); + json_object_int_add( + hold_json, "count", + circuit->hello_multiplier[0]); + json_object_string_add( + hold_json, "pad", + (circuit->pad_hellos ? "yes" : "no")); + json_object_int_add(level_json, "cnsp-interval", + circuit->csnp_interval[0]); + json_object_int_add(level_json, "psnp-interval", + circuit->psnp_interval[0]); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + lan_prio_json = + json_object_new_object(); + json_object_object_add(level_json, + "lan", + lan_prio_json); + json_object_int_add( + lan_prio_json, "priority", + circuit->priority[0]); + json_object_string_add( + lan_prio_json, "is-dis", + (circuit->u.bc.is_dr[0] + ? "yes" + : "no")); + } + } + json_object_array_add(levels_json, level_json); + } + + if (circuit->ip_addrs && listcount(circuit->ip_addrs) > 0) { + ipv4_addr_json = json_object_new_object(); + json_object_object_add(iface_json, "ip-prefix", + ipv4_addr_json); + for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, + ip_addr)) { + snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", + ip_addr); + json_object_string_add(ipv4_addr_json, "ip", + buf_prx); + } + } + if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0) { + ipv6_link_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv6-link-locals", + ipv6_link_json); + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, + ip_addr)) { + snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", + ip_addr); + json_object_string_add(ipv6_link_json, "ipv6", + buf_prx); + } + } + if (circuit->ipv6_non_link && + listcount(circuit->ipv6_non_link) > 0) { + ipv6_non_link_json = json_object_new_object(); + json_object_object_add(iface_json, "ipv6-prefixes", + ipv6_non_link_json); + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, + ip_addr)) { + snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", + ip_addr); + json_object_string_add(ipv6_non_link_json, + "ipv6", buf_prx); + } + } + } + return; +} + void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty, char detail) { diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 746578084..5ff0390c2 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -206,6 +206,8 @@ void isis_circuit_down(struct isis_circuit *); void circuit_update_nlpids(struct isis_circuit *circuit); void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty, char detail); +void isis_circuit_print_json(struct isis_circuit *circuit, + struct json_object *json, char detail); size_t isis_circuit_pdu_size(struct isis_circuit *circuit); void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream); diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 089ad5747..c23b0f0dc 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -1559,48 +1559,6 @@ void cli_show_isis_label_blocks(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, "\n"); } -/* - * XPath: /frr-isisd:isis/instance/segment-routing/srlb - */ -DEFPY_HIDDEN( - isis_sr_local_block_label_range, isis_sr_local_block_label_range_cmd, - "segment-routing local-block (16-1048575)$lower_bound (16-1048575)$upper_bound", - SR_STR - "Segment Routing Local Block label range\n" - "The lower bound of the block\n" - "The upper bound of the block (block size may not exceed 65535)\n") -{ -#if CONFDATE > 20220217 -CPP_NOTICE("Use of the local-block command is deprecated") -#endif - nb_cli_enqueue_change(vty, - "./segment-routing/label-blocks/srlb/lower-bound", - NB_OP_MODIFY, lower_bound_str); - nb_cli_enqueue_change(vty, - "./segment-routing/label-blocks/srlb/upper-bound", - NB_OP_MODIFY, upper_bound_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_HIDDEN(no_isis_sr_local_block_label_range, - no_isis_sr_local_block_label_range_cmd, - "no segment-routing local-block [(16-1048575) (16-1048575)]", - NO_STR SR_STR - "Segment Routing Local Block label range\n" - "The lower bound of the block\n" - "The upper bound of the block (block size may not exceed 65535)\n") -{ - nb_cli_enqueue_change(vty, - "./segment-routing/label-blocks/srlb/lower-bound", - NB_OP_MODIFY, NULL); - nb_cli_enqueue_change(vty, - "./segment-routing/label-blocks/srlb/upper-bound", - NB_OP_MODIFY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - /* * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd */ @@ -3189,8 +3147,6 @@ void isis_cli_init(void) install_element(ISIS_NODE, &no_isis_sr_enable_cmd); install_element(ISIS_NODE, &isis_sr_global_block_label_range_cmd); install_element(ISIS_NODE, &no_isis_sr_global_block_label_range_cmd); - install_element(ISIS_NODE, &isis_sr_local_block_label_range_cmd); - install_element(ISIS_NODE, &no_isis_sr_local_block_label_range_cmd); install_element(ISIS_NODE, &isis_sr_node_msd_cmd); install_element(ISIS_NODE, &no_isis_sr_node_msd_cmd); install_element(ISIS_NODE, &isis_sr_prefix_sid_cmd); diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c index e09e23aae..78197974d 100644 --- a/isisd/isis_dr.c +++ b/isisd/isis_dr.c @@ -61,7 +61,7 @@ const char *isis_disflag2string(int disflag) return NULL; /* not reached */ } -int isis_run_dr(struct thread *thread) +void isis_run_dr(struct thread *thread) { struct isis_circuit_arg *arg = THREAD_ARG(thread); @@ -76,7 +76,7 @@ int isis_run_dr(struct thread *thread) zlog_warn("%s: scheduled for non broadcast circuit from %s:%d", __func__, thread->xref->xref.file, thread->xref->xref.line); - return ISIS_WARNING; + return; } if (circuit->u.bc.run_dr_elect[level - 1]) @@ -84,8 +84,6 @@ int isis_run_dr(struct thread *thread) circuit->u.bc.t_run_dr[level - 1] = NULL; circuit->u.bc.run_dr_elect[level - 1] = 1; - - return ISIS_OK; } static int isis_check_dr_change(struct isis_adjacency *adj, int level) diff --git a/isisd/isis_dr.h b/isisd/isis_dr.h index 5cab985d4..f01a03f37 100644 --- a/isisd/isis_dr.h +++ b/isisd/isis_dr.h @@ -24,7 +24,7 @@ #ifndef _ZEBRA_ISIS_DR_H #define _ZEBRA_ISIS_DR_H -int isis_run_dr(struct thread *thread); +void isis_run_dr(struct thread *thread); int isis_dr_elect(struct isis_circuit *circuit, int level); int isis_dr_resign(struct isis_circuit *circuit, int level); int isis_dr_commence(struct isis_circuit *circuit, int level); diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index ade6e8222..8d76e8193 100644 --- a/isisd/isis_dynhn.c +++ b/isisd/isis_dynhn.c @@ -42,7 +42,7 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_DYNHN, "ISIS dyn hostname"); -static int dyn_cache_cleanup(struct thread *); +static void dyn_cache_cleanup(struct thread *); void dyn_cache_init(struct isis *isis) { @@ -67,7 +67,7 @@ void dyn_cache_finish(struct isis *isis) list_delete(&isis->dyn_cache); } -static int dyn_cache_cleanup(struct thread *thread) +static void dyn_cache_cleanup(struct thread *thread) { struct listnode *node, *nnode; struct isis_dynhn *dyn; @@ -87,8 +87,6 @@ static int dyn_cache_cleanup(struct thread *thread) thread_add_timer(master, dyn_cache_cleanup, isis, 120, &isis->t_dync_clean); - - return ISIS_OK; } struct isis_dynhn *dynhn_find_by_id(struct isis *isis, const uint8_t *id) diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 26c68db76..fce48fec9 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -209,7 +209,7 @@ void isis_circuit_is_type_set(struct isis_circuit *circuit, int newtype) /* events supporting code */ -int isis_event_dis_status_change(struct thread *thread) +void isis_event_dis_status_change(struct thread *thread) { struct isis_circuit *circuit; @@ -217,15 +217,13 @@ int isis_event_dis_status_change(struct thread *thread) /* invalid arguments */ if (!circuit || !circuit->area) - return 0; + return; if (IS_DEBUG_EVENTS) zlog_debug("ISIS-Evt (%s) DIS status change", circuit->area->area_tag); /* LSP generation again */ lsp_regenerate_schedule(circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); - - return 0; } void isis_event_auth_failure(char *area_tag, const char *error_string, diff --git a/isisd/isis_events.h b/isisd/isis_events.h index 25643f4ed..e6d9af58b 100644 --- a/isisd/isis_events.h +++ b/isisd/isis_events.h @@ -31,7 +31,7 @@ void isis_event_circuit_type_change(struct isis_circuit *circuit, int newtype); /* * Events related to adjacencies */ -int isis_event_dis_status_change(struct thread *thread); +void isis_event_dis_status_change(struct thread *thread); /* * Error events diff --git a/isisd/isis_ldp_sync.c b/isisd/isis_ldp_sync.c index 0c541348d..3c68b8d15 100644 --- a/isisd/isis_ldp_sync.c +++ b/isisd/isis_ldp_sync.c @@ -344,7 +344,7 @@ void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit, bool run_regen) /* * LDP-SYNC holddown timer routines */ -static int isis_ldp_sync_holddown_timer(struct thread *thread) +static void isis_ldp_sync_holddown_timer(struct thread *thread) { struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; @@ -355,7 +355,7 @@ static int isis_ldp_sync_holddown_timer(struct thread *thread) */ circuit = THREAD_ARG(thread); if (circuit->ldp_sync_info == NULL) - return 0; + return; ldp_sync_info = circuit->ldp_sync_info; @@ -366,7 +366,6 @@ static int isis_ldp_sync_holddown_timer(struct thread *thread) circuit->interface->name); isis_ldp_sync_set_if_metric(circuit, true); - return 0; } void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit) diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index 84aac24d5..d515873ec 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -1401,7 +1401,7 @@ static struct rlfa *rlfa_lookup(struct isis_spftree *spftree, return rlfa_tree_find(&spftree->lfa.remote.rlfas, &s); } -static int isis_area_verify_routes_cb(struct thread *thread) +static void isis_area_verify_routes_cb(struct thread *thread) { struct isis_area *area = THREAD_ARG(thread); @@ -1409,8 +1409,6 @@ static int isis_area_verify_routes_cb(struct thread *thread) zlog_debug("ISIS-LFA: updating RLFAs in the RIB"); isis_area_verify_routes(area); - - return 0; } static mpls_label_t rlfa_nexthop_label(struct isis_spftree *spftree, diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 92d329f03..eb7e9e725 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -62,9 +62,9 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP"); -static int lsp_refresh(struct thread *thread); -static int lsp_l1_refresh_pseudo(struct thread *thread); -static int lsp_l2_refresh_pseudo(struct thread *thread); +static void lsp_refresh(struct thread *thread); +static void lsp_l1_refresh_pseudo(struct thread *thread); +static void lsp_l2_refresh_pseudo(struct thread *thread); static void lsp_destroy(struct isis_lsp *lsp); @@ -733,8 +733,48 @@ static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size) } /* this function prints the lsp on show isis database */ -void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost, - struct isis *isis) +void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object *json, + char dynhost, struct isis *isis) +{ + if (json) { + return lsp_print_json(lsp, json, dynhost, isis); + } else { + return lsp_print_vty(lsp, vty, dynhost, isis); + } +} + +void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, + char dynhost, struct isis *isis) +{ + char LSPid[255]; + char age_out[8]; + char b[200]; + json_object *own_json; + char buf[256]; + + lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis); + own_json = json_object_new_object(); + json_object_object_add(json, "lsp", own_json); + json_object_string_add(own_json, "id", LSPid); + json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " "); + json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len); + snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno); + json_object_string_add(json, "seq-number", buf); + snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum); + json_object_string_add(json, "chksum", buf); + if (lsp->hdr.rem_lifetime == 0) { + snprintf(age_out, sizeof(age_out), "(%d)", lsp->age_out); + age_out[7] = '\0'; + json_object_string_add(json, "holdtime", age_out); + } else { + json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime); + } + json_object_string_add( + json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); +} + +void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty, + char dynhost, struct isis *isis) { char LSPid[255]; char age_out[8]; @@ -754,30 +794,40 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost, vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); } -void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost, - struct isis *isis) +void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, + struct json_object *json, char dynhost, + struct isis *isis) { - lsp_print(lsp, vty, dynhost, isis); - if (lsp->tlvs) - vty_multiline(vty, " ", "%s", isis_format_tlvs(lsp->tlvs)); - vty_out(vty, "\n"); + if (json) { + lsp_print_json(lsp, json, dynhost, isis); + if (lsp->tlvs) { + isis_format_tlvs(lsp->tlvs, json); + } + } else { + lsp_print_vty(lsp, vty, dynhost, isis); + if (lsp->tlvs) + vty_multiline(vty, " ", "%s", + isis_format_tlvs(lsp->tlvs, NULL)); + vty_out(vty, "\n"); + } } /* print all the lsps info in the local lspdb */ -int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail, - char dynhost, struct isis *isis) +int lsp_print_all(struct vty *vty, struct json_object *json, + struct lspdb_head *head, char detail, char dynhost, + struct isis *isis) { struct isis_lsp *lsp; int lsp_count = 0; if (detail == ISIS_UI_LEVEL_BRIEF) { frr_each (lspdb, head, lsp) { - lsp_print(lsp, vty, dynhost, isis); + lsp_print_common(lsp, vty, json, dynhost, isis); lsp_count++; } } else if (detail == ISIS_UI_LEVEL_DETAIL) { frr_each (lspdb, head, lsp) { - lsp_print_detail(lsp, vty, dynhost, isis); + lsp_print_detail(lsp, vty, json, dynhost, isis); lsp_count++; } } @@ -1264,7 +1314,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) if (!fragments) { zlog_warn("BUG: could not fragment own LSP:"); log_multiline(LOG_WARNING, " ", "%s", - isis_format_tlvs(tlvs)); + isis_format_tlvs(tlvs, NULL)); isis_free_tlvs(tlvs); return; } @@ -1447,7 +1497,7 @@ static int lsp_regenerate(struct isis_area *area, int level) /* * Something has changed or periodic refresh -> regenerate LSP */ -static int lsp_refresh(struct thread *thread) +static void lsp_refresh(struct thread *thread) { struct lsp_refresh_arg *arg = THREAD_ARG(thread); @@ -1463,7 +1513,7 @@ static int lsp_refresh(struct thread *thread) area->lsp_regenerate_pending[level - 1] = 0; if ((area->is_type & level) == 0) - return ISIS_ERROR; + return; /* * Throttle regeneration of LSPs (but not when BFD signalled a 'down' @@ -1476,13 +1526,13 @@ static int lsp_refresh(struct thread *thread) area->area_tag, level); _lsp_regenerate_schedule(area, level, 0, false, __func__, __FILE__, __LINE__); - return 0; + return; } sched_debug( "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...", area->area_tag, level); - return lsp_regenerate(area, level); + lsp_regenerate(area, level); } int _lsp_regenerate_schedule(struct isis_area *area, int level, @@ -1827,7 +1877,7 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level) /* * Something has changed or periodic refresh -> regenerate pseudo LSP */ -static int lsp_l1_refresh_pseudo(struct thread *thread) +static void lsp_l1_refresh_pseudo(struct thread *thread) { struct isis_circuit *circuit; uint8_t id[ISIS_SYS_ID_LEN + 2]; @@ -1843,13 +1893,13 @@ static int lsp_l1_refresh_pseudo(struct thread *thread) LSP_PSEUDO_ID(id) = circuit->circuit_id; LSP_FRAGMENT(id) = 0; lsp_purge_pseudo(id, circuit, IS_LEVEL_1); - return ISIS_ERROR; + return; } - return lsp_regenerate_pseudo(circuit, IS_LEVEL_1); + lsp_regenerate_pseudo(circuit, IS_LEVEL_1); } -static int lsp_l2_refresh_pseudo(struct thread *thread) +static void lsp_l2_refresh_pseudo(struct thread *thread) { struct isis_circuit *circuit; uint8_t id[ISIS_SYS_ID_LEN + 2]; @@ -1865,10 +1915,10 @@ static int lsp_l2_refresh_pseudo(struct thread *thread) LSP_PSEUDO_ID(id) = circuit->circuit_id; LSP_FRAGMENT(id) = 0; lsp_purge_pseudo(id, circuit, IS_LEVEL_2); - return ISIS_ERROR; + return; } - return lsp_regenerate_pseudo(circuit, IS_LEVEL_2); + lsp_regenerate_pseudo(circuit, IS_LEVEL_2); } int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level) @@ -1973,7 +2023,7 @@ int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level) * Walk through LSPs for an area * - set remaining lifetime */ -int lsp_tick(struct thread *thread) +void lsp_tick(struct thread *thread) { struct isis_area *area; struct isis_lsp *lsp; @@ -2064,8 +2114,6 @@ int lsp_tick(struct thread *thread) && !isis_tx_queue_len(fabricd_init_c->tx_queue)) { fabricd_initial_sync_finish(area); } - - return ISIS_OK; } void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level) diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index cac5f0d73..b13b2a35e 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -65,7 +65,7 @@ DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare); void lsp_db_init(struct lspdb_head *head); void lsp_db_fini(struct lspdb_head *head); -int lsp_tick(struct thread *thread); +void lsp_tick(struct thread *thread); int lsp_generate(struct isis_area *area, int level); #define lsp_regenerate_schedule(area, level, all_pseudo) \ @@ -120,12 +120,19 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno); void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost, char frag, struct isis *isis); -void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost, - struct isis *isis); -void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost, +void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, + struct json_object *json, char dynhost, struct isis *isis); -int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail, - char dynhost, struct isis *isis); +void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty, char dynhost, + struct isis *isis); +void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, + char dynhost, struct isis *isis); +void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, + struct json_object *json, char dynhost, + struct isis *isis); +int lsp_print_all(struct vty *vty, struct json_object *json, + struct lspdb_head *head, char detail, char dynhost, + struct isis *isis); /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set); diff --git a/isisd/isis_nb_notifications.c b/isisd/isis_nb_notifications.c index f219632ac..fd7b1b315 100644 --- a/isisd/isis_nb_notifications.c +++ b/isisd/isis_nb_notifications.c @@ -245,7 +245,7 @@ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit, data = yang_data_new_uint8(xpath_arg, max_area_addrs); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); - data = yang_data_new(xpath_arg, raw_pdu); + data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len); listnode_add(arguments, data); hook_call(isis_hook_max_area_addr_mismatch, circuit, max_area_addrs, @@ -270,7 +270,7 @@ void isis_notif_authentication_type_failure(const struct isis_circuit *circuit, notif_prep_instance_hdr(xpath, area, "default", arguments); notif_prepr_iface_hdr(xpath, circuit, arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); - data = yang_data_new(xpath_arg, raw_pdu); + data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len); listnode_add(arguments, data); hook_call(isis_hook_authentication_type_failure, circuit, raw_pdu, @@ -294,7 +294,7 @@ void isis_notif_authentication_failure(const struct isis_circuit *circuit, notif_prep_instance_hdr(xpath, area, "default", arguments); notif_prepr_iface_hdr(xpath, circuit, arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); - data = yang_data_new(xpath_arg, raw_pdu); + data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len); listnode_add(arguments, data); hook_call(isis_hook_authentication_failure, circuit, raw_pdu, @@ -361,7 +361,7 @@ void isis_notif_reject_adjacency(const struct isis_circuit *circuit, data = yang_data_new_string(xpath_arg, reason); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); - data = yang_data_new(xpath_arg, raw_pdu); + data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len); listnode_add(arguments, data); hook_call(isis_hook_reject_adjacency, circuit, raw_pdu, raw_pdu_len); @@ -384,7 +384,7 @@ void isis_notif_area_mismatch(const struct isis_circuit *circuit, notif_prep_instance_hdr(xpath, area, "default", arguments); notif_prepr_iface_hdr(xpath, circuit, arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); - data = yang_data_new(xpath_arg, raw_pdu); + data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len); listnode_add(arguments, data); hook_call(isis_hook_area_mismatch, circuit, raw_pdu, raw_pdu_len); @@ -467,7 +467,7 @@ void isis_notif_id_len_mismatch(const struct isis_circuit *circuit, data = yang_data_new_uint8(xpath_arg, rcv_id_len); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); - data = yang_data_new(xpath_arg, raw_pdu); + data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len); listnode_add(arguments, data); hook_call(isis_hook_id_len_mismatch, circuit, rcv_id_len, raw_pdu, @@ -495,7 +495,7 @@ void isis_notif_version_skew(const struct isis_circuit *circuit, data = yang_data_new_uint8(xpath_arg, version); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); - data = yang_data_new(xpath_arg, raw_pdu); + data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len); listnode_add(arguments, data); hook_call(isis_hook_version_skew, circuit, version, raw_pdu, @@ -525,7 +525,7 @@ void isis_notif_lsp_error(const struct isis_circuit *circuit, data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); - data = yang_data_new(xpath_arg, raw_pdu); + data = yang_data_new_binary(xpath_arg, raw_pdu, raw_pdu_len); listnode_add(arguments, data); /* ignore offset and tlv_type which cannot be set properly */ diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 0814f3eea..1a54d47f3 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -1793,11 +1793,10 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) return retval; } -int isis_receive(struct thread *thread) +void isis_receive(struct thread *thread) { struct isis_circuit *circuit; uint8_t ssnpa[ETH_ALEN]; - int retval; /* * Get the circuit @@ -1809,20 +1808,22 @@ int isis_receive(struct thread *thread) isis_circuit_stream(circuit, &circuit->rcv_stream); +#if ISIS_METHOD != ISIS_METHOD_BPF + int retval; + retval = circuit->rx(circuit, ssnpa); -#if ISIS_METHOD != ISIS_METHOD_BPF if (retval == ISIS_OK) - retval = isis_handle_pdu(circuit, ssnpa); -#endif //ISIS_METHOD != ISIS_METHOD_BPF + isis_handle_pdu(circuit, ssnpa); +#else // ISIS_METHOD != ISIS_METHOD_BPF + circuit->rx(circuit, ssnpa); +#endif /* * prepare for next packet. */ if (!circuit->is_passive) isis_circuit_prepare(circuit); - - return retval; } /* @@ -2015,7 +2016,7 @@ int send_hello(struct isis_circuit *circuit, int level) return retval; } -static int send_hello_cb(struct thread *thread) +static void send_hello_cb(struct thread *thread) { struct isis_circuit_arg *arg = THREAD_ARG(thread); assert(arg); @@ -2030,30 +2031,29 @@ static int send_hello_cb(struct thread *thread) send_hello(circuit, 1); send_hello_sched(circuit, ISIS_LEVEL1, 1000 * circuit->hello_interval[1]); - return ISIS_OK; + return; } if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn("ISIS-Hello (%s): Trying to send hello on unknown circuit type %d", circuit->area->area_tag, circuit->circ_type); - return ISIS_WARNING; + return; } circuit->u.bc.t_send_lan_hello[level - 1] = NULL; if (!(circuit->is_type & level)) { zlog_warn("ISIS-Hello (%s): Trying to send L%d IIH in L%d-only circuit", circuit->area->area_tag, level, 3 - level); - return ISIS_WARNING; + return; } if (circuit->u.bc.run_dr_elect[level - 1]) isis_dr_elect(circuit, level); - int rv = send_hello(circuit, level); + send_hello(circuit, level); /* set next timer thread */ send_hello_sched(circuit, level, 1000 * circuit->hello_interval[level - 1]); - return rv; } static void _send_hello_sched(struct isis_circuit *circuit, @@ -2209,7 +2209,7 @@ int send_csnp(struct isis_circuit *circuit, int level) circuit->interface->name, stream_get_endp(circuit->snd_stream)); log_multiline(LOG_DEBUG, " ", "%s", - isis_format_tlvs(tlvs)); + isis_format_tlvs(tlvs, NULL)); if (IS_DEBUG_PACKET_DUMP) zlog_dump_data( STREAM_DATA(circuit->snd_stream), @@ -2247,7 +2247,7 @@ int send_csnp(struct isis_circuit *circuit, int level) return ISIS_OK; } -int send_l1_csnp(struct thread *thread) +void send_l1_csnp(struct thread *thread) { struct isis_circuit *circuit; @@ -2265,11 +2265,9 @@ int send_l1_csnp(struct thread *thread) thread_add_timer(master, send_l1_csnp, circuit, isis_jitter(circuit->csnp_interval[0], CSNP_JITTER), &circuit->t_send_csnp[0]); - - return ISIS_OK; } -int send_l2_csnp(struct thread *thread) +void send_l2_csnp(struct thread *thread) { struct isis_circuit *circuit; @@ -2287,8 +2285,6 @@ int send_l2_csnp(struct thread *thread) thread_add_timer(master, send_l2_csnp, circuit, isis_jitter(circuit->csnp_interval[1], CSNP_JITTER), &circuit->t_send_csnp[1]); - - return ISIS_OK; } /* @@ -2372,7 +2368,7 @@ static int send_psnp(int level, struct isis_circuit *circuit) circuit->interface->name, stream_get_endp(circuit->snd_stream)); log_multiline(LOG_DEBUG, " ", "%s", - isis_format_tlvs(tlvs)); + isis_format_tlvs(tlvs, NULL)); if (IS_DEBUG_PACKET_DUMP) zlog_dump_data( STREAM_DATA(circuit->snd_stream), @@ -2405,7 +2401,7 @@ static int send_psnp(int level, struct isis_circuit *circuit) return ISIS_OK; } -int send_l1_psnp(struct thread *thread) +void send_l1_psnp(struct thread *thread) { struct isis_circuit *circuit; @@ -2420,15 +2416,13 @@ int send_l1_psnp(struct thread *thread) thread_add_timer(master, send_l1_psnp, circuit, isis_jitter(circuit->psnp_interval[0], PSNP_JITTER), &circuit->t_send_psnp[0]); - - return ISIS_OK; } /* * 7.3.15.4 action on expiration of partial SNP interval * level 2 */ -int send_l2_psnp(struct thread *thread) +void send_l2_psnp(struct thread *thread) { struct isis_circuit *circuit; @@ -2443,8 +2437,6 @@ int send_l2_psnp(struct thread *thread) thread_add_timer(master, send_l2_psnp, circuit, isis_jitter(circuit->psnp_interval[1], PSNP_JITTER), &circuit->t_send_psnp[1]); - - return ISIS_OK; } /* diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h index 1e70a42f1..b2e43781f 100644 --- a/isisd/isis_pdu.h +++ b/isisd/isis_pdu.h @@ -195,7 +195,7 @@ struct isis_partial_seqnum_hdr { /* * Function for receiving IS-IS PDUs */ -int isis_receive(struct thread *thread); +void isis_receive(struct thread *thread); /* * calling arguments for snp_process () @@ -210,10 +210,10 @@ int isis_receive(struct thread *thread); */ void send_hello_sched(struct isis_circuit *circuit, int level, long delay); int send_csnp(struct isis_circuit *circuit, int level); -int send_l1_csnp(struct thread *thread); -int send_l2_csnp(struct thread *thread); -int send_l1_psnp(struct thread *thread); -int send_l2_psnp(struct thread *thread); +void send_l1_csnp(struct thread *thread); +void send_l2_csnp(struct thread *thread); +void send_l1_psnp(struct thread *thread); +void send_l2_psnp(struct thread *thread); void send_lsp(struct isis_circuit *circuit, struct isis_lsp *lsp, enum isis_tx_type tx_type); void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream); diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 5718b48b9..d5b02f388 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1832,7 +1832,7 @@ void isis_spf_invalidate_routes(struct isis_spftree *tree) tree->route_table_backup->cleanup = isis_route_node_cleanup; } -static int isis_run_spf_cb(struct thread *thread) +static void isis_run_spf_cb(struct thread *thread) { struct isis_spf_run *run = THREAD_ARG(thread); struct isis_area *area = run->area; @@ -1845,7 +1845,7 @@ static int isis_run_spf_cb(struct thread *thread) if (IS_DEBUG_SPF_EVENTS) zlog_warn("ISIS-SPF (%s) area does not share level", area->area_tag); - return ISIS_WARNING; + return; } isis_area_delete_backup_adj_sids(area, level); @@ -1883,8 +1883,6 @@ static int isis_run_spf_cb(struct thread *thread) UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); fabricd_run_spf(area); - - return 0; } static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level) @@ -2685,3 +2683,15 @@ void isis_spf_print(struct isis_spftree *spftree, struct vty *vty) vty_out(vty, " run count : %u\n", spftree->runcount); } +void isis_spf_print_json(struct isis_spftree *spftree, struct json_object *json) +{ + char uptime[MONOTIME_STRLEN]; + time_t cur; + cur = time(NULL); + cur -= spftree->last_run_timestamp; + frrtime_to_interval(cur, uptime, sizeof(uptime)); + json_object_string_add(json, "last-run-elapsed", uptime); + json_object_int_add(json, "last-run-duration-usec", + spftree->last_run_duration); + json_object_int_add(json, "last-run-count", spftree->runcount); +} diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 5b3aa5937..815db7b22 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -75,6 +75,8 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, bool prefix_sid, bool backup); void isis_spf_init(void); void isis_spf_print(struct isis_spftree *spftree, struct vty *vty); +void isis_spf_print_json(struct isis_spftree *spftree, + struct json_object *json); void isis_run_spf(struct isis_spftree *spftree); struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, uint8_t *sysid, diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index 18a727add..91886cbc3 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -1090,7 +1090,7 @@ DEFUN(show_sr_node, show_sr_node_cmd, * * @return 1 on success */ -static int sr_start_label_manager(struct thread *start) +static void sr_start_label_manager(struct thread *start) { struct isis_area *area; @@ -1098,8 +1098,6 @@ static int sr_start_label_manager(struct thread *start) /* re-attempt to start SR & Label Manager connection */ isis_sr_start(area); - - return 1; } /** diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 118bcf780..95fbca17a 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -756,6 +756,7 @@ static int lsp_to_edge_cb(const uint8_t *id, uint32_t metric, bool old_metric, return LSP_ITER_CONTINUE; attr->metric = metric; + SET_FLAG(attr->flags, LS_ATTR_METRIC); /* Get corresponding Edge from Link State Data Base */ edge = get_edge(args->ted, attr); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 9a442e037..d3d59fb43 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -22,6 +22,7 @@ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +#include #include #ifdef CRYPTO_INTERNAL @@ -57,7 +58,8 @@ typedef void (*free_item_func)(struct isis_item *i); typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s, struct sbuf *log, void *dest, int indent); typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent); + struct sbuf *buf, struct json_object *json, + int indent); typedef struct isis_item *(*copy_item_func)(struct isis_item *i); struct tlv_ops { @@ -208,152 +210,430 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid) /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, - struct sbuf *buf, int indent, - uint16_t mtid) + struct sbuf *buf, struct json_object *json, + int indent, uint16_t mtid) { + char aux_buf[255]; + char cnt_buf[255]; /* Standard metrics */ - if (IS_SUBTLV(exts, EXT_ADM_GRP)) - sbuf_push(buf, indent, "Administrative Group: 0x%x\n", - exts->adm_group); + if (IS_SUBTLV(exts, EXT_ADM_GRP)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "0x%x", + exts->adm_group); + json_object_string_add(json, "adm-group", aux_buf); + } else + sbuf_push(buf, indent, "Administrative Group: 0x%x\n", + exts->adm_group); + } if (IS_SUBTLV(exts, EXT_LLRI)) { - sbuf_push(buf, indent, "Link Local ID: %u\n", - exts->local_llri); - sbuf_push(buf, indent, "Link Remote ID: %u\n", - exts->remote_llri); - } - if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) - sbuf_push(buf, indent, "Local Interface IP Address(es): %pI4\n", - &exts->local_addr); - if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) - sbuf_push(buf, indent, - "Remote Interface IP Address(es): %pI4\n", - &exts->neigh_addr); - if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) - sbuf_push(buf, indent, - "Local Interface IPv6 Address(es): %pI6\n", - &exts->local_addr6); - if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) - sbuf_push(buf, indent, - "Remote Interface IPv6 Address(es): %pI6\n", - &exts->neigh_addr6); - if (IS_SUBTLV(exts, EXT_MAX_BW)) - sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", - exts->max_bw); - if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) - sbuf_push(buf, indent, - "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", - exts->max_rsv_bw); + if (json) { + json_object_int_add(json, "link-local-id", + exts->local_llri); + json_object_int_add(json, "link-remote-id", + exts->remote_llri); + } else { + sbuf_push(buf, indent, "Link Local ID: %u\n", + exts->local_llri); + sbuf_push(buf, indent, "Link Remote ID: %u\n", + exts->remote_llri); + } + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) { + if (json) { + inet_ntop(AF_INET, &exts->local_addr, aux_buf, + sizeof(aux_buf)); + json_object_string_add(json, "local-iface-ip", aux_buf); + } else + sbuf_push(buf, indent, + "Local Interface IP Address(es): %pI4\n", + &exts->local_addr); + } + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) { + if (json) { + inet_ntop(AF_INET, &exts->neigh_addr, aux_buf, + sizeof(aux_buf)); + json_object_string_add(json, "remote-iface-ip", + aux_buf); + } else + sbuf_push(buf, indent, + "Remote Interface IP Address(es): %pI4\n", + &exts->neigh_addr); + } + if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) { + if (json) { + inet_ntop(AF_INET6, &exts->local_addr6, aux_buf, + sizeof(aux_buf)); + json_object_string_add(json, "local-iface-ipv6", + aux_buf); + } else + sbuf_push(buf, indent, + "Local Interface IPv6 Address(es): %pI6\n", + &exts->local_addr6); + } + if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) { + if (json) { + inet_ntop(AF_INET6, &exts->neigh_addr6, aux_buf, + sizeof(aux_buf)); + json_object_string_add(json, "remote-iface-ipv6", + aux_buf); + } else + sbuf_push(buf, indent, + "Remote Interface IPv6 Address(es): %pI6\n", + &exts->neigh_addr6); + } + if (IS_SUBTLV(exts, EXT_MAX_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + exts->max_bw); + json_object_string_add(json, "max-bandwith-bytes-sec", + aux_buf); + } else + sbuf_push(buf, indent, + "Maximum Bandwidth: %g (Bytes/sec)\n", + exts->max_bw); + } + if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + exts->max_rsv_bw); + json_object_string_add( + json, "max-res-bandwith-bytes-sec", aux_buf); + } else + sbuf_push( + buf, indent, + "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", + exts->max_rsv_bw); + } if (IS_SUBTLV(exts, EXT_UNRSV_BW)) { - sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); - for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { - sbuf_push(buf, indent + 2, - "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", - j, exts->unrsv_bw[j], - j + 1, exts->unrsv_bw[j + 1]); + if (json) { + struct json_object *unrsv_json; + unrsv_json = json_object_new_object(); + json_object_object_add(json, "unrsv-bandwith-bytes-sec", + unrsv_json); + for (int j = 0; j < MAX_CLASS_TYPE; j += 1) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j); + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + exts->unrsv_bw[j]); + json_object_string_add(unrsv_json, cnt_buf, + aux_buf); + } + } else { + sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); + for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { + sbuf_push( + buf, indent + 2, + "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", + j, exts->unrsv_bw[j], j + 1, + exts->unrsv_bw[j + 1]); + } } } - if (IS_SUBTLV(exts, EXT_TE_METRIC)) - sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", - exts->te_metric); - if (IS_SUBTLV(exts, EXT_RMT_AS)) - sbuf_push(buf, indent, - "Inter-AS TE Remote AS number: %u\n", - exts->remote_as); - if (IS_SUBTLV(exts, EXT_RMT_IP)) - sbuf_push(buf, indent, - "Inter-AS TE Remote ASBR IP address: %pI4\n", - &exts->remote_ip); + if (IS_SUBTLV(exts, EXT_TE_METRIC)) { + if (json) { + json_object_int_add(json, "te-metric", exts->te_metric); + } else + sbuf_push(buf, indent, + "Traffic Engineering Metric: %u\n", + exts->te_metric); + } + if (IS_SUBTLV(exts, EXT_RMT_AS)) { + if (json) { + json_object_int_add(json, "inter-as-te-remote-as", + exts->remote_as); + } else + sbuf_push(buf, indent, + "Inter-AS TE Remote AS number: %u\n", + exts->remote_as); + } + if (IS_SUBTLV(exts, EXT_RMT_IP)) { + if (json) { + inet_ntop(AF_INET6, &exts->remote_ip, aux_buf, + sizeof(aux_buf)); + json_object_string_add( + json, "inter-as-te-remote-asbr-ip", aux_buf); + } else + sbuf_push(buf, indent, + "Inter-AS TE Remote ASBR IP address: %pI4\n", + &exts->remote_ip); + } /* Extended metrics */ - if (IS_SUBTLV(exts, EXT_DELAY)) - sbuf_push(buf, indent, - "%s Average Link Delay: %u (micro-sec)\n", - IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal", - exts->delay); + if (IS_SUBTLV(exts, EXT_DELAY)) { + if (json) { + struct json_object *avg_json; + avg_json = json_object_new_object(); + json_object_object_add(json, "avg-delay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(exts->delay) + ? "Anomalous" + : "Normal"); + json_object_int_add(avg_json, "micro-sec", exts->delay); + } else + sbuf_push(buf, indent, + "%s Average Link Delay: %u (micro-sec)\n", + IS_ANORMAL(exts->delay) ? "Anomalous" + : "Normal", + exts->delay); + } if (IS_SUBTLV(exts, EXT_MM_DELAY)) { - sbuf_push(buf, indent, "%s Min/Max Link Delay: %u / %u (micro-sec)\n", - IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal", - exts->min_delay & TE_EXT_MASK, - exts->max_delay & TE_EXT_MASK); + if (json) { + struct json_object *avg_json; + avg_json = json_object_new_object(); + json_object_object_add(json, "max-min-delay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(exts->min_delay) + ? "Anomalous" + : "Normal"); + snprintfrr(aux_buf, sizeof(aux_buf), "%u / %u", + exts->min_delay & TE_EXT_MASK, + exts->max_delay & TE_EXT_MASK); + json_object_string_add(avg_json, "micro-sec", aux_buf); + + } else + sbuf_push( + buf, indent, + "%s Min/Max Link Delay: %u / %u (micro-sec)\n", + IS_ANORMAL(exts->min_delay) ? "Anomalous" + : "Normal", + exts->min_delay & TE_EXT_MASK, + exts->max_delay & TE_EXT_MASK); } if (IS_SUBTLV(exts, EXT_DELAY_VAR)) { - sbuf_push(buf, indent, - "Delay Variation: %u (micro-sec)\n", - exts->delay_var & TE_EXT_MASK); - } - if (IS_SUBTLV(exts, EXT_PKT_LOSS)) - sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", - IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal", - (float)((exts->pkt_loss & TE_EXT_MASK) - * LOSS_PRECISION)); - if (IS_SUBTLV(exts, EXT_RES_BW)) - sbuf_push(buf, indent, - "Unidir. Residual Bandwidth: %g (Bytes/sec)\n", - exts->res_bw); - if (IS_SUBTLV(exts, EXT_AVA_BW)) - sbuf_push(buf, indent, - "Unidir. Available Bandwidth: %g (Bytes/sec)\n", - exts->ava_bw); - if (IS_SUBTLV(exts, EXT_USE_BW)) - sbuf_push(buf, indent, - "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n", - exts->use_bw); + if (json) { + json_object_int_add(json, "delay-variation-micro-sec", + exts->delay_var & TE_EXT_MASK); + } else + sbuf_push(buf, indent, + "Delay Variation: %u (micro-sec)\n", + exts->delay_var & TE_EXT_MASK); + } + if (IS_SUBTLV(exts, EXT_PKT_LOSS)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + (float)((exts->pkt_loss & TE_EXT_MASK) * + LOSS_PRECISION)); + struct json_object *link_json; + link_json = json_object_new_object(); + json_object_object_add(json, "link-packet-loss", + link_json); + json_object_string_add(link_json, "loss", + IS_ANORMAL(exts->pkt_loss) + ? "Anomalous" + : "Normal"); + json_object_string_add(link_json, "percentaje", + aux_buf); + } else + sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", + IS_ANORMAL(exts->pkt_loss) ? "Anomalous" + : "Normal", + (float)((exts->pkt_loss & TE_EXT_MASK) * + LOSS_PRECISION)); + } + if (IS_SUBTLV(exts, EXT_RES_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + (exts->res_bw)); + json_object_string_add(json, + "unidir-residual-band-bytes-sec", + aux_buf); + } else + sbuf_push( + buf, indent, + "Unidir. Residual Bandwidth: %g (Bytes/sec)\n", + exts->res_bw); + } + if (IS_SUBTLV(exts, EXT_AVA_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + (exts->ava_bw)); + json_object_string_add( + json, "unidir-available-band-bytes-sec", + aux_buf); + } else + sbuf_push( + buf, indent, + "Unidir. Available Bandwidth: %g (Bytes/sec)\n", + exts->ava_bw); + } + if (IS_SUBTLV(exts, EXT_USE_BW)) { + if (json) { + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + (exts->use_bw)); + json_object_string_add(json, + "unidir-utilized-band-bytes-sec", + aux_buf); + } else + sbuf_push( + buf, indent, + "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n", + exts->use_bw); + } /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */ if (IS_SUBTLV(exts, EXT_ADJ_SID)) { struct isis_adj_sid *adj; - for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj; - adj = adj->next) { - sbuf_push( - buf, indent, - "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n", - adj->sid, adj->weight, - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? '1' - : '0', - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? '1' - : '0', - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? '1' - : '0', - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? '1' - : '0', - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? '1' - : '0', - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? '1' - : '0'); - } + if (json) { + struct json_object *arr_adj_json, *flags_json; + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "adj-sid", arr_adj_json); + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; + adj; adj = adj->next) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", + adj->sid); + flags_json = json_object_new_object(); + json_object_int_add(flags_json, "sid", + adj->sid); + json_object_int_add(flags_json, "weight", + adj->weight); + json_object_string_add( + flags_json, "flag-f", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-b", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-v", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-l", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-s", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-p", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, flags_json); + } + } else + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; + adj; adj = adj->next) { + sbuf_push( + buf, indent, + "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n", + adj->sid, adj->weight, + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? '1' + : '0', + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? '1' + : '0'); + } } /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */ if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { struct isis_lan_adj_sid *lan; - - for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; - lan; lan = lan->next) { - continue; - sbuf_push(buf, indent, - "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n" - " Neighbor-ID: %s\n", - lan->sid, lan->weight, - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? '1' - : '0', - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? '1' - : '0', - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? '1' - : '0', - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? '1' - : '0', - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? '1' - : '0', - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? '1' - : '0', - isis_format_id(lan->neighbor_id, 6)); - } + if (json) { + struct json_object *arr_adj_json, *flags_json; + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "lan-adj-sid", + arr_adj_json); + for (lan = (struct isis_lan_adj_sid *) + exts->adj_sid.head; + lan; lan = lan->next) { + if (((mtid == ISIS_MT_IPV4_UNICAST) && + (lan->family != AF_INET)) || + ((mtid == ISIS_MT_IPV6_UNICAST) && + (lan->family != AF_INET6))) + continue; + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", + lan->sid); + flags_json = json_object_new_object(); + json_object_int_add(flags_json, "sid", + lan->sid); + json_object_int_add(flags_json, "weight", + lan->weight); + json_object_string_add( + flags_json, "flag-f", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-b", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-v", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-l", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-s", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add( + flags_json, "flag-p", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, flags_json); + } + } else + + for (lan = (struct isis_lan_adj_sid *) + exts->lan_sid.head; + lan; lan = lan->next) { + if (((mtid == ISIS_MT_IPV4_UNICAST) && + (lan->family != AF_INET)) || + ((mtid == ISIS_MT_IPV6_UNICAST) && + (lan->family != AF_INET6))) + continue; + sbuf_push( + buf, indent, + "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n" + " Neighbor-ID: %s\n", + lan->sid, lan->weight, + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? '1' + : '0', + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? '1' + : '0', + isis_format_id(lan->neighbor_id, 6)); + } } } @@ -880,26 +1160,64 @@ static struct isis_item *copy_item_prefix_sid(struct isis_item *i) } static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; - sbuf_push(buf, indent, "SR Prefix-SID "); - if (sid->flags & ISIS_PREFIX_SID_VALUE) { - sbuf_push(buf, 0, "Label: %u, ", sid->value); + if (json) { + struct json_object *sr_json; + sr_json = json_object_new_object(); + json_object_object_add(json, "sr", sr_json); + if (sid->flags & ISIS_PREFIX_SID_VALUE) { + json_object_int_add(sr_json, "label", sid->value); + } else { + json_object_int_add(sr_json, "index", sid->value); + } + json_object_int_add(sr_json, "alg", sid->algorithm); + json_object_string_add( + sr_json, "readvertised", + ((sid->flags & ISIS_PREFIX_SID_READVERTISED) ? "yes" + : "")); + json_object_string_add( + sr_json, "node", + ((sid->flags & ISIS_PREFIX_SID_NODE) ? "yes" : "")); + json_object_string_add(sr_json, "php", + ((sid->flags & ISIS_PREFIX_SID_NO_PHP) + ? "no-php" + : "php")); + json_object_string_add( + sr_json, "explicit-null", + ((sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL) ? "yes" + : "")); + json_object_string_add( + sr_json, "value", + ((sid->flags & ISIS_PREFIX_SID_VALUE) ? "yes" : "")); + json_object_string_add( + sr_json, "local", + ((sid->flags & ISIS_PREFIX_SID_LOCAL) ? "yes" : "")); + } else { - sbuf_push(buf, 0, "Index: %u, ", sid->value); + sbuf_push(buf, indent, "SR Prefix-SID "); + if (sid->flags & ISIS_PREFIX_SID_VALUE) { + sbuf_push(buf, 0, "Label: %u, ", sid->value); + } else { + sbuf_push(buf, 0, "Index: %u, ", sid->value); + } + sbuf_push(buf, 0, "Algorithm: %hhu, ", sid->algorithm); + sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n", + sid->flags & ISIS_PREFIX_SID_READVERTISED + ? " READVERTISED" + : "", + sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "", + sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" + : " PHP", + sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL + ? " EXPLICIT-NULL" + : "", + sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "", + sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : ""); } - sbuf_push(buf, 0, "Algorithm: %hhu, ", sid->algorithm); - sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n", - sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" - : "", - sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "", - sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" : " PHP", - sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" - : "", - sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "", - sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : ""); } static void free_item_prefix_sid(struct isis_item *i) @@ -977,7 +1295,7 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s, sid.value = stream_getl(s); } - format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, indent + 2); + format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, NULL, indent + 2); append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid)); return 0; } @@ -997,14 +1315,21 @@ static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p) } static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, + int indent) { if (!p) return; char prefixbuf[PREFIX2STR_BUFFER]; - sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n", - prefix2str(p, prefixbuf, sizeof(prefixbuf))); + if (json) { + prefix2str(p, prefixbuf, sizeof(prefixbuf)); + json_object_string_add(json, "ipv6-src-prefix", prefixbuf); + } else { + sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n", + prefix2str(p, prefixbuf, sizeof(prefixbuf))); + } } static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, @@ -1080,7 +1405,8 @@ static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *src, struct isis_item_list *dest); static void format_items_(uint16_t mtid, enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *items, - struct sbuf *buf, int indent); + struct sbuf *buf, struct json_object *json, + int indent); #define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__) static void free_items(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *items); @@ -1124,12 +1450,12 @@ static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs) } static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf, - int indent) + struct json_object *json, int indent) { format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID, - &subtlvs->prefix_sids, buf, indent); + &subtlvs->prefix_sids, buf, json, indent); - format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent); + format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, json, indent); } static void isis_free_subtlvs(struct isis_subtlvs *subtlvs) @@ -1189,12 +1515,18 @@ static struct isis_item *copy_item_area_address(struct isis_item *i) } static void format_item_area_address(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_area_address *addr = (struct isis_area_address *)i; - sbuf_push(buf, indent, "Area Address: %s\n", - isonet_print(addr->addr, addr->len)); + if (json) { + json_object_string_add(json, "area-addr", + isonet_print(addr->addr, addr->len)); + } else { + sbuf_push(buf, indent, "Area Address: %s\n", + isonet_print(addr->addr, addr->len)); + } } static void free_item_area_address(struct isis_item *i) @@ -1251,7 +1583,7 @@ static int unpack_item_area_address(uint16_t mtid, uint8_t len, stream_get(rv->addr, s, rv->len); format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv, - log, indent + 2); + log, NULL, indent + 2); append_item(&tlvs->area_addresses, (struct isis_item *)rv); return 0; out: @@ -1271,12 +1603,21 @@ static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i) } static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i; - sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n", - isis_format_id(r->id, 7), r->metric); + if (json) { + struct json_object *old_json; + old_json = json_object_new_object(); + json_object_object_add(json, "old-reach-style", old_json); + json_object_string_add(old_json, "is-reach", + isis_format_id(r->id, 7)); + json_object_int_add(old_json, "metric", r->metric); + } else + sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n", + isis_format_id(r->id, 7), r->metric); } static void free_item_oldstyle_reach(struct isis_item *i) @@ -1327,7 +1668,7 @@ static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len, stream_forward_getp(s, 3); /* Skip other metrics */ stream_get(rv->id, s, 7); - format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log, + format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv); return 0; @@ -1344,11 +1685,17 @@ static struct isis_item *copy_item_lan_neighbor(struct isis_item *i) } static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i; - sbuf_push(buf, indent, "LAN Neighbor: %s\n", isis_format_id(n->mac, 6)); + if (json) { + json_object_string_add(json, "lan-neighbor", + isis_format_id(n->mac, 6)); + } else + sbuf_push(buf, indent, "LAN Neighbor: %s\n", + isis_format_id(n->mac, 6)); } static void free_item_lan_neighbor(struct isis_item *i) @@ -1389,7 +1736,7 @@ static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len, struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); stream_get(rv->mac, s, 6); - format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->lan_neighbor, (struct isis_item *)rv); return 0; } @@ -1409,10 +1756,23 @@ static struct isis_item *copy_item_lsp_entry(struct isis_item *i) } static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_lsp_entry *e = (struct isis_lsp_entry *)i; + if (json) { + char buf[255]; + struct json_object *lsp_json; + lsp_json = json_object_new_object(); + json_object_object_add(json, "lsp-entry", lsp_json); + json_object_string_add(lsp_json, "id", isis_format_id(e->id, 8)); + snprintfrr(buf,sizeof(buf),"0x%08x",e->seqno); + json_object_string_add(lsp_json, "seq", buf); + snprintfrr(buf,sizeof(buf),"0x%04hx",e->checksum); + json_object_string_add(lsp_json, "chksum", buf); + json_object_int_add(lsp_json, "lifetime", e->checksum); + } else sbuf_push(buf, indent, "LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n", isis_format_id(e->id, 8), e->seqno, e->checksum, @@ -1462,7 +1822,7 @@ static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s, rv->seqno = stream_getl(s); rv->checksum = stream_getw(s); - format_item_lsp_entry(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_lsp_entry(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->lsp_entries, (struct isis_item *)rv); return 0; } @@ -1484,19 +1844,40 @@ static struct isis_item *copy_item_extended_reach(struct isis_item *i) } static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_extended_reach *r = (struct isis_extended_reach *)i; - sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)", - (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", - isis_format_id(r->id, 7), r->metric); - if (mtid != ISIS_MT_IPV4_UNICAST) - sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); - sbuf_push(buf, 0, "\n"); + if (json) { + struct json_object *reach_json; + reach_json = json_object_new_object(); + json_object_object_add(json, "ext-reach", reach_json); + json_object_string_add( + reach_json, "mt-id", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); + json_object_string_add(reach_json, "id", + isis_format_id(r->id, 7)); + json_object_int_add(reach_json, "metric", r->metric); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(reach_json, "mt-name", + isis_mtid2str(mtid)); + + if (r->subtlvs) + format_item_ext_subtlvs(r->subtlvs, NULL, json, + indent + 2, mtid); + } else { + sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", + isis_format_id(r->id, 7), r->metric); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); - if (r->subtlvs) - format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid); + if (r->subtlvs) + format_item_ext_subtlvs(r->subtlvs, buf, NULL, + indent + 2, mtid); + } } static void free_item_extended_reach(struct isis_item *i) @@ -1579,7 +1960,7 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len, } } - format_item_extended_reach(mtid, (struct isis_item *)rv, log, + format_item_extended_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(items, (struct isis_item *)rv); return 0; @@ -1603,11 +1984,20 @@ static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i) } static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i; char prefixbuf[PREFIX2STR_BUFFER]; + if (json) { + struct json_object *old_json; + old_json = json_object_new_object(); + json_object_object_add(json, "old-ip-reach-style", old_json); + json_object_string_add(old_json, "prefix", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); + json_object_int_add(old_json, "metric", r->metric); + } else sbuf_push(buf, indent, "IP Reachability: %s (Metric: %hhu)\n", prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric); @@ -1669,7 +2059,7 @@ static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len, stream_get(&mask, s, 4); rv->prefix.prefixlen = ip_masklen(mask); - format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log, + format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(dest, (struct isis_item *)rv); return 0; @@ -1689,17 +2079,32 @@ static void copy_tlv_protocols_supported(struct isis_protocols_supported *src, } static void format_tlv_protocols_supported(struct isis_protocols_supported *p, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { if (!p || !p->count || !p->protocols) return; - sbuf_push(buf, indent, "Protocols Supported: "); - for (uint8_t i = 0; i < p->count; i++) { - sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]), - (i + 1 < p->count) ? ", " : ""); + if (json) { + struct json_object *protocol_json; + char buf[255]; + + protocol_json = json_object_new_object(); + json_object_object_add(json, "protocols-supported", + protocol_json); + for (uint8_t i = 0; i < p->count; i++) { + snprintfrr(buf, sizeof(buf), "%d", i); + json_object_string_add(protocol_json, buf, + nlpid2str(p->protocols[i])); + } + } else { + sbuf_push(buf, indent, "Protocols Supported: "); + for (uint8_t i = 0; i < p->count; i++) { + sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]), + (i + 1 < p->count) ? ", " : ""); + } + sbuf_push(buf, 0, "\n"); } - sbuf_push(buf, 0, "\n"); } static void free_tlv_protocols_supported(struct isis_protocols_supported *p) @@ -1746,7 +2151,7 @@ static int unpack_tlv_protocols_supported(enum isis_tlv_context context, tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len); stream_get(tlvs->protocols_supported.protocols, s, tlv_len); - format_tlv_protocols_supported(&tlvs->protocols_supported, log, + format_tlv_protocols_supported(&tlvs->protocols_supported, log, NULL, indent + 2); return 0; } @@ -1762,13 +2167,18 @@ static struct isis_item *copy_item_ipv4_address(struct isis_item *i) } static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_ipv4_address *a = (struct isis_ipv4_address *)i; char addrbuf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf); + if (json) { + json_object_string_add(json, "ipv4", addrbuf); + } else { + sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf); + } } static void free_item_ipv4_address(struct isis_item *i) @@ -1809,7 +2219,7 @@ static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len, struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); stream_get(&rv->addr, s, 4); - format_item_ipv4_address(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_ipv4_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->ipv4_address, (struct isis_item *)rv); return 0; } @@ -1826,13 +2236,17 @@ static struct isis_item *copy_item_ipv6_address(struct isis_item *i) } static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_ipv6_address *a = (struct isis_ipv6_address *)i; char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf); + if (json) + json_object_string_add(json, "ipv6", addrbuf); + else + sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf); } static void free_item_ipv6_address(struct isis_item *i) @@ -1873,7 +2287,7 @@ static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len, struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); stream_get(&rv->addr, s, IPV6_MAX_BYTELEN); - format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_ipv6_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->ipv6_address, (struct isis_item *)rv); return 0; } @@ -1890,13 +2304,19 @@ static struct isis_item *copy_item_global_ipv6_address(struct isis_item *i) } static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, + int indent) { struct isis_ipv6_address *a = (struct isis_ipv6_address *)i; char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", addrbuf); + if (json) + json_object_string_add(json, "global-ipv6", addrbuf); + else + sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", + addrbuf); } static void free_item_global_ipv6_address(struct isis_item *i) @@ -1937,7 +2357,7 @@ static int unpack_item_global_ipv6_address(uint16_t mtid, uint8_t len, struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); stream_get(&rv->addr, s, IPV6_MAX_BYTELEN); - format_item_global_ipv6_address(mtid, (struct isis_item *)rv, log, + format_item_global_ipv6_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->global_ipv6_address, (struct isis_item *)rv); return 0; @@ -1956,14 +2376,23 @@ static struct isis_item *copy_item_mt_router_info(struct isis_item *i) } static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; - sbuf_push(buf, indent, "MT Router Info: %s%s%s\n", - isis_mtid2str(info->mtid), - info->overload ? " Overload" : "", - info->attached ? " Attached" : ""); + if (json) { + struct json_object *mt_json; + mt_json = json_object_new_object(); + json_object_object_add(json, "mt", mt_json); + json_object_int_add(mt_json, "mtid", info->mtid); + json_object_string_add(mt_json, "overload", info->overload?"true":"false"); + json_object_string_add(mt_json, "attached", info->attached?"true":"false"); + } else + sbuf_push(buf, indent, "MT Router Info: %s%s%s\n", + isis_mtid2str(info->mtid), + info->overload ? " Overload" : "", + info->attached ? " Attached" : ""); } static void free_item_mt_router_info(struct isis_item *i) @@ -2015,7 +2444,7 @@ static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len, rv->attached = entry & ISIS_MT_AT_MASK; rv->mtid = entry & ISIS_MT_MASK; - format_item_mt_router_info(mtid, (struct isis_item *)rv, log, + format_item_mt_router_info(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->mt_router_info, (struct isis_item *)rv); return 0; @@ -2034,14 +2463,17 @@ static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id) } static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf, - int indent) + struct json_object *json, int indent) { if (!id) return; char addrbuf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf); + if (json) + json_object_string_add(json, "te-router-id", addrbuf); + else + sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf); } static void free_tlv_te_router_id(struct in_addr *id) @@ -2085,7 +2517,7 @@ static int unpack_tlv_te_router_id(enum isis_tlv_context context, tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4); stream_get(tlvs->te_router_id, s, 4); - format_tlv_te_router_id(tlvs->te_router_id, log, indent + 2); + format_tlv_te_router_id(tlvs->te_router_id, log, NULL, indent + 2); return 0; } @@ -2107,22 +2539,46 @@ static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i) } static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i; char prefixbuf[PREFIX2STR_BUFFER]; - sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s", - (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric, - r->down ? " Down" : ""); - if (mtid != ISIS_MT_IPV4_UNICAST) - sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); - sbuf_push(buf, 0, "\n"); - - if (r->subtlvs) { - sbuf_push(buf, indent, " Subtlvs:\n"); - format_subtlvs(r->subtlvs, buf, indent + 4); + if (json) { + struct json_object *ext_json; + ext_json = json_object_new_object(); + json_object_object_add(json, "ext-ip-reach", ext_json); + json_object_string_add( + json, "mt-id", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); + json_object_string_add( + json, "ip-reach", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); + json_object_int_add(json, "ip-reach-metric", r->metric); + json_object_string_add(json, "down", r->down ? "yes" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(json, "mt-name", + isis_mtid2str(mtid)); + if (r->subtlvs) { + struct json_object *subtlv_json; + subtlv_json = json_object_new_object(); + json_object_object_add(json, "subtlvs", subtlv_json); + format_subtlvs(r->subtlvs, NULL, subtlv_json, 0); + } + } else { + sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), + r->metric, r->down ? " Down" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); + + if (r->subtlvs) { + sbuf_push(buf, indent, " Subtlvs:\n"); + format_subtlvs(r->subtlvs, buf, NULL, indent + 4); + } } } @@ -2216,7 +2672,7 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len, if (orig_prefix != rv->prefix.prefix.s_addr) sbuf_push(log, indent + 2, "WARNING: Prefix had hostbits set.\n"); - format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log, + format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) { @@ -2273,12 +2729,15 @@ static char *copy_tlv_dynamic_hostname(const char *hostname) } static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf, - int indent) + struct json_object *json, int indent) { if (!hostname) return; - sbuf_push(buf, indent, "Hostname: %s\n", hostname); + if (json) + json_object_string_add(json, "hostname", hostname); + else + sbuf_push(buf, indent, "Hostname: %s\n", hostname); } static void free_tlv_dynamic_hostname(char *hostname) @@ -2356,14 +2815,18 @@ static struct in6_addr *copy_tlv_te_router_id_ipv6(const struct in6_addr *id) } static void format_tlv_te_router_id_ipv6(const struct in6_addr *id, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { if (!id) return; char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf)); - sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf); + if (json) + json_object_string_add(json, "ipv6-te-router-id", addrbuf); + else + sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf); } static void free_tlv_te_router_id_ipv6(struct in6_addr *id) @@ -2409,7 +2872,7 @@ static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context, tlvs->te_router_id_ipv6 = XCALLOC(MTYPE_ISIS_TLV, IPV6_MAX_BYTELEN); stream_get(tlvs->te_router_id_ipv6, s, IPV6_MAX_BYTELEN); - format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, log, indent + 2); + format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, log, NULL, indent + 2); return 0; } @@ -2429,26 +2892,50 @@ static struct isis_spine_leaf *copy_tlv_spine_leaf( } static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { if (!spine_leaf) return; - sbuf_push(buf, indent, "Spine-Leaf-Extension:\n"); - if (spine_leaf->has_tier) { - if (spine_leaf->tier == ISIS_TIER_UNDEFINED) { - sbuf_push(buf, indent, " Tier: undefined\n"); - } else { - sbuf_push(buf, indent, " Tier: %hhu\n", - spine_leaf->tier); + char aux_buf[255]; + + if (json) { + struct json_object *spine_json; + spine_json = json_object_new_object(); + json_object_object_add(json, "spine-leaf-extension", + spine_json); + if (spine_leaf->has_tier) { + snprintfrr(aux_buf, sizeof(aux_buf), "%hhu", + spine_leaf->tier); + json_object_string_add( + spine_json, "tier", + (spine_leaf->tier == ISIS_TIER_UNDEFINED) + ? "undefined" + : aux_buf); + } + json_object_string_add(spine_json, "flag-leaf", + spine_leaf->is_leaf ? "yes" : ""); + json_object_string_add(spine_json, "flag-spine", + spine_leaf->is_spine ? "yes" : ""); + json_object_string_add(spine_json, "flag-backup", + spine_leaf->is_backup ? "yes" : ""); + } else { + sbuf_push(buf, indent, "Spine-Leaf-Extension:\n"); + if (spine_leaf->has_tier) { + if (spine_leaf->tier == ISIS_TIER_UNDEFINED) { + sbuf_push(buf, indent, " Tier: undefined\n"); + } else { + sbuf_push(buf, indent, " Tier: %hhu\n", + spine_leaf->tier); + } } - } - - sbuf_push(buf, indent, " Flags:%s%s%s\n", - spine_leaf->is_leaf ? " LEAF" : "", - spine_leaf->is_spine ? " SPINE" : "", - spine_leaf->is_backup ? " BACKUP" : ""); + sbuf_push(buf, indent, " Flags:%s%s%s\n", + spine_leaf->is_leaf ? " LEAF" : "", + spine_leaf->is_spine ? " SPINE" : "", + spine_leaf->is_backup ? " BACKUP" : ""); + } } static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf) @@ -2562,25 +3049,45 @@ static struct isis_threeway_adj *copy_tlv_threeway_adj( return rv; } -static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, - struct sbuf *buf, int indent) +static void +format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, + struct sbuf *buf, struct json_object *json, int indent) { if (!threeway_adj) return; - sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n"); - sbuf_push(buf, indent, " State: %s (%d)\n", - isis_threeway_state_name(threeway_adj->state), - threeway_adj->state); - sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n", - threeway_adj->local_circuit_id); - if (!threeway_adj->neighbor_set) - return; + if (json) { + struct json_object *three_json; + three_json = json_object_new_object(); + json_object_object_add(json, "p2p-three-way-adj", three_json); + json_object_string_add( + three_json, "state-name", + isis_threeway_state_name(threeway_adj->state)); + json_object_int_add(three_json, "state", threeway_adj->state); + json_object_int_add(three_json, "ext-local-circuit-id", + threeway_adj->local_circuit_id); + if (!threeway_adj->neighbor_set) + return; + json_object_string_add( + three_json, "neigh-system-id", + isis_format_id(threeway_adj->neighbor_id, 6)); + json_object_int_add(three_json, "neigh-ext-circuit-id", + threeway_adj->neighbor_circuit_id); + } else { + sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n"); + sbuf_push(buf, indent, " State: %s (%d)\n", + isis_threeway_state_name(threeway_adj->state), + threeway_adj->state); + sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n", + threeway_adj->local_circuit_id); + if (!threeway_adj->neighbor_set) + return; - sbuf_push(buf, indent, " Neighbor System ID: %s\n", - isis_format_id(threeway_adj->neighbor_id, 6)); - sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n", - threeway_adj->neighbor_circuit_id); + sbuf_push(buf, indent, " Neighbor System ID: %s\n", + isis_format_id(threeway_adj->neighbor_id, 6)); + sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n", + threeway_adj->neighbor_circuit_id); + } } static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj) @@ -2663,24 +3170,51 @@ static struct isis_item *copy_item_ipv6_reach(struct isis_item *i) } static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i; char prefixbuf[PREFIX2STR_BUFFER]; - sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s", - (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), - r->metric, - r->down ? " Down" : "", - r->external ? " External" : ""); - if (mtid != ISIS_MT_IPV4_UNICAST) - sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); - sbuf_push(buf, 0, "\n"); - - if (r->subtlvs) { - sbuf_push(buf, indent, " Subtlvs:\n"); - format_subtlvs(r->subtlvs, buf, indent + 4); + if (json) { + struct json_object *reach_json; + reach_json = json_object_new_object(); + json_object_object_add(json, "ipv6-reach", reach_json); + json_object_string_add(reach_json, "mt-id", + (mtid == ISIS_MT_IPV4_UNICAST) ? "" + : "mt"); + json_object_string_add( + reach_json, "prefix", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); + json_object_int_add(reach_json, "metric", r->metric); + json_object_string_add(reach_json, "down", + r->down ? "yes" : ""); + json_object_string_add(reach_json, "external", + r->external ? "yes" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(reach_json, "mt-name", + isis_mtid2str(mtid)); + if (r->subtlvs) { + struct json_object *subtlvs_json; + subtlvs_json = json_object_new_object(); + json_object_object_add(json, "subtlvs", subtlvs_json); + format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0); + } + } else { + sbuf_push(buf, indent, + "%sIPv6 Reachability: %s (Metric: %u)%s%s", + (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), + r->metric, r->down ? " Down" : "", + r->external ? " External" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); + + if (r->subtlvs) { + sbuf_push(buf, indent, " Subtlvs:\n"); + format_subtlvs(r->subtlvs, buf, NULL, indent + 4); + } } } @@ -2773,7 +3307,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix))) sbuf_push(log, indent + 2, "WARNING: Prefix had hostbits set.\n"); - format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2); if (control & ISIS_IPV6_REACH_SUBTLV) { consume += 1; @@ -2834,6 +3368,77 @@ static struct isis_router_cap *copy_tlv_router_cap( return rv; } +static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, + struct json_object *json) +{ + char addrbuf[INET_ADDRSTRLEN]; + + if (!router_cap) + return; + + /* Router ID and Flags */ + struct json_object *cap_json; + cap_json = json_object_new_object(); + json_object_object_add(json, "router-capability", cap_json); + inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); + json_object_string_add(cap_json, "id", addrbuf); + json_object_string_add( + cap_json, "flag-d", + router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? "1" : "0"); + json_object_string_add( + cap_json, "flag-s", + router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? "1" : "0"); + + /* Segment Routing Global Block as per RFC8667 section #3.1 */ + if (router_cap->srgb.range_size != 0) { + struct json_object *gb_json; + gb_json = json_object_new_object(); + json_object_object_add(json, "segment-routing-gb", gb_json); + json_object_string_add(gb_json, "ipv4", + IS_SR_IPV4(&router_cap->srgb) ? "1" + : "0"); + json_object_string_add(gb_json, "ipv6", + IS_SR_IPV6(&router_cap->srgb) ? "1" + : "0"); + json_object_int_add(gb_json, "global-block-base", + router_cap->srgb.lower_bound); + json_object_int_add(gb_json, "global-block-range", + router_cap->srgb.range_size); + } + + /* Segment Routing Local Block as per RFC8667 section #3.3 */ + if (router_cap->srlb.range_size != 0) { + struct json_object *lb_json; + lb_json = json_object_new_object(); + json_object_object_add(json, "segment-routing-lb", lb_json); + json_object_int_add(lb_json, "global-block-base", + router_cap->srlb.lower_bound); + json_object_int_add(lb_json, "global-block-range", + router_cap->srlb.range_size); + } + + /* Segment Routing Algorithms as per RFC8667 section #3.2 */ + if (router_cap->algo[0] != SR_ALGORITHM_UNSET) { + char buf[255]; + struct json_object *alg_json; + alg_json = json_object_new_object(); + json_object_object_add(json, "segment-routing-algorithm", + alg_json); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) + if (router_cap->algo[i] != SR_ALGORITHM_UNSET) { + snprintfrr(buf, sizeof(buf), "%d", i); + json_object_string_add(alg_json, buf, + router_cap->algo[i] == 0 + ? "SPF" + : "Strict SPF"); + } + } + + /* Segment Routing Node MSD as per RFC8491 section #2 */ + if (router_cap->msd != 0) + json_object_int_add(json, "msd", router_cap->msd); +} + static void format_tlv_router_cap(const struct isis_router_cap *router_cap, struct sbuf *buf, int indent) { @@ -3007,28 +3612,55 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, type = stream_getc(s); length = stream_getc(s); + + if (length > STREAM_READABLE(s) || length > subtlv_len - 2) { + sbuf_push( + log, indent, + "WARNING: Router Capability subTLV length too large compared to expected size\n"); + stream_forward_getp(s, STREAM_READABLE(s)); + + return 0; + } + switch (type) { case ISIS_SUBTLV_SID_LABEL_RANGE: /* Check that SRGB is correctly formated */ if (length < SUBTLV_RANGE_LABEL_SIZE || length > SUBTLV_RANGE_INDEX_SIZE) { stream_forward_getp(s, length); - continue; + break; } /* Only one SRGB is supported. Skip subsequent one */ if (rcap->srgb.range_size != 0) { stream_forward_getp(s, length); - continue; + break; } rcap->srgb.flags = stream_getc(s); rcap->srgb.range_size = stream_get3(s); /* Skip Type and get Length of SID Label */ stream_getc(s); size = stream_getc(s); - if (size == ISIS_SUBTLV_SID_LABEL_SIZE) + + if (size == ISIS_SUBTLV_SID_LABEL_SIZE + && length != SUBTLV_RANGE_LABEL_SIZE) { + stream_forward_getp(s, length - 6); + break; + } + + if (size == ISIS_SUBTLV_SID_INDEX_SIZE + && length != SUBTLV_RANGE_INDEX_SIZE) { + stream_forward_getp(s, length - 6); + break; + } + + if (size == ISIS_SUBTLV_SID_LABEL_SIZE) { rcap->srgb.lower_bound = stream_get3(s); - else + } else if (size == ISIS_SUBTLV_SID_INDEX_SIZE) { rcap->srgb.lower_bound = stream_getl(s); + } else { + stream_forward_getp(s, length - 6); + break; + } /* SRGB sanity checks. */ if (rcap->srgb.range_size == 0 @@ -3042,9 +3674,12 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, /* Only one range is supported. Skip subsequent one */ size = length - (size + SUBTLV_SR_BLOCK_SIZE); if (size > 0) - stream_forward_getp(s, length); + stream_forward_getp(s, size); + break; case ISIS_SUBTLV_ALGORITHM: + if (length == 0) + break; /* Only 2 algorithms are supported: SPF & Strict SPF */ stream_get(&rcap->algo, s, length > SR_ALGORITHM_COUNT @@ -3059,12 +3694,12 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, if (length < SUBTLV_RANGE_LABEL_SIZE || length > SUBTLV_RANGE_INDEX_SIZE) { stream_forward_getp(s, length); - continue; + break; } /* RFC 8667 section #3.3: Only one SRLB is authorized */ if (rcap->srlb.range_size != 0) { stream_forward_getp(s, length); - continue; + break; } /* Ignore Flags which are not defined */ stream_getc(s); @@ -3072,10 +3707,27 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, /* Skip Type and get Length of SID Label */ stream_getc(s); size = stream_getc(s); - if (size == ISIS_SUBTLV_SID_LABEL_SIZE) + + if (size == ISIS_SUBTLV_SID_LABEL_SIZE + && length != SUBTLV_RANGE_LABEL_SIZE) { + stream_forward_getp(s, length - 6); + break; + } + + if (size == ISIS_SUBTLV_SID_INDEX_SIZE + && length != SUBTLV_RANGE_INDEX_SIZE) { + stream_forward_getp(s, length - 6); + break; + } + + if (size == ISIS_SUBTLV_SID_LABEL_SIZE) { rcap->srlb.lower_bound = stream_get3(s); - else + } else if (size == ISIS_SUBTLV_SID_INDEX_SIZE) { rcap->srlb.lower_bound = stream_getl(s); + } else { + stream_forward_getp(s, length - 6); + break; + } /* SRLB sanity checks. */ if (rcap->srlb.range_size == 0 @@ -3089,13 +3741,14 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, /* Only one range is supported. Skip subsequent one */ size = length - (size + SUBTLV_SR_BLOCK_SIZE); if (size > 0) - stream_forward_getp(s, length); + stream_forward_getp(s, size); + break; case ISIS_SUBTLV_NODE_MSD: /* Check that MSD is correctly formated */ if (length < MSD_TLV_SIZE) { stream_forward_getp(s, length); - continue; + break; } msd_type = stream_getc(s); rcap->msd = stream_getc(s); @@ -3129,26 +3782,40 @@ static struct isis_item *copy_item_auth(struct isis_item *i) } static void format_item_auth(uint16_t mtid, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_auth *auth = (struct isis_auth *)i; char obuf[768]; - sbuf_push(buf, indent, "Authentication:\n"); + if (json) + json_object_string_add(json, "test-auth", "ok"); + else + sbuf_push(buf, indent, "Authentication:\n"); switch (auth->type) { case ISIS_PASSWD_TYPE_CLEARTXT: zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length); - sbuf_push(buf, indent, " Password: %s\n", obuf); + if (json) + json_object_string_add(json, "auth-pass", obuf); + else + sbuf_push(buf, indent, " Password: %s\n", obuf); break; case ISIS_PASSWD_TYPE_HMAC_MD5: for (unsigned int j = 0; j < 16; j++) { - snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, - "%02hhx", auth->value[j]); + snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, "%02hhx", + auth->value[j]); } - sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf); + if (json) + json_object_string_add(json, "auth-hmac-md5", obuf); + else + sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf); break; default: - sbuf_push(buf, indent, " Unknown (%hhu)\n", auth->type); + if (json) + json_object_int_add(json, "auth-unknown", auth->type); + else + sbuf_push(buf, indent, " Unknown (%hhu)\n", + auth->type); break; } } @@ -3222,7 +3889,7 @@ static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s, rv->offset = stream_get_getp(s); stream_get(rv->value, s, rv->length); - format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2); + format_item_auth(mtid, (struct isis_item *)rv, log, NULL, indent + 2); append_item(&tlvs->isis_auth, (struct isis_item *)rv); return 0; } @@ -3246,17 +3913,36 @@ static struct isis_purge_originator *copy_tlv_purge_originator( } static void format_tlv_purge_originator(struct isis_purge_originator *poi, - struct sbuf *buf, int indent) + struct sbuf *buf, + struct json_object *json, int indent) { if (!poi) return; - sbuf_push(buf, indent, "Purge Originator Identification:\n"); - sbuf_push(buf, indent, " Generator: %s\n", - isis_format_id(poi->generator, sizeof(poi->generator))); - if (poi->sender_set) { - sbuf_push(buf, indent, " Received-From: %s\n", - isis_format_id(poi->sender, sizeof(poi->sender))); + if (json) { + struct json_object *purge_json; + purge_json = json_object_new_object(); + json_object_object_add(json, "purge_originator", purge_json); + + json_object_string_add( + purge_json, "id", + isis_format_id(poi->generator, sizeof(poi->generator))); + if (poi->sender_set) { + json_object_string_add( + purge_json, "rec-from", + isis_format_id(poi->sender, + sizeof(poi->sender))); + } + } else { + sbuf_push(buf, indent, "Purge Originator Identification:\n"); + sbuf_push( + buf, indent, " Generator: %s\n", + isis_format_id(poi->generator, sizeof(poi->generator))); + if (poi->sender_set) { + sbuf_push(buf, indent, " Received-From: %s\n", + isis_format_id(poi->sender, + sizeof(poi->sender))); + } } } @@ -3369,12 +4055,12 @@ static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type, static void format_item(uint16_t mtid, enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item *i, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, int indent) { const struct tlv_ops *ops = tlv_table[context][type]; if (ops && ops->format_item) { - ops->format_item(mtid, i, buf, indent); + ops->format_item(mtid, i, buf, json, indent); return; } @@ -3383,12 +4069,13 @@ static void format_item(uint16_t mtid, enum isis_tlv_context context, static void format_items_(uint16_t mtid, enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *items, - struct sbuf *buf, int indent) + struct sbuf *buf, struct json_object *json, + int indent) { struct isis_item *i; for (i = items->head; i; i = i->next) - format_item(mtid, context, type, i, buf, indent); + format_item(mtid, context, type, i, buf, json, indent); } static void free_item(enum isis_tlv_context tlv_context, @@ -3717,12 +4404,12 @@ static void free_mt_items(enum isis_tlv_context context, static void format_mt_items(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_mt_item_list *m, struct sbuf *buf, - int indent) + struct json_object *json, int indent) { struct isis_item_list *n; RB_FOREACH (n, isis_mt_item_list, m) { - format_items_(n->mtid, context, type, n, buf, indent); + format_items_(n->mtid, context, type, n, buf, json, indent); } } @@ -3869,87 +4556,100 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs) return rv; } -static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent) +static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_object *json, int indent) { - format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent); + format_tlv_protocols_supported(&tlvs->protocols_supported, buf, json, + indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf, - indent); + json, indent); - format_tlv_purge_originator(tlvs->purge_originator, buf, indent); + format_tlv_purge_originator(tlvs->purge_originator, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES, - &tlvs->area_addresses, buf, indent); + &tlvs->area_addresses, buf, json, indent); if (tlvs->mt_router_info_empty) { - sbuf_push(buf, indent, "MT Router Info: None\n"); + if (json) + json_object_string_add(json, "mt-router-info", "none"); + else + sbuf_push(buf, indent, "MT Router Info: None\n"); } else { format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, - &tlvs->mt_router_info, buf, indent); + &tlvs->mt_router_info, buf, json, indent); } format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH, - &tlvs->oldstyle_reach, buf, indent); + &tlvs->oldstyle_reach, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS, - &tlvs->lan_neighbor, buf, indent); + &tlvs->lan_neighbor, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries, - buf, indent); - - format_tlv_dynamic_hostname(tlvs->hostname, buf, indent); - format_tlv_te_router_id(tlvs->te_router_id, buf, indent); - format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, buf, indent); - format_tlv_router_cap(tlvs->router_cap, buf, indent); + buf, json, indent); + + format_tlv_dynamic_hostname(tlvs->hostname, buf, json, indent); + format_tlv_te_router_id(tlvs->te_router_id, buf, json, indent); + format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, buf, json, + indent); + if (json) + format_tlv_router_cap_json(tlvs->router_cap, json); + else + format_tlv_router_cap(tlvs->router_cap, buf, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH, - &tlvs->extended_reach, buf, indent); + &tlvs->extended_reach, buf, json, indent); format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach, - buf, indent); + buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH, - &tlvs->oldstyle_ip_reach, buf, indent); + &tlvs->oldstyle_ip_reach, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT, - &tlvs->oldstyle_ip_reach_ext, buf, indent); + &tlvs->oldstyle_ip_reach_ext, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, - &tlvs->ipv4_address, buf, indent); + &tlvs->ipv4_address, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, - &tlvs->ipv6_address, buf, indent); + &tlvs->ipv6_address, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS, - &tlvs->global_ipv6_address, buf, indent); + &tlvs->global_ipv6_address, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH, - &tlvs->extended_ip_reach, buf, indent); + &tlvs->extended_ip_reach, buf, json, indent); format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH, - &tlvs->mt_ip_reach, buf, indent); + &tlvs->mt_ip_reach, buf, json, indent); format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach, - buf, indent); + buf, json, indent); format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, - &tlvs->mt_ipv6_reach, buf, indent); + &tlvs->mt_ipv6_reach, buf, json, indent); - format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent); + format_tlv_threeway_adj(tlvs->threeway_adj, buf, json, indent); - format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent); + format_tlv_spine_leaf(tlvs->spine_leaf, buf, json, indent); } -const char *isis_format_tlvs(struct isis_tlvs *tlvs) +const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json) { - static struct sbuf buf; + if (json) { + format_tlvs(tlvs, NULL, json, 0); + return NULL; + } else { + static struct sbuf buf; - if (!sbuf_buf(&buf)) - sbuf_init(&buf, NULL, 0); + if (!sbuf_buf(&buf)) + sbuf_init(&buf, NULL, 0); - sbuf_reset(&buf); - format_tlvs(tlvs, &buf, 0); - return sbuf_buf(&buf); + sbuf_reset(&buf); + format_tlvs(tlvs, &buf, NULL, 0); + return sbuf_buf(&buf); + } } void isis_free_tlvs(struct isis_tlvs *tlvs) diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 38470ef85..364e38aba 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -447,6 +447,7 @@ enum ext_subtlv_size { /* RFC 8667 sections #2 & #3 */ ISIS_SUBTLV_SID_LABEL_SIZE = 3, + ISIS_SUBTLV_SID_INDEX_SIZE = 4, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9, ISIS_SUBTLV_ALGORITHM_SIZE = 4, ISIS_SUBTLV_ADJ_SID_SIZE = 5, @@ -548,7 +549,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs); struct isis_tlvs *isis_alloc_tlvs(void); int isis_unpack_tlvs(size_t avail_len, struct stream *stream, struct isis_tlvs **dest, const char **error_log); -const char *isis_format_tlvs(struct isis_tlvs *tlvs); +const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json); struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs); struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size); diff --git a/isisd/isis_tx_queue.c b/isisd/isis_tx_queue.c index d3da5b9d3..078329221 100644 --- a/isisd/isis_tx_queue.c +++ b/isisd/isis_tx_queue.c @@ -114,7 +114,7 @@ static struct isis_tx_queue_entry *tx_queue_find(struct isis_tx_queue *queue, return hash_lookup(queue->hash, &e); } -static int tx_queue_send_event(struct thread *thread) +static void tx_queue_send_event(struct thread *thread) { struct isis_tx_queue_entry *e = THREAD_ARG(thread); struct isis_tx_queue *queue = e->queue; @@ -128,8 +128,6 @@ static int tx_queue_send_event(struct thread *thread) queue->send_event(queue->circuit, e->lsp, e->type); /* Don't access e here anymore, send_event might have destroyed it */ - - return 0; } void _isis_tx_queue_add(struct isis_tx_queue *queue, diff --git a/isisd/isisd.c b/isisd/isisd.c index 3fa2b7cc2..369b83396 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -109,12 +109,19 @@ DEFINE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area)); int isis_area_get(struct vty *, const char *); int area_net_title(struct vty *, const char *); int area_clear_net_title(struct vty *, const char *); -int show_isis_interface_common(struct vty *, const char *ifname, char, - const char *vrf_name, bool all_vrf); -int show_isis_neighbor_common(struct vty *, const char *id, char, - const char *vrf_name, bool all_vrf); -int clear_isis_neighbor_common(struct vty *, const char *id, const char *vrf_name, +int show_isis_interface_common(struct vty *, struct json_object *json, + const char *ifname, char, const char *vrf_name, bool all_vrf); +int show_isis_interface_common_vty(struct vty *, const char *ifname, char, + const char *vrf_name, bool all_vrf); +int show_isis_interface_common_json(struct json_object *json, + const char *ifname, char, + const char *vrf_name, bool all_vrf); +int show_isis_neighbor_common(struct vty *, struct json_object *json, + const char *id, char, const char *vrf_name, + bool all_vrf); +int clear_isis_neighbor_common(struct vty *, const char *id, + const char *vrf_name, bool all_vrf); /* Link ISIS instance to VRF. */ void isis_vrf_link(struct isis *isis, struct vrf *vrf) @@ -202,7 +209,7 @@ struct isis *isis_new(const char *vrf_name) /* * Default values */ - isis->max_area_addrs = 3; + isis->max_area_addrs = ISIS_DEFAULT_MAX_AREA_ADDRESSES; isis->process_id = getpid(); isis->router_id = 0; isis->area_list = list_new(); @@ -933,9 +940,124 @@ int area_clear_net_title(struct vty *vty, const char *net_title) /* * 'show isis interface' command */ - -int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, +int show_isis_interface_common(struct vty *vty, struct json_object *json, + const char *ifname, char detail, const char *vrf_name, bool all_vrf) +{ + if (json) { + return show_isis_interface_common_json(json, ifname, detail, + vrf_name, all_vrf); + } else { + return show_isis_interface_common_vty(vty, ifname, detail, + vrf_name, all_vrf); + } +} + +int show_isis_interface_common_json(struct json_object *json, + const char *ifname, char detail, + const char *vrf_name, bool all_vrf) +{ + struct listnode *anode, *cnode, *inode; + struct isis_area *area; + struct isis_circuit *circuit; + struct isis *isis; + struct json_object *areas_json, *area_json; + struct json_object *circuits_json, *circuit_json; + if (!im) { + // IS-IS Routing Process not enabled + json_object_string_add(json, "is-is-routing-process-enabled", + "no"); + return CMD_SUCCESS; + } + if (vrf_name) { + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", + areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, + anode, area)) { + area_json = json_object_new_object(); + json_object_string_add( + area_json, "area", + area->area_tag ? area->area_tag + : "null"); + circuits_json = json_object_new_array(); + json_object_object_add(area_json, + "circuits", + circuits_json); + for (ALL_LIST_ELEMENTS_RO( + area->circuit_list, cnode, + circuit)) { + circuit_json = + json_object_new_object(); + json_object_int_add( + circuit_json, "circuit", + circuit->circuit_id); + if (!ifname) + isis_circuit_print_json( + circuit, + circuit_json, + detail); + else if (strcmp(circuit->interface->name, ifname) == 0) + isis_circuit_print_json( + circuit, + circuit_json, + detail); + json_object_array_add( + circuits_json, + circuit_json); + } + json_object_array_add(areas_json, + area_json); + } + } + return CMD_SUCCESS; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) { + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, + area)) { + area_json = json_object_new_object(); + json_object_string_add(area_json, "area", + area->area_tag + ? area->area_tag + : "null"); + + circuits_json = json_object_new_array(); + json_object_object_add(area_json, "circuits", + circuits_json); + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, + cnode, circuit)) { + circuit_json = json_object_new_object(); + json_object_int_add( + circuit_json, "circuit", + circuit->circuit_id); + if (!ifname) + isis_circuit_print_json( + circuit, circuit_json, + detail); + else if ( + strcmp(circuit->interface->name, + ifname) == 0) + isis_circuit_print_json( + circuit, circuit_json, + detail); + json_object_array_add(circuits_json, + circuit_json); + } + json_object_array_add(areas_json, area_json); + } + } + } + return CMD_SUCCESS; +} + +int show_isis_interface_common_vty(struct vty *vty, const char *ifname, + char detail, const char *vrf_name, + bool all_vrf) { struct listnode *anode, *cnode, *inode; struct isis_area *area; @@ -990,8 +1112,7 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, circuit, vty, detail); else if ( strcmp(circuit->interface->name, - ifname) - == 0) + ifname) == 0) isis_circuit_print_vty( circuit, vty, detail); } @@ -1003,63 +1124,90 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail, DEFUN(show_isis_interface, show_isis_interface_cmd, - "show " PROTO_NAME " [vrf ] interface", + "show " PROTO_NAME " [vrf ] interface [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" + "json output\n" "IS-IS interface\n") { + int res = CMD_SUCCESS; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_BRIEF, - vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); + res = show_isis_interface_common(vty, json, NULL, ISIS_UI_LEVEL_BRIEF, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(show_isis_interface_detail, show_isis_interface_detail_cmd, - "show " PROTO_NAME " [vrf ] interface detail", + "show " PROTO_NAME " [vrf ] interface detail [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" "IS-IS interface\n" - "show detailed information\n") + "show detailed information\n" + "json output\n") { + int res = CMD_SUCCESS; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_DETAIL, - vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); + res = show_isis_interface_common(vty, json, NULL, ISIS_UI_LEVEL_DETAIL, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(show_isis_interface_arg, show_isis_interface_arg_cmd, - "show " PROTO_NAME " [vrf ] interface WORD", + "show " PROTO_NAME " [vrf ] interface WORD [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" "IS-IS interface\n" - "IS-IS interface name\n") + "IS-IS interface name\n" + "json output\n") { + int res = CMD_SUCCESS; int idx_word = 0; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); char *ifname = argv_find(argv, argc, "WORD", &idx_word) ? argv[idx_word]->arg : NULL; - return show_isis_interface_common(vty, ifname, ISIS_UI_LEVEL_DETAIL, - vrf_name, all_vrf); + res = show_isis_interface_common( + vty, json, ifname, ISIS_UI_LEVEL_DETAIL, vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid) @@ -1079,8 +1227,65 @@ static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid) return 0; } -static void isis_neighbor_common(struct vty *vty, const char *id, char detail, - struct isis *isis, uint8_t *sysid) +static void isis_neighbor_common_json(struct json_object *json, const char *id, + char detail, struct isis *isis, + uint8_t *sysid) +{ + struct listnode *anode, *cnode, *node; + struct isis_area *area; + struct isis_circuit *circuit; + struct list *adjdb; + struct isis_adjacency *adj; + struct json_object *areas_json, *area_json; + struct json_object *circuits_json, *circuit_json; + int i; + + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { + area_json = json_object_new_object(); + json_object_string_add(area_json, "area", + area->area_tag ? area->area_tag + : "null"); + circuits_json = json_object_new_array(); + json_object_object_add(area_json, "circuits", circuits_json); + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) { + circuit_json = json_object_new_object(); + json_object_int_add(circuit_json, "circuit", + circuit->circuit_id); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + for (i = 0; i < 2; i++) { + adjdb = circuit->u.bc.adjdb[i]; + if (adjdb && adjdb->count) { + for (ALL_LIST_ELEMENTS_RO( + adjdb, node, adj)) + if (!id || + !memcmp(adj->sysid, + sysid, + ISIS_SYS_ID_LEN)) + isis_adj_print_json( + adj, + circuit_json, + detail); + } + } + } else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) { + adj = circuit->u.p2p.neighbor; + if (!id || + !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN)) + isis_adj_print_json(adj, circuit_json, + detail); + } + json_object_array_add(circuits_json, circuit_json); + } + json_object_array_add(areas_json, area_json); + } +} + +static void isis_neighbor_common_vty(struct vty *vty, const char *id, + char detail, struct isis *isis, + uint8_t *sysid) { struct listnode *anode, *cnode, *node; struct isis_area *area; @@ -1103,9 +1308,8 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail, if (adjdb && adjdb->count) { for (ALL_LIST_ELEMENTS_RO( adjdb, node, adj)) - if (!id - || !memcmp( - adj->sysid, + if (!id || + !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_print_vty( @@ -1114,24 +1318,35 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail, detail); } } - } else if (circuit->circ_type == CIRCUIT_T_P2P - && circuit->u.p2p.neighbor) { + } else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) { adj = circuit->u.p2p.neighbor; - if (!id - || !memcmp(adj->sysid, sysid, - ISIS_SYS_ID_LEN)) + if (!id || + !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_print_vty(adj, vty, detail); } } } +} +static void isis_neighbor_common(struct vty *vty, struct json_object *json, + const char *id, char detail, struct isis *isis, + uint8_t *sysid) +{ + if (json) { + isis_neighbor_common_json(json, id, detail,isis,sysid); + } else { + isis_neighbor_common_vty(vty, id, detail,isis,sysid); + } } + /* * 'show isis neighbor' command */ -int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, - const char *vrf_name, bool all_vrf) +int show_isis_neighbor_common(struct vty *vty, struct json_object *json, + const char *id, char detail, const char *vrf_name, + bool all_vrf) { struct listnode *node; uint8_t sysid[ISIS_SYS_ID_LEN]; @@ -1150,8 +1365,8 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, id); return CMD_SUCCESS; } - isis_neighbor_common(vty, id, detail, isis, - sysid); + isis_neighbor_common(vty, json, id, detail, + isis, sysid); } return CMD_SUCCESS; } @@ -1161,7 +1376,8 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, vty_out(vty, "Invalid system id %s\n", id); return CMD_SUCCESS; } - isis_neighbor_common(vty, id, detail, isis, sysid); + isis_neighbor_common(vty, json, id, detail, isis, + sysid); } } @@ -1254,64 +1470,91 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_ DEFUN(show_isis_neighbor, show_isis_neighbor_cmd, - "show " PROTO_NAME " [vrf ] neighbor", + "show " PROTO_NAME " [vrf ] neighbor [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All vrfs\n" - "IS-IS neighbor adjacencies\n") + "IS-IS neighbor adjacencies\n" + "json output\n") { + int res = CMD_SUCCESS; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_BRIEF, - vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); + res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_BRIEF, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(show_isis_neighbor_detail, show_isis_neighbor_detail_cmd, - "show " PROTO_NAME " [vrf ] neighbor detail", + "show " PROTO_NAME " [vrf ] neighbor detail [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "all vrfs\n" "IS-IS neighbor adjacencies\n" - "show detailed information\n") + "show detailed information\n" + "json output\n") { + int res = CMD_SUCCESS; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); - return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_DETAIL, - vrf_name, all_vrf); + res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_DETAIL, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(show_isis_neighbor_arg, show_isis_neighbor_arg_cmd, - "show " PROTO_NAME " [vrf ] neighbor WORD", + "show " PROTO_NAME " [vrf ] neighbor WORD [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All vrfs\n" "IS-IS neighbor adjacencies\n" - "System id\n") + "System id\n" + "json output\n") { + int res = CMD_SUCCESS; int idx_word = 0; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); char *id = argv_find(argv, argc, "WORD", &idx_word) ? argv[idx_word]->arg : NULL; - return show_isis_neighbor_common(vty, id, ISIS_UI_LEVEL_DETAIL, - vrf_name, all_vrf); + res = show_isis_neighbor_common(vty, json, id, ISIS_UI_LEVEL_DETAIL, + vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } DEFUN(clear_isis_neighbor, @@ -2056,7 +2299,152 @@ DEFUN(show_isis_spf_ietf, show_isis_spf_ietf_cmd, return CMD_SUCCESS; } -static void common_isis_summary(struct vty *vty, struct isis *isis) + +static const char *pdu_counter_index_to_name_json(enum pdu_counter_index index) +{ + switch (index) { + case L1_LAN_HELLO_INDEX: + return "l1-iih"; + case L2_LAN_HELLO_INDEX: + return "l2-iih"; + case P2P_HELLO_INDEX: + return "p2p-iih"; + case L1_LINK_STATE_INDEX: + return "l1-lsp"; + case L2_LINK_STATE_INDEX: + return "l2-lsp"; + case FS_LINK_STATE_INDEX: + return "fs-lsp"; + case L1_COMPLETE_SEQ_NUM_INDEX: + return "l1-csnp"; + case L2_COMPLETE_SEQ_NUM_INDEX: + return "l2-csnp"; + case L1_PARTIAL_SEQ_NUM_INDEX: + return "l1-psnp"; + case L2_PARTIAL_SEQ_NUM_INDEX: + return "l2-psnp"; + default: + return "???????"; + } +} + +static void common_isis_summary_json(struct json_object *json, + struct isis *isis) +{ + int level; + json_object *areas_json, *area_json, *tx_pdu_json, *rx_pdu_json, + *levels_json, *level_json; + struct listnode *node, *node2; + struct isis_area *area; + time_t cur; + char uptime[MONOTIME_STRLEN]; + char stier[5]; + json_object_string_add(json, "vrf", isis->name); + json_object_int_add(json, "process-id", isis->process_id); + if (isis->sysid_set) + json_object_string_add(json, "system-id", + sysid_print(isis->sysid)); + + cur = time(NULL); + cur -= isis->uptime; + frrtime_to_interval(cur, uptime, sizeof(uptime)); + json_object_string_add(json, "up-time", uptime); + if (isis->area_list) + json_object_int_add(json, "number-areas", + isis->area_list->count); + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + area_json = json_object_new_object(); + json_object_string_add(area_json, "area", + area->area_tag ? area->area_tag + : "null"); + + + if (fabricd) { + uint8_t tier = fabricd_tier(area); + snprintfrr(stier, sizeof(stier), "%s", &tier); + json_object_string_add(area_json, "tier", + tier == ISIS_TIER_UNDEFINED + ? "undefined" + : stier); + } + + if (listcount(area->area_addrs) > 0) { + struct area_addr *area_addr; + for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node2, + area_addr)) { + json_object_string_add( + area_json, "net", + isonet_print(area_addr->area_addr, + area_addr->addr_len + + ISIS_SYS_ID_LEN + + 1)); + } + } + + tx_pdu_json = json_object_new_object(); + json_object_object_add(area_json, "tx-pdu-type", tx_pdu_json); + for (int i = 0; i < PDU_COUNTER_SIZE; i++) { + if (!area->pdu_tx_counters[i]) + continue; + json_object_int_add(tx_pdu_json, + pdu_counter_index_to_name_json(i), + area->pdu_tx_counters[i]); + } + json_object_int_add(tx_pdu_json, "lsp-rxmt", + area->lsp_rxmt_count); + + rx_pdu_json = json_object_new_object(); + json_object_object_add(area_json, "rx-pdu-type", rx_pdu_json); + for (int i = 0; i < PDU_COUNTER_SIZE; i++) { + if (!area->pdu_rx_counters[i]) + continue; + json_object_int_add(rx_pdu_json, + pdu_counter_index_to_name_json(i), + area->pdu_rx_counters[i]); + } + + levels_json = json_object_new_array(); + json_object_object_add(area_json, "levels", levels_json); + for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + if ((area->is_type & level) == 0) + continue; + level_json = json_object_new_object(); + json_object_int_add(level_json, "id", level); + json_object_int_add(level_json, "lsp0-regenerated", + area->lsp_gen_count[level - 1]); + json_object_int_add(level_json, "lsp-purged", + area->lsp_purge_count[level - 1]); + if (area->spf_timer[level - 1]) + json_object_string_add(level_json, "spf", + "pending"); + else + json_object_string_add(level_json, "spf", + "no pending"); + json_object_int_add(level_json, "minimum-interval", + area->min_spf_interval[level - 1]); + if (area->spf_delay_ietf[level - 1]) + json_object_string_add( + level_json, "ietf-spf-delay-activated", + "not used"); + if (area->ip_circuits) { + isis_spf_print_json( + area->spftree[SPFTREE_IPV4][level - 1], + level_json); + } + if (area->ipv6_circuits) { + isis_spf_print_json( + area->spftree[SPFTREE_IPV6][level - 1], + level_json); + } + json_object_array_add(levels_json, level_json); + } + json_object_array_add(areas_json, area_json); + } +} + +static void common_isis_summary_vty(struct vty *vty, struct isis *isis) { struct listnode *node, *node2; struct isis_area *area; @@ -2156,10 +2544,21 @@ static void common_isis_summary(struct vty *vty, struct isis *isis) } } +static void common_isis_summary(struct vty *vty, struct json_object *json, + struct isis *isis) +{ + if (json) { + common_isis_summary_json(json, isis); + } else { + common_isis_summary_vty(vty, isis); + } +} + DEFUN(show_isis_summary, show_isis_summary_cmd, - "show " PROTO_NAME " [vrf ] summary", + "show " PROTO_NAME " [vrf ] summary [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" + "json output\n" "summary\n") { struct listnode *node; @@ -2167,25 +2566,30 @@ DEFUN(show_isis_summary, show_isis_summary_cmd, struct isis *isis; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; + bool uj = use_json(argc, argv); + json_object *json = NULL; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf) if (!im) { vty_out(vty, PROTO_NAME " is not running\n"); return CMD_SUCCESS; } + if (uj) + json = json_object_new_object(); if (vrf_name) { if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - common_isis_summary(vty, isis); + common_isis_summary(vty, json, isis); return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) - common_isis_summary(vty, isis); + common_isis_summary(vty, json, isis); } - vty_out(vty, "\n"); + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -2250,9 +2654,40 @@ struct isis_lsp *lsp_for_sysid(struct lspdb_head *head, const char *sysid_str, return lsp; } -void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, - int level, struct lspdb_head *lspdb, - const char *sysid_str, int ui_level) +void show_isis_database_lspdb_json(struct json_object *json, + struct isis_area *area, int level, + struct lspdb_head *lspdb, + const char *sysid_str, int ui_level) +{ + struct isis_lsp *lsp; + int lsp_count; + + if (lspdb_count(lspdb) > 0) { + lsp = lsp_for_sysid(lspdb, sysid_str, area->isis); + + if (lsp != NULL || sysid_str == NULL) { + json_object_int_add(json, "id", level + 1); + } + + if (lsp) { + if (ui_level == ISIS_UI_LEVEL_DETAIL) + lsp_print_detail(lsp, NULL, json, + area->dynhostname, area->isis); + else + lsp_print_json(lsp, json, area->dynhostname, + area->isis); + } else if (sysid_str == NULL) { + lsp_count = + lsp_print_all(NULL, json, lspdb, ui_level, + area->dynhostname, area->isis); + + json_object_int_add(json, "count", lsp_count); + } + } +} +void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area, + int level, struct lspdb_head *lspdb, + const char *sysid_str, int ui_level) { struct isis_lsp *lsp; int lsp_count; @@ -2271,14 +2706,14 @@ void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, if (lsp) { if (ui_level == ISIS_UI_LEVEL_DETAIL) - lsp_print_detail(lsp, vty, area->dynhostname, - area->isis); + lsp_print_detail(lsp, vty, NULL, + area->dynhostname, area->isis); else - lsp_print(lsp, vty, area->dynhostname, - area->isis); + lsp_print_vty(lsp, vty, area->dynhostname, + area->isis); } else if (sysid_str == NULL) { lsp_count = - lsp_print_all(vty, lspdb, ui_level, + lsp_print_all(vty, NULL, lspdb, ui_level, area->dynhostname, area->isis); vty_out(vty, " %u LSPs\n\n", lsp_count); @@ -2286,7 +2721,43 @@ void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, } } -static void show_isis_database_common(struct vty *vty, const char *sysid_str, +static void show_isis_database_json(struct json_object *json, const char *sysid_str, + int ui_level, struct isis *isis) +{ + struct listnode *node; + struct isis_area *area; + int level; + struct json_object *tag_area_json,*area_json, *lsp_json, *area_arr_json, *arr_json; + uint8_t area_cnt = 0; + + if (isis->area_list->count == 0) + return; + + area_arr_json = json_object_new_array(); + json_object_object_add(json, "areas", area_arr_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + area_json = json_object_new_object(); + tag_area_json = json_object_new_object(); + json_object_string_add(tag_area_json, "name", + area->area_tag ? area->area_tag + : "null"); + + arr_json = json_object_new_array(); + json_object_object_add(area_json,"area",tag_area_json); + json_object_object_add(area_json,"levels",arr_json); + for (level = 0; level < ISIS_LEVELS; level++) { + lsp_json = json_object_new_object(); + show_isis_database_lspdb_json(lsp_json, area, level, + &area->lspdb[level], + sysid_str, ui_level); + json_object_array_add(arr_json, lsp_json); + } + json_object_array_add(area_arr_json, area_json); + area_cnt++; + } +} + +static void show_isis_database_vty(struct vty *vty, const char *sysid_str, int ui_level, struct isis *isis) { struct listnode *node; @@ -2301,11 +2772,22 @@ static void show_isis_database_common(struct vty *vty, const char *sysid_str, area->area_tag ? area->area_tag : "null"); for (level = 0; level < ISIS_LEVELS; level++) - show_isis_database_lspdb(vty, area, level, + show_isis_database_lspdb_vty(vty, area, level, &area->lspdb[level], sysid_str, ui_level); } } + +static void show_isis_database_common(struct vty *vty, struct json_object *json, const char *sysid_str, + int ui_level, struct isis *isis) +{ + if (json) { + show_isis_database_json(json, sysid_str, ui_level, isis); + } else { + show_isis_database_vty(vty, sysid_str, ui_level, isis); + } +} + /* * This function supports following display options: * [ show isis database [detail] ] @@ -2322,7 +2804,7 @@ static void show_isis_database_common(struct vty *vty, const char *sysid_str, * [ show isis database detail .- ] * [ show isis database detail .- ] */ -static int show_isis_database(struct vty *vty, const char *sysid_str, +static int show_isis_database(struct vty *vty, struct json_object *json, const char *sysid_str, int ui_level, const char *vrf_name, bool all_vrf) { struct listnode *node; @@ -2331,28 +2813,30 @@ static int show_isis_database(struct vty *vty, const char *sysid_str, if (vrf_name) { if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - show_isis_database_common(vty, sysid_str, + show_isis_database_common(vty, json, sysid_str, ui_level, isis); return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); if (isis) - show_isis_database_common(vty, sysid_str, ui_level, - isis); + show_isis_database_common(vty, json, sysid_str, + ui_level, isis); } return CMD_SUCCESS; } DEFUN(show_database, show_database_cmd, - "show " PROTO_NAME " [vrf ] database [detail] [WORD]", + "show " PROTO_NAME " [vrf ] database [detail] [WORD] [json]", SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" "Link state database\n" "Detailed information\n" - "LSP ID\n") + "LSP ID\n" + "json output\n") { + int res = CMD_SUCCESS; int idx = 0; int idx_vrf = 0; const char *vrf_name = VRF_DEFAULT_NAME; @@ -2361,8 +2845,17 @@ DEFUN(show_database, show_database_cmd, ? ISIS_UI_LEVEL_DETAIL : ISIS_UI_LEVEL_BRIEF; char *id = argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL; + bool uj = use_json(argc, argv); + json_object *json = NULL; + ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - return show_isis_database(vty, id, uilevel, vrf_name, all_vrf); + if (uj) + json = json_object_new_object(); + + res = show_isis_database(vty, json, id, uilevel, vrf_name, all_vrf); + if (uj) + vty_json(vty, json); + return res; } #ifdef FABRICD diff --git a/isisd/isisd.h b/isisd/isisd.h index 7f8474a5f..c313fd9ef 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -89,6 +89,8 @@ struct isis_master { }; #define F_ISIS_UNIT_TEST 0x01 +#define ISIS_DEFAULT_MAX_AREA_ADDRESSES 3 + struct isis { vrf_id_t vrf_id; char *name; @@ -305,9 +307,13 @@ int isis_area_passwd_cleartext_set(struct isis_area *area, int level, const char *passwd, uint8_t snp_auth); int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level, const char *passwd, uint8_t snp_auth); -void show_isis_database_lspdb(struct vty *vty, struct isis_area *area, - int level, struct lspdb_head *lspdb, - const char *argv, int ui_level); +void show_isis_database_lspdb_json(struct json_object *json, + struct isis_area *area, int level, + struct lspdb_head *lspdb, const char *argv, + int ui_level); +void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area, + int level, struct lspdb_head *lspdb, + const char *argv, int ui_level); /* YANG paths */ #define ISIS_INSTANCE "/frr-isisd:isis/instance" diff --git a/ldpd/accept.c b/ldpd/accept.c index e8d3976ee..2999a35c0 100644 --- a/ldpd/accept.c +++ b/ldpd/accept.c @@ -25,7 +25,7 @@ struct accept_ev { LIST_ENTRY(accept_ev) entry; struct thread *ev; - int (*accept_cb)(struct thread *); + void (*accept_cb)(struct thread *); void *arg; int fd; }; @@ -37,8 +37,8 @@ struct { static void accept_arm(void); static void accept_unarm(void); -static int accept_cb(struct thread *); -static int accept_timeout(struct thread *); +static void accept_cb(struct thread *); +static void accept_timeout(struct thread *); void accept_init(void) @@ -46,8 +46,7 @@ accept_init(void) LIST_INIT(&accept_queue.queue); } -int -accept_add(int fd, int (*cb)(struct thread *), void *arg) +int accept_add(int fd, void (*cb)(struct thread *), void *arg) { struct accept_ev *av; @@ -115,23 +114,17 @@ accept_unarm(void) thread_cancel(&av->ev); } -static int -accept_cb(struct thread *thread) +static void accept_cb(struct thread *thread) { struct accept_ev *av = THREAD_ARG(thread); thread_add_read(master, accept_cb, av, av->fd, &av->ev); av->accept_cb(thread); - - return (0); } -static int -accept_timeout(struct thread *thread) +static void accept_timeout(struct thread *thread) { accept_queue.evt = NULL; log_debug(__func__); accept_arm(); - - return (0); } diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index d390e70ad..bbc8a277a 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -26,12 +26,12 @@ #include "log.h" static __inline int adj_compare(const struct adj *, const struct adj *); -static int adj_itimer(struct thread *); +static void adj_itimer(struct thread *); static __inline int tnbr_compare(const struct tnbr *, const struct tnbr *); static void tnbr_del(struct ldpd_conf *, struct tnbr *); static void tnbr_start(struct tnbr *); static void tnbr_stop(struct tnbr *); -static int tnbr_hello_timer(struct thread *); +static void tnbr_hello_timer(struct thread *); static void tnbr_start_hello_timer(struct tnbr *); static void tnbr_stop_hello_timer(struct tnbr *); @@ -172,8 +172,7 @@ adj_get_af(const struct adj *adj) /* adjacency timers */ /* ARGSUSED */ -static int -adj_itimer(struct thread *thread) +static void adj_itimer(struct thread *thread) { struct adj *adj = THREAD_ARG(thread); @@ -187,13 +186,11 @@ adj_itimer(struct thread *thread) adj->source.target->rlfa_count == 0) { /* remove dynamic targeted neighbor */ tnbr_del(leconf, adj->source.target); - return (0); + return; } } adj_del(adj, S_HOLDTIME_EXP); - - return (0); } void @@ -345,16 +342,13 @@ tnbr_get_hello_interval(struct tnbr *tnbr) /* target neighbors timers */ /* ARGSUSED */ -static int -tnbr_hello_timer(struct thread *thread) +static void tnbr_hello_timer(struct thread *thread) { struct tnbr *tnbr = THREAD_ARG(thread); tnbr->hello_timer = NULL; send_hello(HELLO_TARGETED, NULL, tnbr); tnbr_start_hello_timer(tnbr); - - return (0); } static void diff --git a/ldpd/control.c b/ldpd/control.c index 3b7776595..376f488bd 100644 --- a/ldpd/control.c +++ b/ldpd/control.c @@ -26,11 +26,11 @@ #define CONTROL_BACKLOG 5 -static int control_accept(struct thread *); +static void control_accept(struct thread *); static struct ctl_conn *control_connbyfd(int); static struct ctl_conn *control_connbypid(pid_t); static void control_close(int); -static int control_dispatch_imsg(struct thread *); +static void control_dispatch_imsg(struct thread *); struct ctl_conns ctl_conns; @@ -101,8 +101,7 @@ control_cleanup(char *path) } /* ARGSUSED */ -static int -control_accept(struct thread *thread) +static void control_accept(struct thread *thread) { int connfd; socklen_t len; @@ -121,14 +120,14 @@ control_accept(struct thread *thread) else if (errno != EWOULDBLOCK && errno != EINTR && errno != ECONNABORTED) log_warn("%s: accept", __func__); - return (0); + return; } sock_set_nonblock(connfd); if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { log_warn(__func__); close(connfd); - return (0); + return; } imsg_init(&c->iev.ibuf, connfd); @@ -140,8 +139,6 @@ control_accept(struct thread *thread) c->iev.ev_write = NULL; TAILQ_INSERT_TAIL(&ctl_conns, c, entry); - - return (0); } static struct ctl_conn * @@ -191,8 +188,7 @@ control_close(int fd) } /* ARGSUSED */ -static int -control_dispatch_imsg(struct thread *thread) +static void control_dispatch_imsg(struct thread *thread) { int fd = THREAD_FD(thread); struct ctl_conn *c; @@ -202,7 +198,7 @@ control_dispatch_imsg(struct thread *thread) if ((c = control_connbyfd(fd)) == NULL) { log_warnx("%s: fd %d: not found", __func__, fd); - return (0); + return; } c->iev.ev_read = NULL; @@ -210,13 +206,13 @@ control_dispatch_imsg(struct thread *thread) if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || n == 0) { control_close(fd); - return (0); + return; } for (;;) { if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { control_close(fd); - return (0); + return; } if (n == 0) @@ -278,8 +274,6 @@ control_dispatch_imsg(struct thread *thread) } imsg_event_add(&c->iev); - - return (0); } int diff --git a/ldpd/interface.c b/ldpd/interface.c index 5e04eab1b..af6e8fd7e 100644 --- a/ldpd/interface.c +++ b/ldpd/interface.c @@ -33,7 +33,7 @@ static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *); static int if_start(struct iface *, int); static int if_reset(struct iface *, int); static void if_update_af(struct iface_af *); -static int if_hello_timer(struct thread *); +static void if_hello_timer(struct thread *thread); static void if_start_hello_timer(struct iface_af *); static void if_stop_hello_timer(struct iface_af *); static int if_join_ipv4_group(struct iface *, struct in_addr *); @@ -43,7 +43,7 @@ static int if_leave_ipv6_group(struct iface *, struct in6_addr *); static int ldp_sync_fsm_init(struct iface *iface, int state); static int ldp_sync_act_iface_start_sync(struct iface *iface); -static int iface_wait_for_ldp_sync_timer(struct thread *thread); +static void iface_wait_for_ldp_sync_timer(struct thread *thread); static void start_wait_for_ldp_sync_timer(struct iface *iface); static void stop_wait_for_ldp_sync_timer(struct iface *iface); static int ldp_sync_act_ldp_start_sync(struct iface *iface); @@ -455,16 +455,13 @@ if_get_wait_for_sync_interval(void) /* timers */ /* ARGSUSED */ -static int -if_hello_timer(struct thread *thread) +static void if_hello_timer(struct thread *thread) { struct iface_af *ia = THREAD_ARG(thread); ia->hello_timer = NULL; send_hello(HELLO_LINK, ia, NULL); if_start_hello_timer(ia); - - return (0); } static void @@ -737,14 +734,11 @@ ldp_sync_act_iface_start_sync(struct iface *iface) return (0); } -static int -iface_wait_for_ldp_sync_timer(struct thread *thread) +static void iface_wait_for_ldp_sync_timer(struct thread *thread) { struct iface *iface = THREAD_ARG(thread); ldp_sync_fsm(iface, LDP_SYNC_EVT_LDP_SYNC_COMPLETE); - - return (0); } static void start_wait_for_ldp_sync_timer(struct iface *iface) diff --git a/ldpd/lde.c b/ldpd/lde.c index 55fa806d4..9d1daabbe 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -41,8 +41,8 @@ #include "libfrr.h" static void lde_shutdown(void); -static int lde_dispatch_imsg(struct thread *); -static int lde_dispatch_parent(struct thread *); +static void lde_dispatch_imsg(struct thread *thread); +static void lde_dispatch_parent(struct thread *thread); static __inline int lde_nbr_compare(const struct lde_nbr *, const struct lde_nbr *); static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *); @@ -243,8 +243,7 @@ lde_imsg_compose_ldpe(int type, uint32_t peerid, pid_t pid, void *data, } /* ARGSUSED */ -static int -lde_dispatch_imsg(struct thread *thread) +static void lde_dispatch_imsg(struct thread *thread) { struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; @@ -422,13 +421,10 @@ lde_dispatch_imsg(struct thread *thread) thread_cancel(&iev->ev_write); lde_shutdown(); } - - return (0); } /* ARGSUSED */ -static int -lde_dispatch_parent(struct thread *thread) +static void lde_dispatch_parent(struct thread *thread) { static struct ldpd_conf *nconf; struct iface *iface, *niface; @@ -710,8 +706,6 @@ lde_dispatch_parent(struct thread *thread) thread_cancel(&iev->ev_write); lde_shutdown(); } - - return (0); } int @@ -2173,11 +2167,9 @@ lde_address_list_free(struct lde_nbr *ln) /* * Event callback used to retry the label-manager sync zapi session. */ -static int zclient_sync_retry(struct thread *thread) +static void zclient_sync_retry(struct thread *thread) { zclient_sync_init(); - - return 0; } /* diff --git a/ldpd/lde.h b/ldpd/lde.h index dee6f3fcb..bcb1e1cca 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -227,7 +227,7 @@ void lde_check_withdraw(struct map *, struct lde_nbr *); void lde_check_withdraw_wcard(struct map *, struct lde_nbr *); int lde_wildcard_apply(struct map *, struct fec *, struct lde_map *); -int lde_gc_timer(struct thread *); +void lde_gc_timer(struct thread *thread); void lde_gc_start_timer(void); void lde_gc_stop_timer(void); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 33bb6c0fc..1ade3c537 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -1037,8 +1037,7 @@ lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me) /* gabage collector timer: timer to remove dead entries from the LIB */ /* ARGSUSED */ -int -lde_gc_timer(struct thread *thread) +void lde_gc_timer(struct thread *thread) { struct fec *fec, *safe; struct fec_node *fn; @@ -1064,8 +1063,6 @@ lde_gc_timer(struct thread *thread) log_debug("%s: %u entries removed", __func__, count); lde_gc_start_timer(); - - return (0); } void diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 92cf24bd5..a78d2b25d 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -46,8 +46,8 @@ static void ldpd_shutdown(void); static pid_t start_child(enum ldpd_process, char *, int, int); -static int main_dispatch_ldpe(struct thread *); -static int main_dispatch_lde(struct thread *); +static void main_dispatch_ldpe(struct thread *thread); +static void main_dispatch_lde(struct thread *thread); static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); static void main_imsg_send_net_sockets(int); @@ -219,7 +219,7 @@ FRR_DAEMON_INFO(ldpd, LDP, .n_yang_modules = array_size(ldpd_yang_modules), ); -static int ldp_config_fork_apply(struct thread *t) +static void ldp_config_fork_apply(struct thread *t) { /* * So the frr_config_fork() function schedules @@ -231,8 +231,6 @@ static int ldp_config_fork_apply(struct thread *t) * after the read in of the config. */ ldp_config_apply(NULL, vty_conf); - - return 0; } int @@ -563,8 +561,7 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync) /* imsg handling */ /* ARGSUSED */ -static int -main_dispatch_ldpe(struct thread *thread) +static void main_dispatch_ldpe(struct thread *thread) { struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; @@ -627,13 +624,10 @@ main_dispatch_ldpe(struct thread *thread) else kill(lde_pid, SIGTERM); } - - return (0); } /* ARGSUSED */ -static int -main_dispatch_lde(struct thread *thread) +static void main_dispatch_lde(struct thread *thread) { struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; @@ -735,13 +729,10 @@ main_dispatch_lde(struct thread *thread) else kill(ldpe_pid, SIGTERM); } - - return (0); } /* ARGSUSED */ -int -ldp_write_handler(struct thread *thread) +void ldp_write_handler(struct thread *thread) { struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; @@ -755,12 +746,10 @@ ldp_write_handler(struct thread *thread) /* this pipe is dead, so remove the event handlers */ thread_cancel(&iev->ev_read); thread_cancel(&iev->ev_write); - return (0); + return; } imsg_event_add(iev); - - return (0); } void @@ -828,9 +817,8 @@ evbuf_event_add(struct evbuf *eb) &eb->ev); } -void -evbuf_init(struct evbuf *eb, int fd, int (*handler)(struct thread *), - void *arg) +void evbuf_init(struct evbuf *eb, int fd, void (*handler)(struct thread *), + void *arg) { msgbuf_init(&eb->wbuf); eb->wbuf.fd = fd; diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 616c390e5..fd0097ca5 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -63,15 +63,15 @@ struct evbuf { struct msgbuf wbuf; struct thread *ev; - int (*handler)(struct thread *); + void (*handler)(struct thread *); void *arg; }; struct imsgev { struct imsgbuf ibuf; - int (*handler_write)(struct thread *); + void (*handler_write)(struct thread *); struct thread *ev_write; - int (*handler_read)(struct thread *); + void (*handler_read)(struct thread *); struct thread *ev_read; }; @@ -792,7 +792,7 @@ void sa2addr(struct sockaddr *, int *, union ldpd_addr *, socklen_t sockaddr_len(struct sockaddr *); /* ldpd.c */ -int ldp_write_handler(struct thread *); +void ldp_write_handler(struct thread *thread); void main_imsg_compose_ldpe(int, pid_t, void *, uint16_t); void main_imsg_compose_lde(int, pid_t, void *, uint16_t); int main_imsg_compose_both(enum imsg_type, void *, @@ -802,8 +802,7 @@ int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, int, void *, uint16_t); void evbuf_enqueue(struct evbuf *, struct ibuf *); void evbuf_event_add(struct evbuf *); -void evbuf_init(struct evbuf *, int, - int (*)(struct thread *), void *); +void evbuf_init(struct evbuf *, int, void (*)(struct thread *), void *); void evbuf_clear(struct evbuf *); int ldp_acl_request(struct imsgev *, char *, int, union ldpd_addr *, uint8_t); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 31f8026e3..29abd420e 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -36,10 +36,10 @@ #include "libfrr.h" static void ldpe_shutdown(void); -static int ldpe_dispatch_main(struct thread *); -static int ldpe_dispatch_lde(struct thread *); +static void ldpe_dispatch_main(struct thread *thread); +static void ldpe_dispatch_lde(struct thread *thread); #ifdef __OpenBSD__ -static int ldpe_dispatch_pfkey(struct thread *); +static void ldpe_dispatch_pfkey(struct thread *thread); #endif static void ldpe_setup_sockets(int, int, int, int); static void ldpe_close_sockets(int); @@ -273,8 +273,7 @@ ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data, } /* ARGSUSED */ -static int -ldpe_dispatch_main(struct thread *thread) +static void ldpe_dispatch_main(struct thread *thread) { static struct ldpd_conf *nconf; struct iface *niface; @@ -631,13 +630,10 @@ ldpe_dispatch_main(struct thread *thread) thread_cancel(&iev->ev_write); ldpe_shutdown(); } - - return (0); } /* ARGSUSED */ -static int -ldpe_dispatch_lde(struct thread *thread) +static void ldpe_dispatch_lde(struct thread *thread) { struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; @@ -770,14 +766,11 @@ ldpe_dispatch_lde(struct thread *thread) thread_cancel(&iev->ev_write); ldpe_shutdown(); } - - return (0); } #ifdef __OpenBSD__ /* ARGSUSED */ -static int -ldpe_dispatch_pfkey(struct thread *thread) +static void ldpe_dispatch_pfkey(struct thread *thread) { int fd = THREAD_FD(thread); @@ -786,8 +779,6 @@ ldpe_dispatch_pfkey(struct thread *thread) if (pfkey_read(fd, NULL) == -1) fatal("pfkey_read failed, exiting..."); - - return (0); } #endif /* __OpenBSD__ */ diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 0f650a86d..ddb0e0d97 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -148,7 +148,7 @@ extern struct nbr_pid_head nbrs_by_pid; /* accept.c */ void accept_init(void); -int accept_add(int, int (*)(struct thread *), void *); +int accept_add(int, void (*)(struct thread *), void *); void accept_del(int); void accept_pause(void); void accept_unpause(void); @@ -292,8 +292,8 @@ int gen_ldp_hdr(struct ibuf *, uint16_t); int gen_msg_hdr(struct ibuf *, uint16_t, uint16_t); int send_packet(int, int, union ldpd_addr *, struct iface_af *, void *, size_t); -int disc_recv_packet(struct thread *); -int session_accept(struct thread *); +void disc_recv_packet(struct thread *thread); +void session_accept(struct thread *thread); void session_accept_nbr(struct nbr *, int); void session_shutdown(struct nbr *, uint32_t, uint32_t, uint32_t); diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index e884b3ebf..867ad92e4 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -35,13 +35,13 @@ static __inline int nbr_addr_compare(const struct nbr *, static __inline int nbr_pid_compare(const struct nbr *, const struct nbr *); static void nbr_update_peerid(struct nbr *); -static int nbr_ktimer(struct thread *); +static void nbr_ktimer(struct thread *thread); static void nbr_start_ktimer(struct nbr *); -static int nbr_ktimeout(struct thread *); +static void nbr_ktimeout(struct thread *thread); static void nbr_start_ktimeout(struct nbr *); -static int nbr_itimeout(struct thread *); +static void nbr_itimeout(struct thread *thread); static void nbr_start_itimeout(struct nbr *); -static int nbr_idtimer(struct thread *); +static void nbr_idtimer(struct thread *thread); static int nbr_act_session_operational(struct nbr *); static void nbr_send_labelmappings(struct nbr *); static __inline int nbr_params_compare(const struct nbr_params *, @@ -419,16 +419,13 @@ nbr_session_active_role(struct nbr *nbr) /* Keepalive timer: timer to send keepalive message to neighbors */ -static int -nbr_ktimer(struct thread *thread) +static void nbr_ktimer(struct thread *thread) { struct nbr *nbr = THREAD_ARG(thread); nbr->keepalive_timer = NULL; send_keepalive(nbr); nbr_start_ktimer(nbr); - - return (0); } static void @@ -451,8 +448,7 @@ nbr_stop_ktimer(struct nbr *nbr) /* Keepalive timeout: if the nbr hasn't sent keepalive */ -static int -nbr_ktimeout(struct thread *thread) +static void nbr_ktimeout(struct thread *thread) { struct nbr *nbr = THREAD_ARG(thread); @@ -461,8 +457,6 @@ nbr_ktimeout(struct thread *thread) log_debug("%s: lsr-id %pI4", __func__, &nbr->id); session_shutdown(nbr, S_KEEPALIVE_TMR, 0, 0); - - return (0); } static void @@ -482,16 +476,13 @@ nbr_stop_ktimeout(struct nbr *nbr) /* Session initialization timeout: if nbr got stuck in the initialization FSM */ -static int -nbr_itimeout(struct thread *thread) +static void nbr_itimeout(struct thread *thread) { struct nbr *nbr = THREAD_ARG(thread); log_debug("%s: lsr-id %pI4", __func__, &nbr->id); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); - - return (0); } static void @@ -513,8 +504,7 @@ nbr_stop_itimeout(struct nbr *nbr) /* Init delay timer: timer to retry to iniziatize session */ -static int -nbr_idtimer(struct thread *thread) +static void nbr_idtimer(struct thread *thread) { struct nbr *nbr = THREAD_ARG(thread); @@ -523,8 +513,6 @@ nbr_idtimer(struct thread *thread) log_debug("%s: lsr-id %pI4", __func__, &nbr->id); nbr_establish_connection(nbr); - - return (0); } void @@ -573,8 +561,7 @@ nbr_pending_connect(struct nbr *nbr) return (nbr->ev_connect != NULL); } -static int -nbr_connect_cb(struct thread *thread) +static void nbr_connect_cb(struct thread *thread) { struct nbr *nbr = THREAD_ARG(thread); int error; @@ -585,7 +572,7 @@ nbr_connect_cb(struct thread *thread) len = sizeof(error); if (getsockopt(nbr->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__); - return (0); + return; } if (error) { @@ -593,12 +580,10 @@ nbr_connect_cb(struct thread *thread) errno = error; log_debug("%s: error while connecting to %s: %s", __func__, log_addr(nbr->af, &nbr->raddr), strerror(errno)); - return (0); + return; } nbr_fsm(nbr, NBR_EVT_CONNECT_UP); - - return (0); } int diff --git a/ldpd/packet.c b/ldpd/packet.c index 56af16d28..707878ca9 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -28,12 +28,12 @@ static struct iface *disc_find_iface(unsigned int, int, union ldpd_addr *); -static int session_read(struct thread *); -static int session_write(struct thread *); +static void session_read(struct thread *thread); +static void session_write(struct thread *thread); static ssize_t session_get_pdu(struct ibuf_read *, char **); static void tcp_close(struct tcp_conn *); static struct pending_conn *pending_conn_new(int, int, union ldpd_addr *); -static int pending_conn_timeout(struct thread *); +static void pending_conn_timeout(struct thread *thread); int gen_ldp_hdr(struct ibuf *buf, uint16_t size) @@ -106,8 +106,7 @@ send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia, } /* Discovery functions */ -int -disc_recv_packet(struct thread *thread) +void disc_recv_packet(struct thread *thread) { int fd = THREAD_FD(thread); struct thread **threadp = THREAD_ARG(thread); @@ -158,7 +157,7 @@ disc_recv_packet(struct thread *thread) if (errno != EAGAIN && errno != EINTR) log_debug("%s: read error: %s", __func__, strerror(errno)); - return (0); + return; } sa2addr((struct sockaddr *)&from, &af, &src, NULL); @@ -205,7 +204,7 @@ disc_recv_packet(struct thread *thread) if (bad_addr(af, &src)) { log_debug("%s: invalid source address: %s", __func__, log_addr(af, &src)); - return (0); + return; } ifindex = getsockopt_ifindex(af, &m); @@ -213,7 +212,7 @@ disc_recv_packet(struct thread *thread) if (multicast) { iface = disc_find_iface(ifindex, af, &src); if (iface == NULL) - return (0); + return; } /* check packet size */ @@ -221,7 +220,7 @@ disc_recv_packet(struct thread *thread) if (len < (LDP_HDR_SIZE + LDP_MSG_SIZE) || len > LDP_MAX_LEN) { log_debug("%s: bad packet size, source %s", __func__, log_addr(af, &src)); - return (0); + return; } /* LDP header sanity checks */ @@ -229,12 +228,12 @@ disc_recv_packet(struct thread *thread) if (ntohs(ldp_hdr.version) != LDP_VERSION) { log_debug("%s: invalid LDP version %d, source %s", __func__, ntohs(ldp_hdr.version), log_addr(af, &src)); - return (0); + return; } if (ntohs(ldp_hdr.lspace_id) != 0) { log_debug("%s: invalid label space %u, source %s", __func__, ntohs(ldp_hdr.lspace_id), log_addr(af, &src)); - return (0); + return; } /* check "PDU Length" field */ pdu_len = ntohs(ldp_hdr.length); @@ -242,7 +241,7 @@ disc_recv_packet(struct thread *thread) (pdu_len > (len - LDP_HDR_DEAD_LEN))) { log_debug("%s: invalid LDP packet length %u, source %s", __func__, ntohs(ldp_hdr.length), log_addr(af, &src)); - return (0); + return; } buf += LDP_HDR_SIZE; len -= LDP_HDR_SIZE; @@ -261,7 +260,7 @@ disc_recv_packet(struct thread *thread) if (msg_len < LDP_MSG_LEN || ((msg_len + LDP_MSG_DEAD_LEN) > pdu_len)) { log_debug("%s: invalid LDP message length %u, source %s", __func__, ntohs(msg.length), log_addr(af, &src)); - return (0); + return; } buf += LDP_MSG_SIZE; len -= LDP_MSG_SIZE; @@ -275,8 +274,6 @@ disc_recv_packet(struct thread *thread) log_debug("%s: unknown LDP packet type, source %s", __func__, log_addr(af, &src)); } - - return (0); } static struct iface * @@ -304,8 +301,7 @@ disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src) return (iface); } -int -session_accept(struct thread *thread) +void session_accept(struct thread *thread) { int fd = THREAD_FD(thread); struct sockaddr_storage src; @@ -328,7 +324,7 @@ session_accept(struct thread *thread) errno != ECONNABORTED) log_debug("%s: accept error: %s", __func__, strerror(errno)); - return (0); + return; } sock_set_nonblock(newfd); @@ -357,22 +353,20 @@ session_accept(struct thread *thread) close(newfd); else pending_conn_new(newfd, af, &addr); - return (0); + return; } /* protection against buggy implementations */ if (nbr_session_active_role(nbr)) { close(newfd); - return (0); + return; } if (nbr->state != NBR_STA_PRESENT) { log_debug("%s: lsr-id %pI4: rejecting additional transport connection", __func__, &nbr->id); close(newfd); - return (0); + return; } session_accept_nbr(nbr, newfd); - - return (0); } void @@ -411,8 +405,7 @@ session_accept_nbr(struct nbr *nbr, int fd) nbr_fsm(nbr, NBR_EVT_MATCH_ADJ); } -static int -session_read(struct thread *thread) +static void session_read(struct thread *thread) { int fd = THREAD_FD(thread); struct nbr *nbr = THREAD_ARG(thread); @@ -431,16 +424,16 @@ session_read(struct thread *thread) if (errno != EINTR && errno != EAGAIN) { log_warn("%s: read error", __func__); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); - return (0); + return; } /* retry read */ - return (0); + return; } if (n == 0) { /* connection closed */ log_debug("%s: connection closed by remote end", __func__); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); - return (0); + return; } tcp->rbuf->wpos += n; @@ -450,7 +443,7 @@ session_read(struct thread *thread) if (ntohs(ldp_hdr->version) != LDP_VERSION) { session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0); free(buf); - return (0); + return; } pdu_len = ntohs(ldp_hdr->length); @@ -467,14 +460,14 @@ session_read(struct thread *thread) pdu_len > max_pdu_len) { session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0); free(buf); - return (0); + return; } pdu_len -= LDP_HDR_PDU_LEN; if (ldp_hdr->lsr_id != nbr->id.s_addr || ldp_hdr->lspace_id != 0) { session_shutdown(nbr, S_BAD_LDP_ID, 0, 0); free(buf); - return (0); + return; } pdu += LDP_HDR_SIZE; len -= LDP_HDR_SIZE; @@ -492,7 +485,7 @@ session_read(struct thread *thread) session_shutdown(nbr, S_BAD_MSG_LEN, msg->id, msg->type); free(buf); - return (0); + return; } msg_size = msg_len + LDP_MSG_DEAD_LEN; pdu_len -= msg_size; @@ -505,7 +498,7 @@ session_read(struct thread *thread) session_shutdown(nbr, S_SHUTDOWN, msg->id, msg->type); free(buf); - return (0); + return; } break; case MSG_TYPE_KEEPALIVE: @@ -514,7 +507,7 @@ session_read(struct thread *thread) session_shutdown(nbr, S_SHUTDOWN, msg->id, msg->type); free(buf); - return (0); + return; } break; case MSG_TYPE_NOTIFICATION: @@ -524,7 +517,7 @@ session_read(struct thread *thread) session_shutdown(nbr, S_SHUTDOWN, msg->id, msg->type); free(buf); - return (0); + return; } break; } @@ -571,7 +564,7 @@ session_read(struct thread *thread) if (ret == -1) { /* parser failed, giving up */ free(buf); - return (0); + return; } /* no errors - update per neighbor message counters */ @@ -618,7 +611,7 @@ session_read(struct thread *thread) buf = NULL; if (len != 0) { session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0); - return (0); + return; } } @@ -626,11 +619,9 @@ session_read(struct thread *thread) * allocated - but let's get rid of the SA warning. */ free(buf); - return (0); } -static int -session_write(struct thread *thread) +static void session_write(struct thread *thread) { struct tcp_conn *tcp = THREAD_ARG(thread); struct nbr *nbr = tcp->nbr; @@ -647,12 +638,10 @@ session_write(struct thread *thread) * close the socket. */ tcp_close(tcp); - return (0); + return; } evbuf_event_add(&tcp->wbuf); - - return (0); } void @@ -817,8 +806,7 @@ pending_conn_find(int af, union ldpd_addr *addr) return (NULL); } -static int -pending_conn_timeout(struct thread *thread) +static void pending_conn_timeout(struct thread *thread) { struct pending_conn *pconn = THREAD_ARG(thread); struct tcp_conn *tcp; @@ -837,6 +825,4 @@ pending_conn_timeout(struct thread *thread) msgbuf_write(&tcp->wbuf.wbuf); pending_conn_del(pconn); - - return (0); } diff --git a/lib/agentx.c b/lib/agentx.c index 5f865ca2b..821c573fb 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -46,7 +46,7 @@ static struct list *events = NULL; static void agentx_events_update(void); -static int agentx_timeout(struct thread *t) +static void agentx_timeout(struct thread *t) { timeout_thr = NULL; @@ -54,10 +54,9 @@ static int agentx_timeout(struct thread *t) run_alarms(); netsnmp_check_outstanding_agent_requests(); agentx_events_update(); - return 0; } -static int agentx_read(struct thread *t) +static void agentx_read(struct thread *t) { fd_set fds; int flags, new_flags = 0; @@ -72,7 +71,7 @@ static int agentx_read(struct thread *t) if (-1 == flags) { flog_err(EC_LIB_SYSTEM_CALL, "Failed to get FD settings fcntl: %s(%d)", strerror(errno), errno); - return -1; + return; } if (flags & O_NONBLOCK) @@ -101,7 +100,6 @@ static int agentx_read(struct thread *t) netsnmp_check_outstanding_agent_requests(); agentx_events_update(); - return 0; } static void agentx_events_update(void) diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 000000000..e3f238969 --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,193 @@ +/* + * This is part of the libb64 project, and has been placed in the public domain. + * For details, see http://sourceforge.net/projects/libb64 + */ + +#include "base64.h" + +static const int CHARS_PER_LINE = 72; +static const char *ENCODING = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +void base64_init_encodestate(struct base64_encodestate *state_in) +{ + state_in->step = step_A; + state_in->result = 0; + state_in->stepcount = 0; +} + +char base64_encode_value(char value_in) +{ + if (value_in > 63) + return '='; + return ENCODING[(int)value_in]; +} + +int base64_encode_block(const char *plaintext_in, int length_in, char *code_out, + struct base64_encodestate *state_in) +{ + const char *plainchar = plaintext_in; + const char *const plaintextend = plaintext_in + length_in; + char *codechar = code_out; + char result; + char fragment; + + result = state_in->result; + + switch (state_in->step) { + while (1) { + case step_A: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_A; + return codechar - code_out; + } + fragment = *plainchar++; + result = (fragment & 0x0fc) >> 2; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x003) << 4; + /* fall through */ + case step_B: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_B; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0f0) >> 4; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x00f) << 2; + /* fall through */ + case step_C: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_C; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0c0) >> 6; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x03f) >> 0; + *codechar++ = base64_encode_value(result); + + ++(state_in->stepcount); + if (state_in->stepcount == CHARS_PER_LINE/4) { + *codechar++ = '\n'; + state_in->stepcount = 0; + } + } + } + /* control should not reach here */ + return codechar - code_out; +} + +int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in) +{ + char *codechar = code_out; + + switch (state_in->step) { + case step_B: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + *codechar++ = '='; + break; + case step_C: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + break; + case step_A: + break; + } + *codechar++ = '\n'; + + return codechar - code_out; +} + + +signed char base64_decode_value(signed char value_in) +{ + static const signed char decoding[] = { + 62, -1, -1, -1, 63, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, -1, + -1, -1, -2, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, + -1, -1, -1, -1, -1, -1, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51 + }; + value_in -= 43; + if (value_in < 0 || value_in >= 80) + return -1; + return decoding[(int)value_in]; +} + +void base64_init_decodestate(struct base64_decodestate *state_in) +{ + state_in->step = step_a; + state_in->plainchar = 0; +} + +int base64_decode_block(const char *code_in, int length_in, char *plaintext_out, + struct base64_decodestate *state_in) +{ + const char *codec = code_in; + char *plainc = plaintext_out; + signed char fragmt; + + *plainc = state_in->plainchar; + + switch (state_in->step) { + while (1) { + case step_a: + do { + if (codec == code_in+length_in) { + state_in->step = step_a; + state_in->plainchar = *plainc; + return plainc - plaintext_out; + } + fragmt = base64_decode_value(*codec++); + } while (fragmt < 0); + *plainc = (fragmt & 0x03f) << 2; + /* fall through */ + case step_b: + do { + if (codec == code_in+length_in) { + state_in->step = step_b; + state_in->plainchar = *plainc; + return plainc - plaintext_out; + } + fragmt = base64_decode_value(*codec++); + } while (fragmt < 0); + *plainc++ |= (fragmt & 0x030) >> 4; + *plainc = (fragmt & 0x00f) << 4; + /* fall through */ + case step_c: + do { + if (codec == code_in+length_in) { + state_in->step = step_c; + state_in->plainchar = *plainc; + return plainc - plaintext_out; + } + fragmt = base64_decode_value(*codec++); + } while (fragmt < 0); + *plainc++ |= (fragmt & 0x03c) >> 2; + *plainc = (fragmt & 0x003) << 6; + /* fall through */ + case step_d: + do { + if (codec == code_in+length_in) { + state_in->step = step_d; + state_in->plainchar = *plainc; + return plainc - plaintext_out; + } + fragmt = base64_decode_value(*codec++); + } while (fragmt < 0); + *plainc++ |= (fragmt & 0x03f); + } + } + /* control should not reach here */ + return plainc - plaintext_out; +} diff --git a/lib/base64.h b/lib/base64.h new file mode 100644 index 000000000..3dc1559aa --- /dev/null +++ b/lib/base64.h @@ -0,0 +1,45 @@ +/* + * This is part of the libb64 project, and has been placed in the public domain. + * For details, see http://sourceforge.net/projects/libb64 + */ + +#ifndef _BASE64_H_ +#define _BASE64_H_ + +enum base64_encodestep { + step_A, step_B, step_C +}; + +struct base64_encodestate { + enum base64_encodestep step; + char result; + int stepcount; +}; + +void base64_init_encodestate(struct base64_encodestate *state_in); + +char base64_encode_value(char value_in); + +int base64_encode_block(const char *plaintext_in, int length_in, char *code_out, + struct base64_encodestate *state_in); + +int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in); + + +enum base64_decodestep { + step_a, step_b, step_c, step_d +}; + +struct base64_decodestate { + enum base64_decodestep step; + char plainchar; +}; + +void base64_init_decodestate(struct base64_decodestate *state_in); + +signed char base64_decode_value(signed char value_in); + +int base64_decode_block(const char *code_in, int length_in, char *plaintext_out, + struct base64_decodestate *state_in); + +#endif /* _BASE64_H_ */ diff --git a/lib/bfd.c b/lib/bfd.c index 7b711a9fb..29b8d85d8 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -461,14 +461,14 @@ static bool _bfd_sess_valid(const struct bfd_session_params *bsp) return true; } -static int _bfd_sess_send(struct thread *t) +static void _bfd_sess_send(struct thread *t) { struct bfd_session_params *bsp = THREAD_ARG(t); int rv; /* Validate configuration before trying to send bogus data. */ if (!_bfd_sess_valid(bsp)) - return 0; + return; if (bsp->lastev == BSE_INSTALL) { bsp->args.command = bsp->installed ? ZEBRA_BFD_DEST_UPDATE @@ -478,7 +478,7 @@ static int _bfd_sess_send(struct thread *t) /* If not installed and asked for uninstall, do nothing. */ if (!bsp->installed && bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER) - return 0; + return; rv = zclient_bfd_command(bsglobal.zc, &bsp->args); /* Command was sent successfully. */ @@ -504,8 +504,6 @@ static int _bfd_sess_send(struct thread *t) bsp->lastev == BSE_INSTALL ? "installed" : "uninstalled"); } - - return 0; } static void _bfd_sess_remove(struct bfd_session_params *bsp) diff --git a/lib/checksum.c b/lib/checksum.c index 347337004..6c5f06de4 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -9,13 +9,24 @@ #include #include "checksum.h" -int /* return checksum in low-order 16 bits */ - in_cksum(void *parg, int nbytes) +#define add_carry(dst, add) \ + do { \ + typeof(dst) _add = (add); \ + dst += _add; \ + if (dst < _add) \ + dst++; \ + } while (0) + +uint16_t in_cksumv(const struct iovec *iov, size_t iov_len) { - unsigned short *ptr = parg; - register long sum; /* assumes long == 32 bits */ - unsigned short oddbyte; - register unsigned short answer; /* assumes unsigned short == 16 bits */ + const struct iovec *iov_end; + uint32_t sum = 0; + + union { + uint8_t bytes[2]; + uint16_t word; + } wordbuf; + bool have_oddbyte = false; /* * Our algorithm is simple, using a 32-bit accumulator (sum), @@ -23,17 +34,42 @@ int /* return checksum in low-order 16 bits */ * all the carry bits from the top 16 bits into the lower 16 bits. */ - sum = 0; - while (nbytes > 1) { - sum += *ptr++; - nbytes -= 2; + for (iov_end = iov + iov_len; iov < iov_end; iov++) { + const uint8_t *ptr, *end; + + ptr = (const uint8_t *)iov->iov_base; + end = ptr + iov->iov_len; + if (ptr == end) + continue; + + if (have_oddbyte) { + have_oddbyte = false; + wordbuf.bytes[1] = *ptr++; + + add_carry(sum, wordbuf.word); + } + + while (ptr + 8 <= end) { + add_carry(sum, *(const uint32_t *)(ptr + 0)); + add_carry(sum, *(const uint32_t *)(ptr + 4)); + ptr += 8; + } + + while (ptr + 2 <= end) { + add_carry(sum, *(const uint16_t *)ptr); + ptr += 2; + } + + if (ptr + 1 <= end) { + wordbuf.bytes[0] = *ptr++; + have_oddbyte = true; + } } /* mop up an odd byte, if necessary */ - if (nbytes == 1) { - oddbyte = 0; /* make sure top half is zero */ - *((uint8_t *)&oddbyte) = *(uint8_t *)ptr; /* one byte only */ - sum += oddbyte; + if (have_oddbyte) { + wordbuf.bytes[1] = 0; + add_carry(sum, wordbuf.word); } /* @@ -42,26 +78,7 @@ int /* return checksum in low-order 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */ sum += (sum >> 16); /* add carry */ - answer = ~sum; /* ones-complement, then truncate to 16 bits */ - return (answer); -} - -int in_cksum_with_ph4(struct ipv4_ph *ph, void *data, int nbytes) -{ - uint8_t dat[sizeof(struct ipv4_ph) + nbytes]; - - memcpy(dat, ph, sizeof(struct ipv4_ph)); - memcpy(dat + sizeof(struct ipv4_ph), data, nbytes); - return in_cksum(dat, sizeof(dat)); -} - -int in_cksum_with_ph6(struct ipv6_ph *ph, void *data, int nbytes) -{ - uint8_t dat[sizeof(struct ipv6_ph) + nbytes]; - - memcpy(dat, ph, sizeof(struct ipv6_ph)); - memcpy(dat + sizeof(struct ipv6_ph), data, nbytes); - return in_cksum(dat, sizeof(dat)); + return ~sum; } /* Fletcher Checksum -- Refer to RFC1008. */ diff --git a/lib/checksum.h b/lib/checksum.h index 56771d4f2..508c3f38a 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -1,3 +1,6 @@ +#ifndef _FRR_CHECKSUM_H +#define _FRR_CHECKSUM_H + #include #include @@ -24,9 +27,41 @@ struct ipv6_ph { uint8_t next_hdr; } __attribute__((packed)); -extern int in_cksum(void *data, int nbytes); -extern int in_cksum_with_ph4(struct ipv4_ph *ph, void *data, int nbytes); -extern int in_cksum_with_ph6(struct ipv6_ph *ph, void *data, int nbytes); + +extern uint16_t in_cksumv(const struct iovec *iov, size_t iov_len); + +static inline uint16_t in_cksum(const void *data, size_t nbytes) +{ + struct iovec iov[1]; + + iov[0].iov_base = (void *)data; + iov[0].iov_len = nbytes; + return in_cksumv(iov, array_size(iov)); +} + +static inline uint16_t in_cksum_with_ph4(const struct ipv4_ph *ph, + const void *data, size_t nbytes) +{ + struct iovec iov[2]; + + iov[0].iov_base = (void *)ph; + iov[0].iov_len = sizeof(*ph); + iov[1].iov_base = (void *)data; + iov[1].iov_len = nbytes; + return in_cksumv(iov, array_size(iov)); +} + +static inline uint16_t in_cksum_with_ph6(const struct ipv6_ph *ph, + const void *data, size_t nbytes) +{ + struct iovec iov[2]; + + iov[0].iov_base = (void *)ph; + iov[0].iov_len = sizeof(*ph); + iov[1].iov_base = (void *)data; + iov[1].iov_len = nbytes; + return in_cksumv(iov, array_size(iov)); +} #define FLETCHER_CHECKSUM_VALIDATE 0xffff extern uint16_t fletcher_checksum(uint8_t *, const size_t len, @@ -35,3 +70,5 @@ extern uint16_t fletcher_checksum(uint8_t *, const size_t len, #ifdef __cplusplus } #endif + +#endif /* _FRR_CHECKSUM_H */ diff --git a/lib/command.c b/lib/command.c index 9cf93ea19..1989668bf 100644 --- a/lib/command.c +++ b/lib/command.c @@ -106,6 +106,21 @@ const char *cmd_domainname_get(void) return host.domainname; } +const char *cmd_system_get(void) +{ + return host.system; +} + +const char *cmd_release_get(void) +{ + return host.release; +} + +const char *cmd_version_get(void) +{ + return host.version; +} + static int root_on_exit(struct vty *vty); /* Standard command node structures. */ @@ -1398,8 +1413,9 @@ DEFUN (show_version, SHOW_STR "Displays zebra version\n") { - vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION, - cmd_hostname_get() ? cmd_hostname_get() : ""); + vty_out(vty, "%s %s (%s) on %s(%s).\n", FRR_FULL_NAME, FRR_VERSION, + cmd_hostname_get() ? cmd_hostname_get() : "", cmd_system_get(), + cmd_release_get()); vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO); #ifdef ENABLE_VERSION_BUILD_CONFIG vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS); @@ -2223,9 +2239,9 @@ DEFUN (banner_motd_file, int cmd = cmd_banner_motd_file(filename); if (cmd == CMD_ERR_NO_FILE) - vty_out(vty, "%s does not exist", filename); + vty_out(vty, "%s does not exist\n", filename); else if (cmd == CMD_WARNING_CONFIG_FAILED) - vty_out(vty, "%s must be in %s", filename, SYSCONFDIR); + vty_out(vty, "%s must be in %s\n", filename, SYSCONFDIR); return cmd; } @@ -2445,6 +2461,10 @@ void cmd_init(int terminal) /* Default host value settings. */ host.name = XSTRDUP(MTYPE_HOST, names.nodename); + host.system = XSTRDUP(MTYPE_HOST, names.sysname); + host.release = XSTRDUP(MTYPE_HOST, names.release); + host.version = XSTRDUP(MTYPE_HOST, names.version); + #ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME if ((strcmp(names.domainname, "(none)") == 0)) host.domainname = NULL; @@ -2563,6 +2583,9 @@ void cmd_terminate(void) } XFREE(MTYPE_HOST, host.name); + XFREE(MTYPE_HOST, host.system); + XFREE(MTYPE_HOST, host.release); + XFREE(MTYPE_HOST, host.version); XFREE(MTYPE_HOST, host.domainname); XFREE(MTYPE_HOST, host.password); XFREE(MTYPE_HOST, host.password_encrypt); diff --git a/lib/command.h b/lib/command.h index c888356d6..047e55053 100644 --- a/lib/command.h +++ b/lib/command.h @@ -55,6 +55,13 @@ struct host { /* Domainname of this router */ char *domainname; + /* + * Some extra system data that is useful + */ + char *system; + char *release; + char *version; + /* Password for vty interface. */ char *password; char *password_encrypt; @@ -93,6 +100,7 @@ enum node_type { RMAP_DEBUG_NODE, /* Route-map debug node */ RESOLVER_DEBUG_NODE, /* Resolver debug node */ AAA_NODE, /* AAA node. */ + EXTLOG_NODE, /* RFC5424 & co. extended syslog */ KEYCHAIN_NODE, /* Key-chain node. */ KEYCHAIN_KEY_NODE, /* Key-chain key node. */ IP_NODE, /* Static ip route node. */ @@ -600,6 +608,9 @@ extern int cmd_domainname_set(const char *domainname); extern int cmd_hostname_set(const char *hostname); extern const char *cmd_hostname_get(void); extern const char *cmd_domainname_get(void); +extern const char *cmd_system_get(void); +extern const char *cmd_release_get(void); +extern const char *cmd_version_get(void); /* NOT safe for general use; call this only if DEV_BUILD! */ extern void grammar_sandbox_init(void); diff --git a/lib/cspf.c b/lib/cspf.c new file mode 100644 index 000000000..ef3e7c2fa --- /dev/null +++ b/lib/cspf.c @@ -0,0 +1,646 @@ +/* + * Constraints Shortest Path First algorithms - cspf.c + * + * Author: Olivier Dugeon + * + * Copyright (C) 2022 Orange http://www.orange.com + * + * This file is part of Free Range Routing (FRR). + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "if.h" +#include "linklist.h" +#include "log.h" +#include "hash.h" +#include "memory.h" +#include "prefix.h" +#include "table.h" +#include "stream.h" +#include "printfrr.h" +#include "link_state.h" +#include "cspf.h" + +/* Link State Memory allocation */ +DEFINE_MTYPE_STATIC(LIB, PCA, "Path Computation Algorithms"); + +/** + * Create new Constrained Path. Memory is dynamically allocated. + * + * @param key Vertex key of the destination of this path + * + * @return Pointer to a new Constrained Path structure + */ +static struct c_path *cpath_new(uint64_t key) +{ + struct c_path *path; + + /* Sanity Check */ + if (key == 0) + return NULL; + + path = XCALLOC(MTYPE_PCA, sizeof(struct c_path)); + path->dst = key; + path->status = IN_PROGRESS; + path->edges = list_new(); + path->weight = MAX_COST; + + return path; +} + +/** + * Copy src Constrained Path into dst Constrained Path. A new Constrained Path + * structure is dynamically allocated if dst is NULL. If src is NULL, the + * function return the dst disregarding if it is NULL or not. + * + * @param dest Destination Constrained Path structure + * @param src Source Constrained Path structure + * + * @return Pointer to the destination Constrained Path structure + */ +static struct c_path *cpath_copy(struct c_path *dest, const struct c_path *src) +{ + struct c_path *new_path; + + if (!src) + return dest; + + if (!dest) { + new_path = XCALLOC(MTYPE_PCA, sizeof(struct c_path)); + } else { + new_path = dest; + if (dest->edges) + list_delete(&new_path->edges); + } + + new_path->dst = src->dst; + new_path->weight = src->weight; + new_path->edges = list_dup(src->edges); + new_path->status = src->status; + + return new_path; +} + +/** + * Delete Constrained Path structure. Previous allocated memory is freed. + * + * @param path Constrained Path structure to be deleted + */ +static void cpath_del(struct c_path *path) +{ + if (!path) + return; + + if (path->edges) + list_delete(&path->edges); + + XFREE(MTYPE_PCA, path); + path = NULL; +} + +/** + * Replace the list of edges in the next Constrained Path by the list of edges + * in the current Constrained Path. + * + * @param next_path next Constrained Path structure + * @param cur_path current Constrained Path structure + */ +static void cpath_replace(struct c_path *next_path, struct c_path *cur_path) +{ + + if (next_path->edges) + list_delete(&next_path->edges); + + next_path->edges = list_dup(cur_path->edges); +} + +/** + * Create a new Visited Node structure from the provided Vertex. Structure is + * dynamically allocated. + * + * @param vertex Vertex structure + * + * @return Pointer to the new Visited Node structure + */ +static struct v_node *vnode_new(struct ls_vertex *vertex) +{ + struct v_node *vnode; + + if (!vertex) + return NULL; + + vnode = XCALLOC(MTYPE_PCA, sizeof(struct v_node)); + vnode->vertex = vertex; + vnode->key = vertex->key; + + return vnode; +} + +/** + * Delete Visited Node structure. Previous allocated memory is freed. + * + * @param vnode Visited Node structure to be deleted + */ +static void vnode_del(struct v_node *vnode) +{ + if (!vnode) + return; + + XFREE(MTYPE_PCA, vnode); + vnode = NULL; +} + +/** + * Search Vertex in TED by IPv4 address. The function search vertex by browsing + * the subnets table. It allows to find not only vertex by router ID, but also + * vertex by interface IPv4 address. + * + * @param ted Traffic Engineering Database + * @param ipv4 IPv4 address + * + * @return Vertex if found, NULL otherwise + */ +static struct ls_vertex *get_vertex_by_ipv4(struct ls_ted *ted, + struct in_addr ipv4) +{ + struct ls_subnet *subnet; + struct prefix p; + + p.family = AF_INET; + p.u.prefix4 = ipv4; + + frr_each (subnets, &ted->subnets, subnet) { + if (subnet->key.family != AF_INET) + continue; + p.prefixlen = subnet->key.prefixlen; + if (prefix_same(&subnet->key, &p)) + return subnet->vertex; + } + + return NULL; +} + +/** + * Search Vertex in TED by IPv6 address. The function search vertex by browsing + * the subnets table. It allows to find not only vertex by router ID, but also + * vertex by interface IPv6 address. + * + * @param ted Traffic Engineering Database + * @param ipv6 IPv6 address + * + * @return Vertex if found, NULL otherwise + */ +static struct ls_vertex *get_vertex_by_ipv6(struct ls_ted *ted, + struct in6_addr ipv6) +{ + struct ls_subnet *subnet; + struct prefix p; + + p.family = AF_INET6; + p.u.prefix6 = ipv6; + + frr_each (subnets, &ted->subnets, subnet) { + if (subnet->key.family != AF_INET6) + continue; + p.prefixlen = subnet->key.prefixlen; + if (prefix_cmp(&subnet->key, &p) == 0) + return subnet->vertex; + } + + return NULL; +} + +struct cspf *cspf_new(void) +{ + struct cspf *algo; + + /* Allocate New CSPF structure */ + algo = XCALLOC(MTYPE_PCA, sizeof(struct cspf)); + + /* Initialize RB-Trees */ + processed_init(&algo->processed); + visited_init(&algo->visited); + pqueue_init(&algo->pqueue); + + algo->path = NULL; + algo->pdst = NULL; + + return algo; +} + +struct cspf *cspf_init(struct cspf *algo, const struct ls_vertex *src, + const struct ls_vertex *dst, struct constraints *csts) +{ + struct cspf *new_algo; + struct c_path *psrc; + + if (!csts) + return NULL; + + if (!algo) + new_algo = cspf_new(); + else + new_algo = algo; + + /* Initialize Processed Path and Priority Queue with Src & Dst */ + if (src) { + psrc = cpath_new(src->key); + psrc->weight = 0; + processed_add(&new_algo->processed, psrc); + pqueue_add(&new_algo->pqueue, psrc); + new_algo->path = psrc; + } + if (dst) { + new_algo->pdst = cpath_new(dst->key); + processed_add(&new_algo->processed, new_algo->pdst); + } + + memcpy(&new_algo->csts, csts, sizeof(struct constraints)); + + return new_algo; +} + +struct cspf *cspf_init_v4(struct cspf *algo, struct ls_ted *ted, + const struct in_addr src, const struct in_addr dst, + struct constraints *csts) +{ + struct ls_vertex *vsrc; + struct ls_vertex *vdst; + struct cspf *new_algo; + + /* Sanity Check */ + if (!ted) + return algo; + + if (!algo) + new_algo = cspf_new(); + else + new_algo = algo; + + /* Got Source and Destination Vertex from TED */ + vsrc = get_vertex_by_ipv4(ted, src); + vdst = get_vertex_by_ipv4(ted, dst); + csts->family = AF_INET; + + return cspf_init(new_algo, vsrc, vdst, csts); +} + +struct cspf *cspf_init_v6(struct cspf *algo, struct ls_ted *ted, + const struct in6_addr src, const struct in6_addr dst, + struct constraints *csts) +{ + struct ls_vertex *vsrc; + struct ls_vertex *vdst; + struct cspf *new_algo; + + /* Sanity Check */ + if (!ted) + return algo; + + if (!algo) + new_algo = cspf_new(); + else + new_algo = algo; + + /* Got Source and Destination Vertex from TED */ + vsrc = get_vertex_by_ipv6(ted, src); + vdst = get_vertex_by_ipv6(ted, dst); + csts->family = AF_INET6; + + return cspf_init(new_algo, vsrc, vdst, csts); +} + +void cspf_clean(struct cspf *algo) +{ + struct c_path *path; + struct v_node *vnode; + + if (!algo) + return; + + /* Normally, Priority Queue is empty. Clean it in case of. */ + if (pqueue_count(&algo->pqueue)) { + frr_each_safe (pqueue, &algo->pqueue, path) { + pqueue_del(&algo->pqueue, path); + } + } + + /* Empty Processed Path tree and associated Path */ + if (processed_count(&algo->processed)) { + frr_each_safe (processed, &algo->processed, path) { + processed_del(&algo->processed, path); + cpath_del(path); + } + } + + /* Empty visited Vertex tree and associated Node */ + if (visited_count(&algo->visited)) { + frr_each_safe (visited, &algo->visited, vnode) { + visited_del(&algo->visited, vnode); + vnode_del(vnode); + } + } + + memset(&algo->csts, 0, sizeof(struct constraints)); + algo->path = NULL; + algo->pdst = NULL; +} + +void cspf_del(struct cspf *algo) +{ + if (!algo) + return; + + /* Empty Priority Queue and Processes Path */ + cspf_clean(algo); + + /* Then, reset Priority Queue, Processed Path and Visited RB-Tree */ + pqueue_fini(&algo->pqueue); + processed_fini(&algo->processed); + visited_fini(&algo->visited); + + XFREE(MTYPE_PCA, algo); + algo = NULL; +} + +/** + * Prune Edge if constraints are not met by testing Edge Attributes against + * given constraints and cumulative cost of the given constrained path. + * + * @param path On-going Computed Path with cumulative cost constraints + * @param edge Edge to be validate against Constraints + * @param csts Constraints for this path + * + * @return True if Edge should be prune, false if Edge is valid + */ +static bool prune_edge(const struct c_path *path, const struct ls_edge *edge, + const struct constraints *csts) +{ + struct ls_vertex *dst; + struct ls_attributes *attr; + + /* Check that Path, Edge and Constraints are valid */ + if (!path || !edge || !csts) + return true; + + /* Check that Edge has a valid destination */ + if (!edge->destination) + return true; + dst = edge->destination; + + /* Check that Edge has valid attributes */ + if (!edge->attributes) + return true; + attr = edge->attributes; + + /* Check that Edge belongs to the requested Address Family and type */ + if (csts->family == AF_INET) { + if (IPV4_NET0(attr->standard.local.s_addr)) + return true; + if (csts->type == SR_TE) + if (!CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID) || + !CHECK_FLAG(dst->node->flags, LS_NODE_SR)) + return true; + } + if (csts->family == AF_INET6) { + if (IN6_IS_ADDR_UNSPECIFIED(&attr->standard.local6)) + return true; + if (csts->type == SR_TE) + if (!CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID6) || + !CHECK_FLAG(dst->node->flags, LS_NODE_SR)) + return true; + } + + /* + * Check that total cost, up to this edge, respects the initial + * constraints + */ + switch (csts->ctype) { + case CSPF_METRIC: + if (!CHECK_FLAG(attr->flags, LS_ATTR_METRIC)) + return true; + if ((attr->metric + path->weight) > csts->cost) + return true; + break; + + case CSPF_TE_METRIC: + if (!CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) + return true; + if ((attr->standard.te_metric + path->weight) > csts->cost) + return true; + break; + + case CSPF_DELAY: + if (!CHECK_FLAG(attr->flags, LS_ATTR_DELAY)) + return true; + if ((attr->extended.delay + path->weight) > csts->cost) + return true; + break; + } + + /* If specified, check that Edge meet Bandwidth constraint */ + if (csts->bw > 0.0) { + if (attr->standard.max_bw < csts->bw || + attr->standard.max_rsv_bw < csts->bw || + attr->standard.unrsv_bw[csts->cos] < csts->bw) + return true; + } + + /* All is fine. We can consider this Edge valid, so not to be prune */ + return false; +} + +/** + * Relax constraints of the current path up to the destination vertex of the + * provided Edge. This function progress in the network topology by validating + * the next vertex on the computed path. If Vertex has not already been visited, + * list of edges of the current path is augmented with this edge if the new cost + * is lower than prior path up to this vertex. Current path is re-inserted in + * the Priority Queue with its new cost i.e. current cost + edge cost. + * + * @param algo CSPF structure + * @param edge Next Edge to be added to the current computed path + * + * @return True if current path reach destination, false otherwise + */ +static bool relax_constraints(struct cspf *algo, struct ls_edge *edge) +{ + + struct c_path pkey = {}; + struct c_path *next_path; + struct v_node vnode = {}; + uint32_t total_cost = MAX_COST; + + /* Verify that we have a current computed path */ + if (!algo->path) + return false; + + /* Verify if we have not visited the next Vertex to avoid loop */ + vnode.key = edge->destination->key; + if (visited_member(&algo->visited, &vnode)) { + return false; + } + + /* + * Get Next Computed Path from next vertex key + * or create a new one if it has not yet computed. + */ + pkey.dst = edge->destination->key; + next_path = processed_find(&algo->processed, &pkey); + if (!next_path) { + next_path = cpath_new(pkey.dst); + processed_add(&algo->processed, next_path); + } + + /* + * Add or update the Computed Path in the Priority Queue if total cost + * is lower than cost associated to this next Vertex. This could occurs + * if we process a Vertex that as not yet been visited in the Graph + * or if we found a shortest path up to this Vertex. + */ + switch (algo->csts.ctype) { + case CSPF_METRIC: + total_cost = edge->attributes->metric + algo->path->weight; + break; + case CSPF_TE_METRIC: + total_cost = edge->attributes->standard.te_metric + + algo->path->weight; + break; + case CSPF_DELAY: + total_cost = + edge->attributes->extended.delay + algo->path->weight; + break; + default: + break; + } + if (total_cost < next_path->weight) { + /* + * It is not possible to directly update the q_path in the + * Priority Queue. Indeed, if we modify the path weight, the + * Priority Queue must be re-ordered. So, we need fist to remove + * the q_path if it is present in the Priority Queue, then, + * update the Path, in particular the Weight, and finally + * (re-)insert it in the Priority Queue. + */ + struct c_path *path; + frr_each_safe (pqueue, &algo->pqueue, path) { + if (path->dst == pkey.dst) { + pqueue_del(&algo->pqueue, path); + break; + } + } + next_path->weight = total_cost; + cpath_replace(next_path, algo->path); + listnode_add(next_path->edges, edge); + pqueue_add(&algo->pqueue, next_path); + } + + /* Return True if we reach the destination */ + return (next_path->dst == algo->pdst->dst); +} + +struct c_path *compute_p2p_path(struct cspf *algo, struct ls_ted *ted) +{ + struct listnode *node; + struct ls_vertex *vertex; + struct ls_edge *edge; + struct c_path *optim_path; + struct v_node *vnode; + uint32_t cur_cost; + + optim_path = cpath_new(0xFFFFFFFFFFFFFFFF); + optim_path->status = FAILED; + + /* Check that all is correctly initialized */ + if (!algo) + return optim_path; + + if (!algo->csts.ctype) + return optim_path; + + if (!algo->pdst) { + optim_path->status = NO_DESTINATION; + return optim_path; + } + + if (!algo->path) { + optim_path->status = NO_SOURCE; + return optim_path; + } + + if (algo->pdst->dst == algo->path->dst) { + optim_path->status = SAME_SRC_DST; + return optim_path; + } + + optim_path->dst = algo->pdst->dst; + optim_path->status = IN_PROGRESS; + + /* + * Process all Connected Vertex until priority queue becomes empty. + * Connected Vertices are added into the priority queue when + * processing the next Connected Vertex: see relax_constraints() + */ + cur_cost = MAX_COST; + while (pqueue_count(&algo->pqueue) != 0) { + /* Got shortest current Path from the Priority Queue */ + algo->path = pqueue_pop(&algo->pqueue); + + /* Add destination Vertex of this path to the visited RB Tree */ + vertex = ls_find_vertex_by_key(ted, algo->path->dst); + if (!vertex) + continue; + vnode = vnode_new(vertex); + visited_add(&algo->visited, vnode); + + /* Process all outgoing links from this Vertex */ + for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) { + /* + * Skip Connected Edges that must be prune i.e. + * Edges that not satisfy the given constraints, + * in particular the Bandwidth, TE Metric and Delay. + */ + if (prune_edge(algo->path, edge, &algo->csts)) + continue; + + /* + * Relax constraints and check if we got a shorter + * candidate path + */ + if (relax_constraints(algo, edge) && + algo->pdst->weight < cur_cost) { + cur_cost = algo->pdst->weight; + cpath_copy(optim_path, algo->pdst); + optim_path->status = SUCCESS; + } + } + } + + /* + * The priority queue is empty => all the possible (vertex, path) + * elements have been explored. The optim_path contains the optimal + * path if it exists. Otherwise an empty path with status failed is + * returned. + */ + if (optim_path->status == IN_PROGRESS || + listcount(optim_path->edges) == 0) + optim_path->status = FAILED; + cspf_clean(algo); + + return optim_path; +} diff --git a/lib/cspf.h b/lib/cspf.h new file mode 100644 index 000000000..6466ddb25 --- /dev/null +++ b/lib/cspf.h @@ -0,0 +1,211 @@ +/* + * Constraints Shortest Path First algorithms definition - cspf.h + * + * Author: Olivier Dugeon + * + * Copyright (C) 2022 Orange http://www.orange.com + * + * This file is part of Free Range Routing (FRR). + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FRR_CSPF_H_ +#define _FRR_CSPF_H_ + +#include "typesafe.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This file defines the different structure used for Path Computation with + * various constrained. Up to now, standard metric, TE metric, delay and + * bandwidth constraints are supported. + * All proposed algorithms used the same principle: + * - A pruning function that keeps only links that meet constraints + * - A priority Queue that keeps the shortest on-going computed path + * - A main loop over all vertices to find the shortest path + */ + +#define MAX_COST 0xFFFFFFFF + +/* Status of the path */ +enum path_status { + FAILED = 0, + NO_SOURCE, + NO_DESTINATION, + SAME_SRC_DST, + IN_PROGRESS, + SUCCESS +}; +enum path_type {RSVP_TE = 1, SR_TE, SRV6_TE}; +enum metric_type {CSPF_METRIC = 1, CSPF_TE_METRIC, CSPF_DELAY}; + +/* Constrained metrics structure */ +struct constraints { + uint32_t cost; /* total cost (metric) of the path */ + enum metric_type ctype; /* Metric Type: standard, TE or Delay */ + float bw; /* bandwidth of the path */ + uint8_t cos; /* Class of Service of the path */ + enum path_type type; /* RSVP-TE or SR-TE path */ + uint8_t family; /* AF_INET or AF_INET6 address family */ +}; + +/* Priority Queue for Constrained Path Computation */ +PREDECL_RBTREE_NONUNIQ(pqueue); + +/* Processed Path for Constrained Path Computation */ +PREDECL_RBTREE_UNIQ(processed); + +/* Constrained Path structure */ +struct c_path { + struct pqueue_item q_itm; /* entry in the Priority Queue */ + uint32_t weight; /* Weight to sort path in Priority Queue */ + struct processed_item p_itm; /* entry in the Processed RB Tree */ + uint64_t dst; /* Destination vertex key of this path */ + struct list *edges; /* List of Edges that compose this path */ + enum path_status status; /* status of the computed path */ +}; + +macro_inline int q_cmp(const struct c_path *p1, const struct c_path *p2) +{ + return numcmp(p1->weight, p2->weight); +} +DECLARE_RBTREE_NONUNIQ(pqueue, struct c_path, q_itm, q_cmp); + +macro_inline int p_cmp(const struct c_path *p1, const struct c_path *p2) +{ + return numcmp(p1->dst, p2->dst); +} +DECLARE_RBTREE_UNIQ(processed, struct c_path, p_itm, p_cmp); + +/* List of visited node */ +PREDECL_RBTREE_UNIQ(visited); +struct v_node { + struct visited_item item; /* entry in the Processed RB Tree */ + uint64_t key; + struct ls_vertex *vertex; +}; + +macro_inline int v_cmp(const struct v_node *p1, const struct v_node *p2) +{ + return numcmp(p1->key, p2->key); +} +DECLARE_RBTREE_UNIQ(visited, struct v_node, item, v_cmp); + +/* Path Computation algorithms structure */ +struct cspf { + struct pqueue_head pqueue; /* Priority Queue */ + struct processed_head processed; /* Paths that have been processed */ + struct visited_head visited; /* Vertices that have been visited */ + struct constraints csts; /* Constraints of the path */ + struct c_path *path; /* Current Computed Path */ + struct c_path *pdst; /* Computed Path to the destination */ +}; + +/** + * Create a new CSPF structure. Memory is dynamically allocated. + * + * @return pointer to the new cspf structure + */ +extern struct cspf *cspf_new(void); + +/** + * Initialize CSPF structure prior to compute a constrained path. If CSPF + * structure is NULL, a new CSPF is dynamically allocated prior to the + * configuration itself. + * + * @param algo CSPF structure, may be null if a new CSPF must be created + * @param src Source vertex of the requested path + * @param dst Destination vertex of the requested path + * @param csts Constraints of the requested path + * + * @return pointer to the initialized CSPF structure + */ +extern struct cspf *cspf_init(struct cspf *algo, const struct ls_vertex *src, + const struct ls_vertex *dst, + struct constraints *csts); + +/** + * Initialize CSPF structure prior to compute a constrained path. If CSPF + * structure is NULL, a new CSPF is dynamically allocated prior to the + * configuration itself. This function starts by searching source and + * destination vertices from the IPv4 addresses in the provided TED. + * + * @param algo CSPF structure, may be null if a new CSPF must be created + * @param ted Traffic Engineering Database + * @param src Source IPv4 address of the requested path + * @param dst Destination IPv4 address of the requested path + * @param csts Constraints of the requested path + * + * @return pointer to the initialized CSPF structure + */ +extern struct cspf *cspf_init_v4(struct cspf *algo, struct ls_ted *ted, + const struct in_addr src, + const struct in_addr dst, + struct constraints *csts); + +/** + * Initialize CSPF structure prior to compute a constrained path. If CSPF + * structure is NULL, a new CSPF is dynamically allocated prior to the + * configuration itself. This function starts by searching source and + * destination vertices from the IPv6 addresses in the provided TED. + * + * @param algo CSPF structure, may be null if a new CSPF must be created + * @param ted Traffic Engineering Database + * @param src Source IPv6 address of the requested path + * @param dst Destination IPv6 address of the requested path + * @param csts Constraints of the requested path + * + * @return pointer to the initialized CSPF structure + */ +extern struct cspf *cspf_init_v6(struct cspf *algo, struct ls_ted *ted, + const struct in6_addr src, + const struct in6_addr dst, + struct constraints *csts); + +/** + * Clean CSPF structure. Reset all internal list and priority queue for latter + * initialization of the CSPF structure and new path computation. + * + * @param algo CSPF structure + */ +extern void cspf_clean(struct cspf *algo); + +/** + * Delete CSPF structure, internal list and priority queue. + * + * @param algo CSPF structure + */ +extern void cspf_del(struct cspf *algo); + +/** + * Compute point-to-point constrained path. cspf_init() function must be call + * prior to call this function. + * + * @param algo CSPF structure + * @param ted Traffic Engineering Database + * + * @return Constrained Path with status to indicate computation success + */ +extern struct c_path *compute_p2p_path(struct cspf *algo, struct ls_ted *ted); + +#ifdef __cplusplus +} +#endif + +#endif /* _FRR_CSPF_H_ */ diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 80ea7a57c..35b97a9bd 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -1135,7 +1135,7 @@ static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args) f = nb_running_get_entry(args->dnode, NULL, true); fz = &f->u.zfilter; - fz->prefix.family = 0; + fz->prefix.family = AF_UNSPEC; acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 898fe98aa..0f56fbac8 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -237,18 +237,16 @@ void frr_pthread_stop_all(void) */ /* dummy task for sleeper pipe */ -static int fpt_dummy(struct thread *thread) +static void fpt_dummy(struct thread *thread) { - return 0; } /* poison pill task to end event loop */ -static int fpt_finish(struct thread *thread) +static void fpt_finish(struct thread *thread) { struct frr_pthread *fpt = THREAD_ARG(thread); atomic_store_explicit(&fpt->running, false, memory_order_relaxed); - return 0; } /* stop function, called from other threads to halt this one */ diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c index e572558de..db5c4c91a 100644 --- a/lib/frr_zmq.c +++ b/lib/frr_zmq.c @@ -56,7 +56,7 @@ void frrzmq_finish(void) } } -static int frrzmq_read_msg(struct thread *t) +static void frrzmq_read_msg(struct thread *t) { struct frrzmq_cb **cbp = THREAD_ARG(t); struct frrzmq_cb *cb; @@ -67,10 +67,10 @@ static int frrzmq_read_msg(struct thread *t) size_t moresz; if (!cbp) - return 1; + return; cb = (*cbp); if (!cb || !cb->zmqsock) - return 1; + return; while (1) { zmq_pollitem_t polli = {.socket = cb->zmqsock, @@ -97,7 +97,7 @@ static int frrzmq_read_msg(struct thread *t) if (cb->write.cancelled && !cb->write.thread) XFREE(MTYPE_ZEROMQ_CB, *cbp); - return 0; + return; } continue; } @@ -129,7 +129,7 @@ static int frrzmq_read_msg(struct thread *t) if (cb->write.cancelled && !cb->write.thread) XFREE(MTYPE_ZEROMQ_CB, *cbp); - return 0; + return; } /* cb_part may have read additional parts of the @@ -153,14 +153,13 @@ static int frrzmq_read_msg(struct thread *t) thread_add_read(t->master, frrzmq_read_msg, cbp, cb->fd, &cb->read.thread); - return 0; + return; out_err: flog_err(EC_LIB_ZMQ, "ZeroMQ read error: %s(%d)", strerror(errno), errno); if (cb->read.cb_error) cb->read.cb_error(cb->read.arg, cb->zmqsock); - return 1; } int _frrzmq_thread_add_read(const struct xref_threadsched *xref, @@ -215,7 +214,7 @@ int _frrzmq_thread_add_read(const struct xref_threadsched *xref, return 0; } -static int frrzmq_write_msg(struct thread *t) +static void frrzmq_write_msg(struct thread *t) { struct frrzmq_cb **cbp = THREAD_ARG(t); struct frrzmq_cb *cb; @@ -223,10 +222,10 @@ static int frrzmq_write_msg(struct thread *t) int ret; if (!cbp) - return 1; + return; cb = (*cbp); if (!cb || !cb->zmqsock) - return 1; + return; while (1) { zmq_pollitem_t polli = {.socket = cb->zmqsock, @@ -252,7 +251,7 @@ static int frrzmq_write_msg(struct thread *t) if (cb->read.cancelled && !cb->read.thread) XFREE(MTYPE_ZEROMQ_CB, *cbp); - return 0; + return; } continue; } @@ -263,14 +262,13 @@ static int frrzmq_write_msg(struct thread *t) thread_add_write(t->master, frrzmq_write_msg, cbp, cb->fd, &cb->write.thread); - return 0; + return; out_err: flog_err(EC_LIB_ZMQ, "ZeroMQ write error: %s(%d)", strerror(errno), errno); if (cb->write.cb_error) cb->write.cb_error(cb->write.arg, cb->zmqsock); - return 1; } int _frrzmq_thread_add_write(const struct xref_threadsched *xref, diff --git a/lib/hash.h b/lib/hash.h index f3b24f051..91770d181 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -235,9 +235,10 @@ extern void *hash_release(struct hash *hash, void *data); /* * Iterate over the elements in a hash table. * - * It is safe to delete items passed to the iteration function from the hash - * table during iteration. More than one item cannot be deleted during each - * iteration. Please note that adding entries to the hash + * The passed in arg to the handler function is the only safe + * item to delete from the hash. + * + * Please note that adding entries to the hash * during the walk will cause undefined behavior in that some new entries * will be walked and some will not. So do not do this. * @@ -258,8 +259,10 @@ extern void hash_iterate(struct hash *hash, /* * Iterate over the elements in a hash table, stopping on condition. * - * It is safe to delete items passed to the iteration function from the hash - * table during iteration. Please note that adding entries to the hash + * The passed in arg to the handler function is the only safe item + * to delete from the hash. + * + * Please note that adding entries to the hash * during the walk will cause undefined behavior in that some new entries * will be walked and some will not. So do not do this. * diff --git a/lib/if.c b/lib/if.c index 158303a38..83fa85ecc 100644 --- a/lib/if.c +++ b/lib/if.c @@ -490,7 +490,8 @@ struct connected *if_lookup_address(const void *matchaddr, int family, addr.family = AF_INET6; addr.u.prefix6 = *((struct in6_addr *)matchaddr); addr.prefixlen = IPV6_MAX_BITLEN; - } + } else + assert(!"Attempted lookup of family not supported"); match = NULL; @@ -1090,9 +1091,6 @@ struct if_link_params *if_link_params_get(struct interface *ifp) struct if_link_params *iflp = XCALLOC(MTYPE_IF_LINK_PARAMS, sizeof(struct if_link_params)); - /* Set TE metric equal to standard metric */ - iflp->te_metric = ifp->metric; - /* Compute default bandwidth based on interface */ iflp->default_bw = ((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH) @@ -1105,8 +1103,13 @@ struct if_link_params *if_link_params_get(struct interface *ifp) iflp->unrsv_bw[i] = iflp->default_bw; /* Update Link parameters status */ - iflp->lp_status = - LP_TE_METRIC | LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW; + iflp->lp_status = LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW; + + /* Set TE metric equal to standard metric only if it is set */ + if (ifp->metric != 0) { + iflp->te_metric = ifp->metric; + iflp->lp_status |= LP_TE_METRIC; + } /* Finally attach newly created Link Parameters */ ifp->link_params = iflp; diff --git a/lib/json.c b/lib/json.c index 854a3d59d..d85a21215 100644 --- a/lib/json.c +++ b/lib/json.c @@ -74,6 +74,19 @@ void json_object_string_addv(struct json_object *obj, const char *key, json_object_object_add(obj, key, json_object_new_stringv(fmt, args)); } +void json_object_object_addv(struct json_object *parent, + struct json_object *child, const char *keyfmt, + va_list args) +{ + char *text, buf[256]; + + text = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), keyfmt, args); + json_object_object_add(parent, text, child); + + if (text != buf) + XFREE(MTYPE_TMP, text); +} + void json_object_int_add(struct json_object *obj, const char *key, int64_t i) { json_object_object_add(obj, key, json_object_new_int64(i)); diff --git a/lib/json.h b/lib/json.h index 9d33ac7ae..78c383651 100644 --- a/lib/json.h +++ b/lib/json.h @@ -42,6 +42,15 @@ extern "C" { json_object_iter_equal(&(joi), &(join)) == 0; \ json_object_iter_next(&(joi))) +#define JSON_OBJECT_NEW_ARRAY(json_func, fields, n) \ + ({ \ + struct json_object *_json_array = json_object_new_array(); \ + for (int _i = 0; _i < (n); _i++) \ + json_object_array_add(_json_array, \ + (json_func)((fields)[_i])); \ + (_json_array); \ + }) + extern bool use_json(const int argc, struct cmd_token *argv[]); extern void json_object_string_add(struct json_object *obj, const char *key, const char *s); @@ -107,6 +116,28 @@ static inline struct json_object *json_object_new_stringf(const char *fmt, ...) return ret; } +/* NOTE: argument order differs! (due to varargs) + * json_object_object_add(parent, key, child) + * json_object_object_addv(parent, child, key, va) + * json_object_object_addf(parent, child, key, ...) + * (would be weird to have the child inbetween the format string and args) + */ +PRINTFRR(3, 0) +extern void json_object_object_addv(struct json_object *parent, + struct json_object *child, + const char *keyfmt, va_list args); +PRINTFRR(3, 4) +static inline void json_object_object_addf(struct json_object *parent, + struct json_object *child, + const char *keyfmt, ...) +{ + va_list args; + + va_start(args, keyfmt); + json_object_object_addv(parent, child, keyfmt, args); + va_end(args); +} + #define JSON_STR "JavaScript Object Notation\n" /* NOTE: json-c lib has following commit 316da85 which diff --git a/lib/keychain.c b/lib/keychain.c index 02f83ef0a..c29c45a11 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include #include "command.h" @@ -207,6 +208,7 @@ static struct key *key_get(const struct keychain *keychain, uint32_t index) key = key_new(); key->index = index; + key->hash_algo = KEYCHAIN_ALGO_NULL; listnode_add_sort(keychain->key, key); return key; @@ -336,6 +338,133 @@ DEFUN (no_key_string, return CMD_SUCCESS; } +const struct keychain_algo_info algo_info[] = { + {KEYCHAIN_ALGO_NULL, "null", 0, 0, "NULL"}, + {KEYCHAIN_ALGO_MD5, "md5", KEYCHAIN_MD5_HASH_SIZE, + KEYCHAIN_ALGO_MD5_INTERNAL_BLK_SIZE, "MD5"}, + {KEYCHAIN_ALGO_HMAC_SHA1, "hmac-sha-1", KEYCHAIN_HMAC_SHA1_HASH_SIZE, + KEYCHAIN_ALGO_SHA1_INTERNAL_BLK_SIZE, "HMAC-SHA-1"}, + {KEYCHAIN_ALGO_HMAC_SHA256, "hmac-sha-256", + KEYCHAIN_HMAC_SHA256_HASH_SIZE, KEYCHAIN_ALGO_SHA256_INTERNAL_BLK_SIZE, + "HMAC-SHA-256"}, + {KEYCHAIN_ALGO_HMAC_SHA384, "hmac-sha-384", + KEYCHAIN_HMAC_SHA384_HASH_SIZE, KEYCHAIN_ALGO_SHA384_INTERNAL_BLK_SIZE, + "HMAC-SHA-384"}, + {KEYCHAIN_ALGO_HMAC_SHA512, "hmac-sha-512", + KEYCHAIN_HMAC_SHA512_HASH_SIZE, KEYCHAIN_ALGO_SHA512_INTERNAL_BLK_SIZE, + "HMAC-SHA-512"}, + {KEYCHAIN_ALGO_MAX, "max", KEYCHAIN_MAX_HASH_SIZE, + KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE, "Not defined"} +}; + +uint16_t keychain_get_block_size(enum keychain_hash_algo key) +{ + return algo_info[key].block; +} + +uint16_t keychain_get_hash_len(enum keychain_hash_algo key) +{ + return algo_info[key].length; +} + +const char *keychain_get_description(enum keychain_hash_algo key) +{ + return algo_info[key].desc; +} + +struct keychain_algo_info +keychain_get_hash_algo_info(enum keychain_hash_algo key) +{ + return algo_info[key]; +} + +enum keychain_hash_algo keychain_get_algo_id_by_name(const char *name) +{ +#ifdef CRYPTO_INTERNAL + if (!strncmp(name, "hmac-sha-2", 10)) + return KEYCHAIN_ALGO_HMAC_SHA256; + else if (!strncmp(name, "m", 1)) + return KEYCHAIN_ALGO_MD5; + else + return KEYCHAIN_ALGO_NULL; +#else + if (!strncmp(name, "m", 1)) + return KEYCHAIN_ALGO_MD5; + else if (!strncmp(name, "hmac-sha-1", 10)) + return KEYCHAIN_ALGO_HMAC_SHA1; + else if (!strncmp(name, "hmac-sha-2", 10)) + return KEYCHAIN_ALGO_HMAC_SHA256; + else if (!strncmp(name, "hmac-sha-3", 10)) + return KEYCHAIN_ALGO_HMAC_SHA384; + else if (!strncmp(name, "hmac-sha-5", 10)) + return KEYCHAIN_ALGO_HMAC_SHA512; + else + return KEYCHAIN_ALGO_NULL; +#endif +} + +const char *keychain_get_algo_name_by_id(enum keychain_hash_algo key) +{ + return algo_info[key].name; +} + +DEFUN(cryptographic_algorithm, cryptographic_algorithm_cmd, + "cryptographic-algorithm " + "", + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n") +{ + int algo_idx = 1; + uint8_t hash_algo = KEYCHAIN_ALGO_NULL; + + VTY_DECLVAR_CONTEXT_SUB(key, key); + hash_algo = keychain_get_algo_id_by_name(argv[algo_idx]->arg); +#ifndef CRYPTO_OPENSSL + if (hash_algo == KEYCHAIN_ALGO_NULL) { + vty_out(vty, + "Hash algorithm not supported, compile with --with-crypto=openssl\n"); + return CMD_WARNING_CONFIG_FAILED; + } +#endif /* CRYPTO_OPENSSL */ + key->hash_algo = hash_algo; + return CMD_SUCCESS; +} + +DEFUN(no_cryptographic_algorithm, no_cryptographic_algorithm_cmd, + "no cryptographic-algorithm " + "[]", + NO_STR + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n") +{ + int algo_idx = 2; + uint8_t hash_algo = KEYCHAIN_ALGO_NULL; + + VTY_DECLVAR_CONTEXT_SUB(key, key); + if (argc > algo_idx) { + hash_algo = keychain_get_algo_id_by_name(argv[algo_idx]->arg); + if (hash_algo == KEYCHAIN_ALGO_NULL) { + vty_out(vty, + "Hash algorithm not supported, try compiling with --with-crypto=openssl\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if ((hash_algo != KEYCHAIN_ALGO_NULL) && (hash_algo != key->hash_algo)) + return CMD_SUCCESS; + + key->hash_algo = KEYCHAIN_ALGO_NULL; + return CMD_SUCCESS; +} + /* Convert HH:MM:SS MON DAY YEAR to time_t value. -1 is returned when given string is malformed. */ static time_t key_str2time(const char *time_str, const char *day_str, @@ -1004,6 +1133,11 @@ static int keychain_config_write(struct vty *vty) if (key->string) vty_out(vty, " key-string %s\n", key->string); + if (key->hash_algo != KEYCHAIN_ALGO_NULL) + vty_out(vty, " cryptographic-algorithm %s\n", + keychain_get_algo_name_by_id( + key->hash_algo)); + if (key->accept.start) { keychain_strftime(buf, BUFSIZ, &key->accept.start); @@ -1051,10 +1185,29 @@ static int keychain_config_write(struct vty *vty) return 0; } + +static void keychain_active_config(vector comps, struct cmd_token *token) +{ + struct keychain *keychain; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(keychain_list, node, keychain)) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, keychain->name)); +} + +static const struct cmd_variable_handler keychain_var_handlers[] = { + {.varname = "key_chain", .completions = keychain_active_config}, + {.tokenname = "KEYCHAIN_NAME", .completions = keychain_active_config}, + {.tokenname = "KCHAIN_NAME", .completions = keychain_active_config}, + {.completions = NULL} +}; + void keychain_init(void) { keychain_list = list_new(); + /* Register handler for keychain auto config support */ + cmd_variable_handler_register(keychain_var_handlers); install_node(&keychain_node); install_node(&keychain_key_node); @@ -1113,4 +1266,6 @@ void keychain_init(void) install_element(KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd); install_element(KEYCHAIN_KEY_NODE, &no_send_lifetime_cmd); + install_element(KEYCHAIN_KEY_NODE, &cryptographic_algorithm_cmd); + install_element(KEYCHAIN_KEY_NODE, &no_cryptographic_algorithm_cmd); } diff --git a/lib/keychain.h b/lib/keychain.h index eb6d2f175..71319d972 100644 --- a/lib/keychain.h +++ b/lib/keychain.h @@ -27,6 +27,47 @@ extern "C" { #endif +enum keychain_hash_algo { + KEYCHAIN_ALGO_NULL, + KEYCHAIN_ALGO_MD5, + KEYCHAIN_ALGO_HMAC_SHA1, + KEYCHAIN_ALGO_HMAC_SHA256, + KEYCHAIN_ALGO_HMAC_SHA384, + KEYCHAIN_ALGO_HMAC_SHA512, + KEYCHAIN_ALGO_MAX +}; + +#define KEYCHAIN_MD5_HASH_SIZE 16 +#define KEYCHAIN_HMAC_SHA1_HASH_SIZE 20 +#define KEYCHAIN_HMAC_SHA256_HASH_SIZE 32 +#define KEYCHAIN_HMAC_SHA384_HASH_SIZE 48 +#define KEYCHAIN_HMAC_SHA512_HASH_SIZE 64 +#define KEYCHAIN_MAX_HASH_SIZE 64 + +#define KEYCHAIN_ALGO_MD5_INTERNAL_BLK_SIZE 16 +#define KEYCHAIN_ALGO_SHA1_INTERNAL_BLK_SIZE 64 +#define KEYCHAIN_ALGO_SHA256_INTERNAL_BLK_SIZE 64 +#define KEYCHAIN_ALGO_SHA384_INTERNAL_BLK_SIZE 128 +#define KEYCHAIN_ALGO_SHA512_INTERNAL_BLK_SIZE 128 +#define KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE 128 + +struct keychain_algo_info { + enum keychain_hash_algo key; + const char *name; + uint16_t length; + uint16_t block; + const char *desc; +}; + +extern const struct keychain_algo_info algo_info[]; +uint16_t keychain_get_block_size(enum keychain_hash_algo key); +uint16_t keychain_get_hash_len(enum keychain_hash_algo key); +const char *keychain_get_description(enum keychain_hash_algo key); +struct keychain_algo_info +keychain_get_hash_algo_info(enum keychain_hash_algo key); +enum keychain_hash_algo keychain_get_algo_id_by_name(const char *name); +const char *keychain_get_algo_name_by_id(enum keychain_hash_algo key); + struct keychain { char *name; @@ -47,7 +88,7 @@ struct key { uint32_t index; char *string; - + enum keychain_hash_algo hash_algo; struct key_range send; struct key_range accept; @@ -60,7 +101,7 @@ extern struct keychain *keychain_lookup(const char *); extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t); extern struct key *key_match_for_accept(const struct keychain *, const char *); extern struct key *key_lookup_for_send(const struct keychain *); - +const char *keychain_algo_str(enum keychain_hash_algo hash_algo); #ifdef __cplusplus } #endif diff --git a/lib/lib_errors.c b/lib/lib_errors.c index acc9a05c3..a658e4c29 100644 --- a/lib/lib_errors.c +++ b/lib/lib_errors.c @@ -68,6 +68,12 @@ static struct log_ref ferr_lib_warn[] = { .description = "The Event subsystem has detected a file descriptor read/write event without an associated handling function. This is a bug, please collect log data and open an issue.", .suggestion = "Gather log data and open an Issue", }, + { + .code = EC_LIB_TIMER_TOO_LONG, + .title = "The Event subsystem has detected an internal timer that is scheduled to pop in greater than one year", + .description = "The Event subsystem has detected a timer being started that will pop in a timer that is greater than one year. This is a bug, please collect log data and open an issue.", + .suggestion = "Gather log data and open an Issue", + }, { .code = EC_LIB_RMAP_RECURSION_LIMIT, .title = "Reached the Route-Map Recursion Limit", diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 64ac6c1ce..91f206f74 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -48,6 +48,7 @@ enum lib_log_refs { EC_LIB_SLOW_THREAD_WALL, EC_LIB_STARVE_THREAD, EC_LIB_NO_THREAD, + EC_LIB_TIMER_TOO_LONG, EC_LIB_RMAP_RECURSION_LIMIT, EC_LIB_BACKUP_CONFIG, EC_LIB_VRF_LENGTH, diff --git a/lib/libfrr.c b/lib/libfrr.c index 89bbe6de2..042c9d370 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -46,6 +46,7 @@ #include "frrscript.h" #include "systemd.h" +DEFINE_HOOK(frr_early_init, (struct thread_master * tm), (tm)); DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)); DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm)); DEFINE_HOOK(frr_config_post, (struct thread_master * tm), (tm)); @@ -332,6 +333,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) umask(0027); + log_args_init(daemon->early_logging); + opt_extend(&os_always); if (!(di->flags & FRR_NO_SPLIT_CONFIG)) opt_extend(&os_cfg); @@ -430,6 +433,8 @@ static int frr_opt(int opt) static int vty_port_set = 0; static int vty_addr_set = 0; struct option_chain *oc; + struct log_arg *log_arg; + size_t arg_len; char *err; switch (opt) { @@ -612,7 +617,10 @@ static int frr_opt(int opt) di->privs->group = optarg; break; case OPTION_LOG: - di->early_logging = optarg; + arg_len = strlen(optarg) + 1; + log_arg = XCALLOC(MTYPE_TMP, sizeof(*log_arg) + arg_len); + memcpy(log_arg->target, optarg, arg_len); + log_args_add_tail(di->early_logging, log_arg); break; case OPTION_LOGLEVEL: di->early_loglevel = optarg; @@ -705,10 +713,12 @@ static struct thread_master *master; struct thread_master *frr_init(void) { struct option_chain *oc; + struct log_arg *log_arg; struct frrmod_runtime *module; struct zprivs_ids_t ids; char p_instance[16] = "", p_pathspace[256] = ""; const char *dir; + dir = di->module_path ? di->module_path : frr_moduledir; srandom(time(NULL)); @@ -738,7 +748,11 @@ struct thread_master *frr_init(void) zlog_init(di->progname, di->logname, di->instance, ids.uid_normal, ids.gid_normal); - command_setup_early_logging(di->early_logging, di->early_loglevel); + while ((log_arg = log_args_pop(di->early_logging))) { + command_setup_early_logging(log_arg->target, + di->early_loglevel); + XFREE(MTYPE_TMP, log_arg); + } if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len, frr_zclientpath)) { @@ -770,6 +784,7 @@ struct thread_master *frr_init(void) master = thread_master_create(NULL); signal_init(master, di->n_signals, di->signals); + hook_call(frr_early_init, master); #ifdef HAVE_SQLITE3 if (!di->db_file) @@ -960,7 +975,7 @@ static void frr_daemonize(void) * to read the config in after thread execution starts, so that * we can match this behavior. */ -static int frr_config_read_in(struct thread *t) +static void frr_config_read_in(struct thread *t) { hook_call(frr_config_pre, master); @@ -998,8 +1013,6 @@ static int frr_config_read_in(struct thread *t) } hook_call(frr_config_post, master); - - return 0; } void frr_config_fork(void) @@ -1095,7 +1108,7 @@ static void frr_terminal_close(int isexit) static struct thread *daemon_ctl_thread = NULL; -static int frr_daemon_ctl(struct thread *t) +static void frr_daemon_ctl(struct thread *t) { char buf[1]; ssize_t nr; @@ -1104,7 +1117,7 @@ static int frr_daemon_ctl(struct thread *t) if (nr < 0 && (errno == EINTR || errno == EAGAIN)) goto out; if (nr <= 0) - return 0; + return; switch (buf[0]) { case 'S': /* SIGTSTP */ @@ -1129,7 +1142,6 @@ static int frr_daemon_ctl(struct thread *t) out: thread_add_read(master, frr_daemon_ctl, NULL, daemon_ctl_sock, &daemon_ctl_thread); - return 0; } void frr_detach(void) diff --git a/lib/libfrr.h b/lib/libfrr.h index e0642ef84..69054e426 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -21,6 +21,7 @@ #ifndef _ZEBRA_FRR_H #define _ZEBRA_FRR_H +#include "typesafe.h" #include "sigevent.h" #include "privs.h" #include "thread.h" @@ -52,6 +53,14 @@ extern "C" { */ #define FRR_DETACH_LATER (1 << 6) +PREDECL_DLIST(log_args); +struct log_arg { + struct log_args_item itm; + + char target[0]; +}; +DECLARE_DLIST(log_args, struct log_arg, itm); + enum frr_cli_mode { FRR_CLI_CLASSIC = 0, FRR_CLI_TRANSACTIONAL, @@ -88,7 +97,7 @@ struct frr_daemon_info { const char *pathspace; bool zpathspace; - const char *early_logging; + struct log_args_head early_logging[1]; const char *early_loglevel; const char *proghelp; @@ -144,6 +153,7 @@ extern uint32_t frr_get_fd_limit(void); extern bool frr_is_startup_fd(int fd); /* call order of these hooks is as ordered here */ +DECLARE_HOOK(frr_early_init, (struct thread_master * tm), (tm)); DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm)); /* fork() happens between late_init and config_pre */ DECLARE_HOOK(frr_config_pre, (struct thread_master * tm), (tm)); diff --git a/lib/log_vty.c b/lib/log_vty.c index 621949ab5..81280f302 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -24,8 +24,10 @@ #include "command.h" #include "lib/log.h" #include "lib/zlog_targets.h" +#include "lib/zlog_5424.h" #include "lib/lib_errors.h" #include "lib/printfrr.h" +#include "lib/systemd.h" #ifndef VTYSH_EXTRACT_PL #include "lib/log_vty_clippy.c" @@ -51,15 +53,34 @@ static struct zlog_cfg_file zt_file_cmdline = { static struct zlog_cfg_file zt_file = { .prio_min = ZLOG_DISABLED, }; -static struct zlog_cfg_file zt_stdout = { - .prio_min = ZLOG_DISABLED, -}; static struct zlog_cfg_filterfile zt_filterfile = { .parent = { .prio_min = ZLOG_DISABLED, }, }; +static struct zlog_cfg_file zt_stdout_file = { + .prio_min = ZLOG_DISABLED, +}; +static struct zlog_cfg_5424 zt_stdout_journald = { + .prio_min = ZLOG_DISABLED, + + .fmt = ZLOG_FMT_JOURNALD, + .dst = ZLOG_5424_DST_UNIX, + .filename = "/run/systemd/journal/socket", + + /* this can't be changed through config since this target substitutes + * in for the "plain" stdout target + */ + .facility = LOG_DAEMON, + .kw_version = false, + .kw_location = true, + .kw_uid = true, + .kw_ec = true, + .kw_args = true, +}; +static bool stdout_journald_in_use; + const char *zlog_progname; static const char *zlog_protoname; @@ -138,6 +159,7 @@ void zlog_rotate(void) { zlog_file_rotate(&zt_file); zlog_file_rotate(&zt_filterfile.parent); + zlog_file_rotate(&zt_file_cmdline); hook_call(zlog_rotate); } @@ -162,14 +184,18 @@ DEFUN_NOSH (show_logging, SHOW_STR "Show current logging configuration\n") { + int stdout_prio; + log_show_syslog(vty); + stdout_prio = stdout_journald_in_use ? zt_stdout_journald.prio_min + : zt_stdout_file.prio_min; + vty_out(vty, "Stdout logging: "); - if (zt_stdout.prio_min == ZLOG_DISABLED) + if (stdout_prio == ZLOG_DISABLED) vty_out(vty, "disabled"); else - vty_out(vty, "level %s", - zlog_priority[zt_stdout.prio_min]); + vty_out(vty, "level %s", zlog_priority[stdout_prio]); vty_out(vty, "\n"); vty_out(vty, "File logging: "); @@ -209,6 +235,21 @@ DEFUN_NOSH (show_logging, return CMD_SUCCESS; } +static void log_stdout_apply_level(void) +{ + int maxlvl; + + maxlvl = ZLOG_MAXLVL(log_config_stdout_lvl, log_cmdline_stdout_lvl); + + if (stdout_journald_in_use) { + zt_stdout_journald.prio_min = maxlvl; + zlog_5424_apply_meta(&zt_stdout_journald); + } else { + zt_stdout_file.prio_min = maxlvl; + zlog_file_set_other(&zt_stdout_file); + } +} + DEFPY (config_log_stdout, config_log_stdout_cmd, "log stdout [$levelarg]", @@ -226,9 +267,7 @@ DEFPY (config_log_stdout, level = log_default_lvl; log_config_stdout_lvl = level; - zt_stdout.prio_min = ZLOG_MAXLVL(log_config_stdout_lvl, - log_cmdline_stdout_lvl); - zlog_file_set_other(&zt_stdout); + log_stdout_apply_level(); return CMD_SUCCESS; } @@ -241,9 +280,7 @@ DEFUN (no_config_log_stdout, LOG_LEVEL_DESC) { log_config_stdout_lvl = ZLOG_DISABLED; - zt_stdout.prio_min = ZLOG_MAXLVL(log_config_stdout_lvl, - log_cmdline_stdout_lvl); - zlog_file_set_other(&zt_stdout); + log_stdout_apply_level(); return CMD_SUCCESS; } @@ -377,9 +414,7 @@ void command_setup_early_logging(const char *dest, const char *level) if (strcmp(type, "stdout") == 0) { log_cmdline_stdout_lvl = nlevel; - zt_stdout.prio_min = ZLOG_MAXLVL(log_config_stdout_lvl, - log_cmdline_stdout_lvl); - zlog_file_set_other(&zt_stdout); + log_stdout_apply_level(); return; } if (strcmp(type, "syslog") == 0) { @@ -393,6 +428,22 @@ void command_setup_early_logging(const char *dest, const char *level) set_log_file(&zt_file_cmdline, NULL, sep, nlevel); return; } + if (strcmp(type, "monitor") == 0 && sep) { + struct zlog_live_cfg cfg = {}; + unsigned long fd; + char *endp; + + sep++; + fd = strtoul(sep, &endp, 10); + if (!*sep || *endp) { + fprintf(stderr, "invalid monitor fd \"%s\"\n", sep); + exit(1); + } + + zlog_live_open_fd(&cfg, nlevel, fd); + zlog_live_disown(&cfg); + return; + } fprintf(stderr, "invalid log target \"%s\" (\"%s\")\n", type, dest); exit(1); @@ -413,9 +464,7 @@ DEFUN (clear_log_cmdline, log_cmdline_syslog_lvl)); log_cmdline_stdout_lvl = ZLOG_DISABLED; - zt_stdout.prio_min = ZLOG_MAXLVL(log_config_stdout_lvl, - log_cmdline_stdout_lvl); - zlog_file_set_other(&zt_stdout); + log_stdout_apply_level(); return CMD_SUCCESS; } @@ -523,8 +572,10 @@ DEFUN (config_log_record_priority, { zt_file.record_priority = true; zlog_file_set_other(&zt_file); - zt_stdout.record_priority = true; - zlog_file_set_other(&zt_stdout); + if (!stdout_journald_in_use) { + zt_stdout_file.record_priority = true; + zlog_file_set_other(&zt_stdout_file); + } zt_filterfile.parent.record_priority = true; zlog_file_set_other(&zt_filterfile.parent); return CMD_SUCCESS; @@ -539,8 +590,10 @@ DEFUN (no_config_log_record_priority, { zt_file.record_priority = false; zlog_file_set_other(&zt_file); - zt_stdout.record_priority = false; - zlog_file_set_other(&zt_stdout); + if (!stdout_journald_in_use) { + zt_stdout_file.record_priority = false; + zlog_file_set_other(&zt_stdout_file); + } zt_filterfile.parent.record_priority = false; zlog_file_set_other(&zt_filterfile.parent); return CMD_SUCCESS; @@ -556,8 +609,10 @@ DEFPY (config_log_timestamp_precision, { zt_file.ts_subsec = precision; zlog_file_set_other(&zt_file); - zt_stdout.ts_subsec = precision; - zlog_file_set_other(&zt_stdout); + if (!stdout_journald_in_use) { + zt_stdout_file.ts_subsec = precision; + zlog_file_set_other(&zt_stdout_file); + } zt_filterfile.parent.ts_subsec = precision; zlog_file_set_other(&zt_filterfile.parent); return CMD_SUCCESS; @@ -574,8 +629,10 @@ DEFUN (no_config_log_timestamp_precision, { zt_file.ts_subsec = 0; zlog_file_set_other(&zt_file); - zt_stdout.ts_subsec = 0; - zlog_file_set_other(&zt_stdout); + if (!stdout_journald_in_use) { + zt_stdout_file.ts_subsec = 0; + zlog_file_set_other(&zt_stdout_file); + } zt_filterfile.parent.ts_subsec = 0; zlog_file_set_other(&zt_filterfile.parent); return CMD_SUCCESS; @@ -821,7 +878,12 @@ static int log_vty_init(const char *progname, const char *protoname, zlog_filterfile_init(&zt_filterfile); - zlog_file_set_fd(&zt_stdout, STDOUT_FILENO); + if (sd_stdout_is_journal) { + stdout_journald_in_use = true; + zlog_5424_init(&zt_stdout_journald); + zlog_5424_apply_dst(&zt_stdout_journald); + } else + zlog_file_set_fd(&zt_stdout_file, STDOUT_FILENO); return 0; } @@ -861,4 +923,6 @@ void log_cmd_init(void) install_element(ENABLE_NODE, &debug_uid_backtrace_cmd); install_element(CONFIG_NODE, &debug_uid_backtrace_cmd); + + log_5424_cmd_init(); } diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 70c71b18c..1e25f6a1e 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -347,7 +347,7 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty) return ret; } -static int nb_cli_confirmed_commit_timeout(struct thread *thread) +static void nb_cli_confirmed_commit_timeout(struct thread *thread) { struct vty *vty = THREAD_ARG(thread); @@ -357,8 +357,6 @@ static int nb_cli_confirmed_commit_timeout(struct thread *thread) nb_cli_confirmed_commit_rollback(vty); nb_cli_confirmed_commit_clean(vty); - - return 0; } static int nb_cli_commit(struct vty *vty, bool force, diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index e1c8983fc..27eaefd07 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -283,7 +283,7 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op, return ITER_RECURSE; } -static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) +static void frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) { struct nb_context context = {}; struct nb_config *candidate; @@ -313,9 +313,9 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) 0, "Couldn't apply configuration changes") != CONFD_OK) { flog_err_confd("cdb_sub_abort_trans"); - return -1; + return; } - return 0; + return; } /* @@ -346,25 +346,23 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) errmsg) != CONFD_OK) { flog_err_confd("cdb_sub_abort_trans"); - return -1; + return; } } else { /* Acknowledge the notification. */ if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY) != CONFD_OK) { flog_err_confd("cdb_sync_subscription_socket"); - return -1; + return; } /* No configuration changes. */ if (!transaction) nb_config_free(candidate); } - - return 0; } -static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen) +static void frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen) { /* * No need to process the configuration changes again as we're already @@ -385,10 +383,8 @@ static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen) /* Acknowledge the notification. */ if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY) != CONFD_OK) { flog_err_confd("cdb_sync_subscription_socket"); - return -1; + return; } - - return 0; } static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen) @@ -417,7 +413,7 @@ static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen) return 0; } -static int frr_confd_cdb_read_cb(struct thread *thread) +static void frr_confd_cdb_read_cb(struct thread *thread) { int fd = THREAD_FD(thread); enum cdb_sub_notification cdb_ev; @@ -430,19 +426,22 @@ static int frr_confd_cdb_read_cb(struct thread *thread) if (cdb_read_subscription_socket2(fd, &cdb_ev, &flags, &subp, &reslen) != CONFD_OK) { flog_err_confd("cdb_read_subscription_socket2"); - return -1; + return; } switch (cdb_ev) { case CDB_SUB_PREPARE: - return frr_confd_cdb_read_cb_prepare(fd, subp, reslen); + frr_confd_cdb_read_cb_prepare(fd, subp, reslen); + break; case CDB_SUB_COMMIT: - return frr_confd_cdb_read_cb_commit(fd, subp, reslen); + frr_confd_cdb_read_cb_commit(fd, subp, reslen); + break; case CDB_SUB_ABORT: - return frr_confd_cdb_read_cb_abort(fd, subp, reslen); + frr_confd_cdb_read_cb_abort(fd, subp, reslen); + break; default: flog_err_confd("unknown CDB event"); - return -1; + break; } } @@ -1186,7 +1185,7 @@ static int frr_confd_dp_read(struct confd_daemon_ctx *dctx, int fd) return 0; } -static int frr_confd_dp_ctl_read(struct thread *thread) +static void frr_confd_dp_ctl_read(struct thread *thread) { struct confd_daemon_ctx *dctx = THREAD_ARG(thread); int fd = THREAD_FD(thread); @@ -1194,11 +1193,9 @@ static int frr_confd_dp_ctl_read(struct thread *thread) thread_add_read(master, frr_confd_dp_ctl_read, dctx, fd, &t_dp_ctl); frr_confd_dp_read(dctx, fd); - - return 0; } -static int frr_confd_dp_worker_read(struct thread *thread) +static void frr_confd_dp_worker_read(struct thread *thread) { struct confd_daemon_ctx *dctx = THREAD_ARG(thread); int fd = THREAD_FD(thread); @@ -1206,8 +1203,6 @@ static int frr_confd_dp_worker_read(struct thread *thread) thread_add_read(master, frr_confd_dp_worker_read, dctx, fd, &t_dp_worker); frr_confd_dp_read(dctx, fd); - - return 0; } static int frr_confd_subscribe_state(const struct lysc_node *snode, void *arg) diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index e227d0385..e2a629003 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -1,7 +1,7 @@ // +// Copyright (c) 2021-2022, LabN Consulting, L.L.C // Copyright (C) 2019 NetDEF, Inc. // Renato Westphal -// Copyright (c) 2021, LabN Consulting, L.L.C // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free @@ -50,6 +50,8 @@ static struct thread_master *main_master; static struct frr_pthread *fpt; +static bool grpc_running; + #define grpc_debug(...) \ do { \ if (nb_dbg_client_grpc) \ @@ -96,11 +98,11 @@ class Candidates { char errmsg[BUFSIZ] = {0}; - _cdb.erase(c->id); nb_config_free(c->config); if (c->transaction) nb_candidate_commit_abort(c->transaction, errmsg, sizeof(errmsg)); + _cdb.erase(c->id); } struct candidate *get_candidate(uint32_t id) @@ -116,9 +118,11 @@ class Candidates class RpcStateBase { public: + virtual ~RpcStateBase() = default; virtual CallState doCallback() = 0; virtual void do_request(::frr::Northbound::AsyncService *service, - ::grpc::ServerCompletionQueue *cq) = 0; + ::grpc::ServerCompletionQueue *cq, + bool no_copy) = 0; }; /* @@ -188,17 +192,22 @@ template class NewRpcState : RpcStateBase } void do_request(::frr::Northbound::AsyncService *service, - ::grpc::ServerCompletionQueue *cq) override + ::grpc::ServerCompletionQueue *cq, + bool no_copy) override { grpc_debug("%s, posting a request for: %s", __func__, name); if (requestf) { NewRpcState *copy = - new NewRpcState(cdb, requestf, callback, name); + no_copy ? this + : new NewRpcState(cdb, requestf, + callback, name); (service->*requestf)(©->ctx, ©->request, ©->responder, cq, cq, copy); } else { NewRpcState *copy = - new NewRpcState(cdb, requestsf, callback, name); + no_copy ? this + : new NewRpcState(cdb, requestsf, + callback, name); (service->*requestsf)(©->ctx, ©->request, ©->async_responder, cq, cq, copy); @@ -206,7 +215,7 @@ template class NewRpcState : RpcStateBase } - static int c_callback(struct thread *thread) + static void c_callback(struct thread *thread) { auto _tag = static_cast *>(thread->arg); /* @@ -225,9 +234,8 @@ template class NewRpcState : RpcStateBase pthread_cond_signal(&_tag->cond); pthread_mutex_unlock(&_tag->cmux); - return 0; + return; } - NewRpcState *orig; const char *name; grpc::ServerContext ctx; @@ -238,12 +246,12 @@ template class NewRpcState : RpcStateBase Candidates *cdb; void (*callback)(NewRpcState *); - reqfunc_t requestf; - reqsfunc_t requestsf; + reqfunc_t requestf = NULL; + reqsfunc_t requestsf = NULL; pthread_mutex_t cmux = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; - void *context; + void *context = 0; CallState state = CREATE; }; @@ -268,10 +276,10 @@ static LYD_FORMAT encoding2lyd_format(enum frr::Encoding encoding) } static int yang_dnode_edit(struct lyd_node *dnode, const std::string &path, - const std::string &value) + const char *value) { - LY_ERR err = lyd_new_path(dnode, ly_native_ctx, path.c_str(), - value.c_str(), LYD_NEW_PATH_UPDATE, &dnode); + LY_ERR err = lyd_new_path(dnode, ly_native_ctx, path.c_str(), value, + LYD_NEW_PATH_UPDATE, &dnode); if (err != LY_SUCCESS) { flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed: %s", __func__, ly_errmsg(ly_native_ctx)); @@ -698,8 +706,8 @@ void HandleUnaryEditCandidate( auto pvs = tag->request.update(); for (const frr::PathValue &pv : pvs) { - if (yang_dnode_edit(candidate_tmp->dnode, pv.path(), pv.value()) - != 0) { + if (yang_dnode_edit(candidate_tmp->dnode, pv.path(), + pv.value().c_str()) != 0) { nb_config_free(candidate_tmp); tag->responder.Finish( @@ -1226,7 +1234,7 @@ void HandleUnaryExecute( frr::NAME##Response>( \ (cdb), &frr::Northbound::AsyncService::Request##NAME, \ &HandleUnary##NAME, #NAME); \ - _rpcState->do_request(service, s_cq); \ + _rpcState->do_request(&service, cq.get(), true); \ } while (0) #define REQUEST_NEWRPC_STREAMING(NAME, cdb) \ @@ -1235,7 +1243,7 @@ void HandleUnaryExecute( frr::NAME##Response>( \ (cdb), &frr::Northbound::AsyncService::Request##NAME, \ &HandleStreaming##NAME, #NAME); \ - _rpcState->do_request(service, s_cq); \ + _rpcState->do_request(&service, cq.get(), true); \ } while (0) struct grpc_pthread_attr { @@ -1244,8 +1252,8 @@ struct grpc_pthread_attr { }; // Capture these objects so we can try to shut down cleanly -static std::unique_ptr s_server; -static grpc::ServerCompletionQueue *s_cq; +static pthread_mutex_t s_server_lock = PTHREAD_MUTEX_INITIALIZER; +static grpc::Server *s_server; static void *grpc_pthread_start(void *arg) { @@ -1255,18 +1263,22 @@ static void *grpc_pthread_start(void *arg) Candidates candidates; grpc::ServerBuilder builder; std::stringstream server_address; - frr::Northbound::AsyncService *service = - new frr::Northbound::AsyncService(); + frr::Northbound::AsyncService service; frr_pthread_set_name(fpt); server_address << "0.0.0.0:" << port; builder.AddListeningPort(server_address.str(), grpc::InsecureServerCredentials()); - builder.RegisterService(service); - auto cq = builder.AddCompletionQueue(); - s_cq = cq.get(); - s_server = builder.BuildAndStart(); + builder.RegisterService(&service); + builder.AddChannelArgument( + GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, 5000); + std::unique_ptr cq = + builder.AddCompletionQueue(); + std::unique_ptr server = builder.BuildAndStart(); + s_server = server.get(); + + grpc_running = true; /* Schedule all RPC handlers */ REQUEST_NEWRPC(GetCapabilities, NULL); @@ -1287,20 +1299,25 @@ static void *grpc_pthread_start(void *arg) server_address.str().c_str()); /* Process inbound RPCs */ - while (true) { - void *tag; - bool ok; - - s_cq->Next(&tag, &ok); - if (!ok) + bool ok; + void *tag; + while (grpc_running) { + if (!cq->Next(&tag, &ok)) { + grpc_debug("%s: CQ empty exiting", __func__); break; + } + + grpc_debug("%s: got next from CQ tag: %p ok: %d", __func__, tag, + ok); - grpc_debug("%s: Got next from CompletionQueue, %p %d", __func__, - tag, ok); + if (!ok || !grpc_running) { + delete static_cast(tag); + break; + } RpcStateBase *rpc = static_cast(tag); CallState state = rpc->doCallback(); - grpc_debug("%s: Callback returned RPC State: %s", __func__, + grpc_debug("%s: callback returned RPC State: %s", __func__, call_states[state]); /* @@ -1310,10 +1327,30 @@ static void *grpc_pthread_start(void *arg) * to be called back once more in the FINISH state (from the * user indicating Finish() for cleanup. */ - if (state == FINISH) - rpc->do_request(service, s_cq); + if (state == FINISH && grpc_running) + rpc->do_request(&service, cq.get(), false); + } + + /* This was probably done for us to get here, but let's be safe */ + pthread_mutex_lock(&s_server_lock); + grpc_running = false; + if (s_server) { + grpc_debug("%s: shutdown server and CQ", __func__); + server->Shutdown(); + s_server = NULL; + } + pthread_mutex_unlock(&s_server_lock); + + grpc_debug("%s: shutting down CQ", __func__); + cq->Shutdown(); + + grpc_debug("%s: draining the CQ", __func__); + while (cq->Next(&tag, &ok)) { + grpc_debug("%s: drain tag %p", __func__, tag); + delete static_cast(tag); } + zlog_info("%s: exiting from grpc pthread", __func__); return NULL; } @@ -1325,6 +1362,8 @@ static int frr_grpc_init(uint port) .stop = NULL, }; + grpc_debug("%s: entered", __func__); + fpt = frr_pthread_new(&attr, "frr-grpc", "frr-grpc"); fpt->data = reinterpret_cast((intptr_t)port); @@ -1340,24 +1379,27 @@ static int frr_grpc_init(uint port) static int frr_grpc_finish(void) { - // Shutdown the grpc server - if (s_server) { - s_server->Shutdown(); - s_cq->Shutdown(); + grpc_debug("%s: entered", __func__); - // And drain the queue - void *ignore; - bool ok; - - while (s_cq->Next(&ignore, &ok)) - ; - } + if (!fpt) + return 0; - if (fpt) { - pthread_join(fpt->thread, NULL); - frr_pthread_destroy(fpt); + /* + * Shut the server down here in main thread. This will cause the wait on + * the completion queue (cq.Next()) to exit and cleanup everything else. + */ + pthread_mutex_lock(&s_server_lock); + grpc_running = false; + if (s_server) { + grpc_debug("%s: shutdown server", __func__); + s_server->Shutdown(); + s_server = NULL; } + pthread_mutex_unlock(&s_server_lock); + grpc_debug("%s: joining and destroy grpc thread", __func__); + pthread_join(fpt->thread, NULL); + frr_pthread_destroy(fpt); return 0; } @@ -1368,7 +1410,7 @@ static int frr_grpc_finish(void) * fork. This is done by scheduling this init function as an event task, since * the event loop doesn't run until after fork. */ -static int frr_grpc_module_very_late_init(struct thread *thread) +static void frr_grpc_module_very_late_init(struct thread *thread) { const char *args = THIS_MODULE->load_args; uint port = GRPC_DEFAULT_PORT; @@ -1386,11 +1428,10 @@ static int frr_grpc_module_very_late_init(struct thread *thread) if (frr_grpc_init(port) < 0) goto error; - return 0; + return; error: flog_err(EC_LIB_GRPC_INIT, "failed to initialize the gRPC module"); - return -1; } static int frr_grpc_module_late_init(struct thread_master *tm) diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 86a159e50..0158d8ea0 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -41,7 +41,7 @@ static sr_session_ctx_t *session; static sr_conn_ctx_t *connection; static struct nb_transaction *transaction; -static int frr_sr_read_cb(struct thread *thread); +static void frr_sr_read_cb(struct thread *thread); static int frr_sr_finish(void); /* Convert FRR YANG data value to sysrepo YANG data value. */ @@ -526,7 +526,7 @@ static int frr_sr_notification_send(const char *xpath, struct list *arguments) return NB_OK; } -static int frr_sr_read_cb(struct thread *thread) +static void frr_sr_read_cb(struct thread *thread) { struct yang_module *module = THREAD_ARG(thread); int fd = THREAD_FD(thread); @@ -536,12 +536,10 @@ static int frr_sr_read_cb(struct thread *thread) if (ret != SR_ERR_OK) { flog_err(EC_LIB_LIBSYSREPO, "%s: sr_fd_event_process(): %s", __func__, sr_strerror(ret)); - return -1; + return; } thread_add_read(master, frr_sr_read_cb, module, fd, &module->sr_thread); - - return 0; } static void frr_sr_subscribe_config(struct yang_module *module) diff --git a/lib/prefix.c b/lib/prefix.c index 90ab48a13b..89c5be8f3 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1071,6 +1071,26 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) return str; } +static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu) +{ + const struct prefix *p = pu.p; + char buf[PREFIX2STR_BUFFER]; + + switch (p->family) { + case AF_INET: + case AF_INET6: + inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)); + return bputs(fbuf, buf); + + case AF_ETHERNET: + prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)); + return bputs(fbuf, buf); + + default: + return bprintfrr(fbuf, "{prefix.af=%dPF}", p->family); + } +} + void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size) { @@ -1458,13 +1478,24 @@ printfrr_ext_autoreg_p("FX", printfrr_pfx); static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { - char cbuf[PREFIX_STRLEN]; + bool host_only = false; + + if (ea->fmt[0] == 'h') { + ea->fmt++; + host_only = true; + } if (!ptr) return bputs(buf, "(null)"); - prefix2str(ptr, cbuf, sizeof(cbuf)); - return bputs(buf, cbuf); + if (host_only) + return prefixhost2str(buf, (struct prefix *)ptr); + else { + char cbuf[PREFIX_STRLEN]; + + prefix2str(ptr, cbuf, sizeof(cbuf)); + return bputs(buf, cbuf); + } } printfrr_ext_autoreg_p("PSG4", printfrr_psg); diff --git a/lib/prefix.h b/lib/prefix.h index f2773240d..b3545a72b 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -341,9 +341,6 @@ union prefixconstptr { prefixtype(prefixconstptr, const struct prefix_rd, rd) } TRANSPARENT_UNION; -#undef prefixtype -#undef TRANSPARENT_UNION - #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif /* INET_ADDRSTRLEN */ diff --git a/lib/pullwr.c b/lib/pullwr.c index 15563d247..5e836984b 100644 --- a/lib/pullwr.c +++ b/lib/pullwr.c @@ -51,7 +51,7 @@ struct pullwr { DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller"); DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF, "pull-driven write buffer"); -static int pullwr_run(struct thread *t); +static void pullwr_run(struct thread *t); struct pullwr *_pullwr_new(struct thread_master *tm, int fd, void *arg, @@ -189,7 +189,7 @@ void pullwr_write(struct pullwr *pullwr, const void *data, size_t len) pullwr_bump(pullwr); } -static int pullwr_run(struct thread *t) +static void pullwr_run(struct thread *t) { struct pullwr *pullwr = THREAD_ARG(t); struct iovec iov[2]; @@ -222,7 +222,7 @@ static int pullwr_run(struct thread *t) * into idle, i.e. no calling thread_add_write() */ pullwr_resize(pullwr, 0); - return 0; + return; } niov = pullwr_iov(pullwr, iov); @@ -233,12 +233,12 @@ static int pullwr_run(struct thread *t) if (errno == EAGAIN || errno == EWOULDBLOCK) break; pullwr->err(pullwr->arg, pullwr, false); - return 0; + return; } if (nwr == 0) { pullwr->err(pullwr->arg, pullwr, true); - return 0; + return; } pullwr->total_written += nwr; @@ -258,7 +258,6 @@ static int pullwr_run(struct thread *t) */ if (!maxspun) pullwr_resize(pullwr, 0); - return 0; } void pullwr_stats(struct pullwr *pullwr, uint64_t *total_written, diff --git a/lib/resolver.c b/lib/resolver.c index 29138bbc8..93fa84bbe 100644 --- a/lib/resolver.c +++ b/lib/resolver.c @@ -104,17 +104,15 @@ static void resolver_fd_drop_maybe(struct resolver_fd *resfd) static void resolver_update_timeouts(struct resolver_state *r); -static int resolver_cb_timeout(struct thread *t) +static void resolver_cb_timeout(struct thread *t) { struct resolver_state *r = THREAD_ARG(t); ares_process(r->channel, NULL, NULL); resolver_update_timeouts(r); - - return 0; } -static int resolver_cb_socket_readable(struct thread *t) +static void resolver_cb_socket_readable(struct thread *t) { struct resolver_fd *resfd = THREAD_ARG(t); struct resolver_state *r = resfd->state; @@ -127,11 +125,9 @@ static int resolver_cb_socket_readable(struct thread *t) */ ares_process_fd(r->channel, resfd->fd, ARES_SOCKET_BAD); resolver_update_timeouts(r); - - return 0; } -static int resolver_cb_socket_writable(struct thread *t) +static void resolver_cb_socket_writable(struct thread *t) { struct resolver_fd *resfd = THREAD_ARG(t); struct resolver_state *r = resfd->state; @@ -144,8 +140,6 @@ static int resolver_cb_socket_writable(struct thread *t) */ ares_process_fd(r->channel, ARES_SOCKET_BAD, resfd->fd); resolver_update_timeouts(r); - - return 0; } static void resolver_update_timeouts(struct resolver_state *r) @@ -232,7 +226,7 @@ static void ares_address_cb(void *arg, int status, int timeouts, callback(query, NULL, i, &addr[0]); } -static int resolver_cb_literal(struct thread *t) +static void resolver_cb_literal(struct thread *t) { struct resolver_query *query = THREAD_ARG(t); void (*callback)(struct resolver_query *, const char *, int, @@ -242,7 +236,6 @@ static int resolver_cb_literal(struct thread *t) query->callback = NULL; callback(query, ARES_SUCCESS, 1, &query->literal_addr); - return 0; } void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id, diff --git a/lib/routemap.c b/lib/routemap.c index 7f733c811..46161fd81 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -100,6 +100,7 @@ static void route_map_del_plist_entries(afi_t afi, struct prefix_list_entry *entry); static struct hash *route_map_get_dep_hash(route_map_event_t event); +static void route_map_free_map(struct route_map *map); struct route_map_match_set_hooks rmap_match_set_hook; @@ -566,15 +567,8 @@ static bool route_map_hash_cmp(const void *p1, const void *p2) const struct route_map *map1 = p1; const struct route_map *map2 = p2; - if (map1->deleted == map2->deleted) { - if (map1->name && map2->name) { - if (!strcmp(map1->name, map2->name)) { - return true; - } - } else if (!map1->name && !map2->name) { - return true; - } - } + if (!strcmp(map1->name, map2->name)) + return true; return false; } @@ -636,13 +630,25 @@ static struct route_map *route_map_new(const char *name) /* Add new name to route_map. */ static struct route_map *route_map_add(const char *name) { - struct route_map *map; + struct route_map *map, *exist; struct route_map_list *list; map = route_map_new(name); list = &route_map_master; - /* Add map to the hash */ + /* + * Add map to the hash + * + * If the map already exists in the hash, then we know that + * FRR is now in a sequence of delete/create. + * All FRR needs to do here is set the to_be_processed + * bit (to inherit from the old one + */ + exist = hash_release(route_map_master_hash, map); + if (exist) { + map->to_be_processed = exist->to_be_processed; + route_map_free_map(exist); + } hash_get(route_map_master_hash, map, hash_alloc_intern); /* Add new entry to the head of the list to match how it is added in the @@ -752,11 +758,15 @@ struct route_map *route_map_lookup_by_name(const char *name) if (!name) return NULL; - // map.deleted is 0 via memset + // map.deleted is false via memset memset(&tmp_map, 0, sizeof(struct route_map)); tmp_map.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name); map = hash_lookup(route_map_master_hash, &tmp_map); XFREE(MTYPE_ROUTE_MAP_NAME, tmp_map.name); + + if (map && map->deleted) + return NULL; + return map; } @@ -1799,12 +1809,11 @@ static struct list *route_map_get_index_list(struct route_node **rn, /* * This function returns the route-map index that best matches the prefix. */ -static struct route_map_index *route_map_get_index(struct route_map *map, - const struct prefix *prefix, - void *object, - uint8_t *match_ret) +static struct route_map_index * +route_map_get_index(struct route_map *map, const struct prefix *prefix, + void *object, enum route_map_cmd_result_t *match_ret) { - int ret = 0; + enum route_map_cmd_result_t ret = RMAP_NOMATCH; struct list *candidate_rmap_list = NULL; struct route_node *rn = NULL; struct listnode *ln = NULL, *nn = NULL; @@ -2559,7 +2568,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, if ((!map->optimization_disabled) && (map->ipv4_prefix_table || map->ipv6_prefix_table)) { index = route_map_get_index(map, prefix, match_object, - (uint8_t *)&match_ret); + &match_ret); if (index) { index->applied++; if (rmap_debug) diff --git a/lib/sigevent.c b/lib/sigevent.c index 00bc31f51..0f20bc027 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -143,7 +143,7 @@ int frr_sigevent_process(void) #ifdef SIGEVENT_SCHEDULE_THREAD /* timer thread to check signals. shouldn't be needed */ -int frr_signal_timer(struct thread *t) +void frr_signal_timer(struct thread *t) { struct frr_sigevent_master_t *sigm; @@ -151,7 +151,7 @@ int frr_signal_timer(struct thread *t) sigm->t = NULL; thread_add_timer(sigm->t->master, frr_signal_timer, &sigmaster, FRR_SIGNAL_TIMER_INTERVAL, &sigm->t); - return frr_sigevent_process(); + frr_sigevent_process(); } #endif /* SIGEVENT_SCHEDULE_THREAD */ diff --git a/lib/sockunion.c b/lib/sockunion.c index 006ac142a..9763b38e2 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -351,21 +351,6 @@ int sockopt_ttl(int family, int sock, int ttl) return 0; } -/* - * This function called setsockopt(.., TCP_CORK,...) - * Which on linux is a no-op since it is enabled by - * default and on BSD it uses TCP_NOPUSH to do - * the same thing( which it was not configured to - * use). This cleanup of the api occurred on 8/1/17 - * I imagine if after more than 1 year of no-one - * complaining, and a major upgrade release we - * can deprecate and remove this function call - */ -int sockopt_cork(int sock, int onoff) -{ - return 0; -} - int sockopt_minttl(int family, int sock, int minttl) { #ifdef IP_MINTTL diff --git a/lib/sockunion.h b/lib/sockunion.h index 9e6719ccf..8ace3e478 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -95,7 +95,6 @@ extern int sockunion_bind(int sock, union sockunion *, unsigned short, union sockunion *); extern int sockopt_ttl(int family, int sock, int ttl); extern int sockopt_minttl(int family, int sock, int minttl); -extern int sockopt_cork(int sock, int onoff); extern int sockunion_socket(const union sockunion *su); extern const char *inet_sutop(const union sockunion *su, char *str); extern enum connect_result sockunion_connect(int fd, const union sockunion *su, diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c index a273e9346..117b7d3e8 100644 --- a/lib/spf_backoff.c +++ b/lib/spf_backoff.c @@ -117,17 +117,16 @@ void spf_backoff_free(struct spf_backoff *backoff) XFREE(MTYPE_SPF_BACKOFF, backoff); } -static int spf_backoff_timetolearn_elapsed(struct thread *thread) +static void spf_backoff_timetolearn_elapsed(struct thread *thread) { struct spf_backoff *backoff = THREAD_ARG(thread); backoff->state = SPF_BACKOFF_LONG_WAIT; backoff_debug("SPF Back-off(%s) TIMETOLEARN elapsed, move to state %s", backoff->name, spf_backoff_state2str(backoff->state)); - return 0; } -static int spf_backoff_holddown_elapsed(struct thread *thread) +static void spf_backoff_holddown_elapsed(struct thread *thread) { struct spf_backoff *backoff = THREAD_ARG(thread); @@ -136,7 +135,6 @@ static int spf_backoff_holddown_elapsed(struct thread *thread) backoff->state = SPF_BACKOFF_QUIET; backoff_debug("SPF Back-off(%s) HOLDDOWN elapsed, move to state %s", backoff->name, spf_backoff_state2str(backoff->state)); - return 0; } long spf_backoff_schedule(struct spf_backoff *backoff) diff --git a/lib/subdir.am b/lib/subdir.am index bb10d71ed..b505e235c 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -8,6 +8,7 @@ lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST lib_libfrr_la_SOURCES = \ lib/agg_table.c \ lib/atomlist.c \ + lib/base64.c \ lib/bfd.c \ lib/buffer.c \ lib/checksum.c \ @@ -16,6 +17,7 @@ lib_libfrr_la_SOURCES = \ lib/command_lex.l \ lib/command_match.c \ lib/command_parse.y \ + lib/cspf.c \ lib/csv.c \ lib/debug.c \ lib/defaults.c \ @@ -110,6 +112,9 @@ lib_libfrr_la_SOURCES = \ lib/yang_wrappers.c \ lib/zclient.c \ lib/zlog.c \ + lib/zlog_5424.c \ + lib/zlog_5424_cli.c \ + lib/zlog_live.c \ lib/zlog_targets.c \ lib/printf/printf-pos.c \ lib/printf/vfprintf.c \ @@ -168,11 +173,13 @@ clippy_scan += \ lib/routemap_cli.c \ lib/thread.c \ lib/vty.c \ + lib/zlog_5424_cli.c \ # end pkginclude_HEADERS += \ lib/agg_table.h \ lib/atomlist.h \ + lib/base64.h \ lib/bfd.h \ lib/bitfield.h \ lib/buffer.h \ @@ -182,6 +189,7 @@ pkginclude_HEADERS += \ lib/command_graph.h \ lib/command_match.h \ lib/compiler.h \ + lib/cspf.h \ lib/csv.h \ lib/db.h \ lib/debug.h \ @@ -281,6 +289,8 @@ pkginclude_HEADERS += \ lib/zclient.h \ lib/zebra.h \ lib/zlog.h \ + lib/zlog_5424.h \ + lib/zlog_live.h \ lib/zlog_targets.h \ lib/pbr.h \ lib/routing_nb.h \ diff --git a/lib/systemd.c b/lib/systemd.c index 2238dc9f3..1c9a6f122 100644 --- a/lib/systemd.c +++ b/lib/systemd.c @@ -80,14 +80,13 @@ void systemd_send_stopping(void) static struct thread_master *systemd_master = NULL; -static int systemd_send_watchdog(struct thread *t) +static void systemd_send_watchdog(struct thread *t) { systemd_send_information("WATCHDOG=1"); assert(watchdog_msec > 0); thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL, watchdog_msec, NULL); - return 1; } void systemd_send_started(struct thread_master *m) diff --git a/lib/systemd.h b/lib/systemd.h index 1933f4f68..b9290930d 100644 --- a/lib/systemd.h +++ b/lib/systemd.h @@ -23,6 +23,10 @@ extern "C" { #endif +/* fd 1/2 connected to journald? */ +extern bool sd_stdout_is_journal; +extern bool sd_stderr_is_journal; + /* * Wrapper functions to systemd calls. * diff --git a/lib/thread.c b/lib/thread.c index 376f61c24..90074b3d8 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -138,11 +138,12 @@ static void cpu_record_hash_free(void *a) static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { - vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu", + vty_out(vty, + "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu %10zu", a->total_active, a->cpu.total / 1000, a->cpu.total % 1000, a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max, (a->real.total / a->total_calls), a->real.max, - a->total_cpu_warn, a->total_wall_warn); + a->total_cpu_warn, a->total_wall_warn, a->total_starv_warn); vty_out(vty, " %c%c%c%c%c %s\n", a->types & (1 << THREAD_READ) ? 'R' : ' ', a->types & (1 << THREAD_WRITE) ? 'W' : ' ', @@ -168,6 +169,8 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) atomic_load_explicit(&a->total_cpu_warn, memory_order_seq_cst); copy.total_wall_warn = atomic_load_explicit(&a->total_wall_warn, memory_order_seq_cst); + copy.total_starv_warn = atomic_load_explicit(&a->total_starv_warn, + memory_order_seq_cst); copy.cpu.total = atomic_load_explicit(&a->cpu.total, memory_order_seq_cst); copy.cpu.max = atomic_load_explicit(&a->cpu.max, memory_order_seq_cst); @@ -186,6 +189,7 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) totals->total_calls += copy.total_calls; totals->total_cpu_warn += copy.total_cpu_warn; totals->total_wall_warn += copy.total_wall_warn; + totals->total_starv_warn += copy.total_starv_warn; totals->real.total += copy.real.total; if (totals->real.max < copy.real.max) totals->real.max = copy.real.max; @@ -231,7 +235,8 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs"); vty_out(vty, " Avg uSec Max uSecs"); - vty_out(vty, " CPU_Warn Wall_Warn Type Thread\n"); + vty_out(vty, + " CPU_Warn Wall_Warn Starv_Warn Type Thread\n"); if (m->cpu_record->count) hash_iterate( @@ -493,6 +498,41 @@ DEFUN (clear_thread_cpu, return CMD_SUCCESS; } +static void show_thread_timers_helper(struct vty *vty, struct thread_master *m) +{ + const char *name = m->name ? m->name : "main"; + char underline[strlen(name) + 1]; + struct thread *thread; + + memset(underline, '-', sizeof(underline)); + underline[sizeof(underline) - 1] = '\0'; + + vty_out(vty, "\nShowing timers for %s\n", name); + vty_out(vty, "-------------------%s\n", underline); + + frr_each (thread_timer_list, &m->timer, thread) { + vty_out(vty, " %-50s%pTH\n", thread->hist->funcname, thread); + } +} + +DEFPY_NOSH (show_thread_timers, + show_thread_timers_cmd, + "show thread timers", + SHOW_STR + "Thread information\n" + "Show all timers and how long they have in the system\n") +{ + struct listnode *node; + struct thread_master *m; + + frr_with_mutex (&masters_mtx) { + for (ALL_LIST_ELEMENTS_RO(masters, node, m)) + show_thread_timers_helper(vty, m); + } + + return CMD_SUCCESS; +} + void thread_cmd_init(void) { install_element(VIEW_NODE, &show_thread_cpu_cmd); @@ -504,6 +544,8 @@ void thread_cmd_init(void) install_element(CONFIG_NODE, &no_service_cputime_warning_cmd); install_element(CONFIG_NODE, &service_walltime_warning_cmd); install_element(CONFIG_NODE, &no_service_walltime_warning_cmd); + + install_element(VIEW_NODE, &show_thread_timers_cmd); } /* CLI end ------------------------------------------------------------------ */ @@ -768,7 +810,7 @@ char *thread_timer_to_hhmmss(char *buf, int buf_size, /* Get new thread. */ static struct thread *thread_get(struct thread_master *m, uint8_t type, - int (*func)(struct thread *), void *arg, + void (*func)(struct thread *), void *arg, const struct xref_threadsched *xref) { struct thread *thread = thread_list_pop(&m->unuse); @@ -925,7 +967,7 @@ done: /* Add new read thread. */ void _thread_add_read_write(const struct xref_threadsched *xref, struct thread_master *m, - int (*func)(struct thread *), void *arg, int fd, + void (*func)(struct thread *), void *arg, int fd, struct thread **t_ptr) { int dir = xref->thread_type; @@ -1005,7 +1047,7 @@ void _thread_add_read_write(const struct xref_threadsched *xref, static void _thread_add_timer_timeval(const struct xref_threadsched *xref, struct thread_master *m, - int (*func)(struct thread *), void *arg, + void (*func)(struct thread *), void *arg, struct timeval *time_relative, struct thread **t_ptr) { @@ -1047,12 +1089,18 @@ static void _thread_add_timer_timeval(const struct xref_threadsched *xref, if (thread_timer_list_first(&m->timer) == thread) AWAKEN(m); } +#define ONEYEAR2SEC (60 * 60 * 24 * 365) + if (time_relative->tv_sec > ONEYEAR2SEC) + flog_err( + EC_LIB_TIMER_TOO_LONG, + "Timer: %pTHD is created with an expiration that is greater than 1 year", + thread); } /* Add timer event thread. */ void _thread_add_timer(const struct xref_threadsched *xref, - struct thread_master *m, int (*func)(struct thread *), + struct thread_master *m, void (*func)(struct thread *), void *arg, long timer, struct thread **t_ptr) { struct timeval trel; @@ -1068,8 +1116,8 @@ void _thread_add_timer(const struct xref_threadsched *xref, /* Add timer event thread with "millisecond" resolution */ void _thread_add_timer_msec(const struct xref_threadsched *xref, struct thread_master *m, - int (*func)(struct thread *), void *arg, long timer, - struct thread **t_ptr) + void (*func)(struct thread *), void *arg, + long timer, struct thread **t_ptr) { struct timeval trel; @@ -1083,15 +1131,16 @@ void _thread_add_timer_msec(const struct xref_threadsched *xref, /* Add timer event thread with "timeval" resolution */ void _thread_add_timer_tv(const struct xref_threadsched *xref, - struct thread_master *m, int (*func)(struct thread *), - void *arg, struct timeval *tv, struct thread **t_ptr) + struct thread_master *m, + void (*func)(struct thread *), void *arg, + struct timeval *tv, struct thread **t_ptr) { _thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr); } /* Add simple event thread. */ void _thread_add_event(const struct xref_threadsched *xref, - struct thread_master *m, int (*func)(struct thread *), + struct thread_master *m, void (*func)(struct thread *), void *arg, int val, struct thread **t_ptr) { struct thread *thread = NULL; @@ -1668,13 +1717,17 @@ static unsigned int thread_process_timers(struct thread_master *m, * really getting behind on handling of events. * Let's log it and do the right thing with it. */ - if (!displayed && !thread->ignore_timer_late && - timercmp(timenow, &prev, >)) { - flog_warn( - EC_LIB_STARVE_THREAD, - "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago", - thread); - displayed = true; + if (timercmp(timenow, &prev, >)) { + atomic_fetch_add_explicit( + &thread->hist->total_starv_warn, 1, + memory_order_seq_cst); + if (!displayed && !thread->ignore_timer_late) { + flog_warn( + EC_LIB_STARVE_THREAD, + "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago", + thread); + displayed = true; + } } thread_timer_list_pop(&m->timer); @@ -1831,6 +1884,27 @@ unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime) { #ifdef HAVE_CLOCK_THREAD_CPUTIME_ID + +#ifdef __FreeBSD__ + /* + * FreeBSD appears to have an issue when calling clock_gettime + * with CLOCK_THREAD_CPUTIME_ID really close to each other + * occassionally the now time will be before the start time. + * This is not good and FRR is ending up with CPU HOG's + * when the subtraction wraps to very large numbers + * + * What we are going to do here is cheat a little bit + * and notice that this is a problem and just correct + * it so that it is impossible to happen + */ + if (start->cpu.tv_sec == now->cpu.tv_sec && + start->cpu.tv_nsec > now->cpu.tv_nsec) + now->cpu.tv_nsec = start->cpu.tv_nsec + 1; + else if (start->cpu.tv_sec > now->cpu.tv_sec) { + now->cpu.tv_sec = start->cpu.tv_sec; + now->cpu.tv_nsec = start->cpu.tv_nsec + 1; + } +#endif *cputime = (now->cpu.tv_sec - start->cpu.tv_sec) * TIMER_SECOND_MICRO + (now->cpu.tv_nsec - start->cpu.tv_nsec) / 1000; #else @@ -1999,7 +2073,7 @@ void thread_call(struct thread *thread) /* Execute thread */ void _thread_execute(const struct xref_threadsched *xref, - struct thread_master *m, int (*func)(struct thread *), + struct thread_master *m, void (*func)(struct thread *), void *arg, int val) { struct thread *thread; diff --git a/lib/thread.h b/lib/thread.h index 660f8bd28..a2049ae52 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -114,7 +114,7 @@ struct thread { struct thread_timer_list_item timeritem; struct thread **ref; /* external reference (if given) */ struct thread_master *master; /* pointer to the struct thread_master */ - int (*func)(struct thread *); /* event function */ + void (*func)(struct thread *); /* event function */ void *arg; /* event argument */ union { int val; /* second argument of the event. */ @@ -134,9 +134,10 @@ struct thread { #endif struct cpu_thread_history { - int (*func)(struct thread *); + void (*func)(struct thread *); atomic_size_t total_cpu_warn; atomic_size_t total_wall_warn; + atomic_size_t total_starv_warn; atomic_size_t total_calls; atomic_size_t total_active; struct time_stats { @@ -226,32 +227,32 @@ extern void thread_master_free_unused(struct thread_master *); extern void _thread_add_read_write(const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, + void (*fn)(struct thread *), void *arg, int fd, struct thread **tref); extern void _thread_add_timer(const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, long t, + void (*fn)(struct thread *), void *arg, long t, struct thread **tref); extern void _thread_add_timer_msec(const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, + void (*fn)(struct thread *), void *arg, long t, struct thread **tref); extern void _thread_add_timer_tv(const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, + void (*fn)(struct thread *), void *arg, struct timeval *tv, struct thread **tref); extern void _thread_add_event(const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, int val, + void (*fn)(struct thread *), void *arg, int val, struct thread **tref); extern void _thread_execute(const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, int val); + void (*fn)(struct thread *), void *arg, int val); extern void thread_cancel(struct thread **event); extern void thread_cancel_async(struct thread_master *, struct thread **, diff --git a/lib/typerb.c b/lib/typerb.c index e1346df19..fe142ff35 100644 --- a/lib/typerb.c +++ b/lib/typerb.c @@ -468,6 +468,28 @@ struct rb_entry *typed_rb_next(const struct rb_entry *rbe_const) return rbe; } +struct rb_entry *typed_rb_prev(const struct rb_entry *rbe_const) +{ + struct rb_entry *rbe = (struct rb_entry *)rbe_const; + + if (RBE_LEFT(rbe)) { + rbe = RBE_LEFT(rbe); + while (RBE_RIGHT(rbe)) + rbe = RBE_RIGHT(rbe); + } else { + if (RBE_PARENT(rbe) && (rbe == RBE_RIGHT(RBE_PARENT(rbe)))) + rbe = RBE_PARENT(rbe); + else { + while (RBE_PARENT(rbe) + && (rbe == RBE_LEFT(RBE_PARENT(rbe)))) + rbe = RBE_PARENT(rbe); + rbe = RBE_PARENT(rbe); + } + } + + return rbe; +} + struct rb_entry *typed_rb_min(const struct rbt_tree *rbt) { struct rb_entry *rbe = RBH_ROOT(rbt); @@ -481,6 +503,19 @@ struct rb_entry *typed_rb_min(const struct rbt_tree *rbt) return parent; } +struct rb_entry *typed_rb_max(const struct rbt_tree *rbt) +{ + struct rb_entry *rbe = RBH_ROOT(rbt); + struct rb_entry *parent = NULL; + + while (rbe != NULL) { + parent = rbe; + rbe = RBE_RIGHT(rbe); + } + + return parent; +} + bool typed_rb_member(const struct typed_rb_root *rbt, const struct typed_rb_entry *rbe) { diff --git a/lib/typerb.h b/lib/typerb.h index 75a1de77b..8ac182174 100644 --- a/lib/typerb.h +++ b/lib/typerb.h @@ -62,6 +62,8 @@ const struct typed_rb_entry *typed_rb_find_lt(const struct typed_rb_root *rbt, const struct typed_rb_entry *a, const struct typed_rb_entry *b)); struct typed_rb_entry *typed_rb_min(const struct typed_rb_root *rbt); +struct typed_rb_entry *typed_rb_max(const struct typed_rb_root *rbt); +struct typed_rb_entry *typed_rb_prev(const struct typed_rb_entry *rbe); struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe); bool typed_rb_member(const struct typed_rb_root *rbt, const struct typed_rb_entry *rbe); @@ -135,12 +137,32 @@ macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \ return container_of_null(re, type, field.re); \ } \ TYPESAFE_FIRST_NEXT(prefix, type) \ +macro_pure const type *prefix ## _const_last(const struct prefix##_head *h) \ +{ \ + const struct typed_rb_entry *re; \ + re = typed_rb_max(&h->rr); \ + return container_of_null(re, type, field.re); \ +} \ +macro_pure const type *prefix ## _const_prev(const struct prefix##_head *h, \ + const type *item) \ +{ \ + const struct typed_rb_entry *re; \ + re = typed_rb_prev(&item->field.re); \ + return container_of_null(re, type, field.re); \ +} \ +TYPESAFE_LAST_PREV(prefix, type) \ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ { \ struct typed_rb_entry *re; \ re = item ? typed_rb_next(&item->field.re) : NULL; \ return container_of_null(re, type, field.re); \ } \ +macro_pure type *prefix ## _prev_safe(struct prefix##_head *h, type *item) \ +{ \ + struct typed_rb_entry *re; \ + re = item ? typed_rb_prev(&item->field.re) : NULL; \ + return container_of_null(re, type, field.re); \ +} \ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->rr.count; \ diff --git a/lib/typesafe.h b/lib/typesafe.h index b284397d9..06fdc52e7 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -43,6 +43,22 @@ extern "C" { item; \ item = from, from = prefix##_next_safe(head, from)) +/* reverse direction, only supported by a few containers */ + +#define frr_rev_each(prefix, head, item) \ + for (item = prefix##_last(head); item; \ + item = prefix##_prev(head, item)) +#define frr_rev_each_safe(prefix, head, item) \ + for (typeof(prefix##_prev_safe(head, NULL)) prefix##_safe = \ + prefix##_prev_safe(head, \ + (item = prefix##_last(head))); \ + item; \ + item = prefix##_safe, \ + prefix##_safe = prefix##_prev_safe(head, prefix##_safe)) +#define frr_rev_each_from(prefix, head, item, from) \ + for (item = from, from = prefix##_prev_safe(head, item); \ + item; \ + item = from, from = prefix##_prev_safe(head, from)) /* non-const variants. these wrappers are the same for all the types, so * bundle them together here. @@ -57,6 +73,16 @@ macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \ return (type *)prefix ## _const_next(h, item); \ } \ /* ... */ +#define TYPESAFE_LAST_PREV(prefix, type) \ +macro_pure type *prefix ## _last(struct prefix##_head *h) \ +{ \ + return (type *)prefix ## _const_last(h); \ +} \ +macro_pure type *prefix ## _prev(struct prefix##_head *h, type *item) \ +{ \ + return (type *)prefix ## _const_prev(h, item); \ +} \ +/* ... */ #define TYPESAFE_FIND(prefix, type) \ macro_inline type *prefix ## _find(struct prefix##_head *h, \ const type *item) \ @@ -398,12 +424,34 @@ macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \ return container_of(ditem->next, type, field.di); \ } \ TYPESAFE_FIRST_NEXT(prefix, type) \ +macro_pure const type *prefix ## _const_last(const struct prefix##_head *h) \ +{ \ + const struct dlist_item *ditem = h->dh.hitem.prev; \ + if (ditem == &h->dh.hitem) \ + return NULL; \ + return container_of(ditem, type, field.di); \ +} \ +macro_pure const type *prefix ## _const_prev(const struct prefix##_head *h, \ + const type *item) \ +{ \ + const struct dlist_item *ditem = &item->field.di; \ + if (ditem->prev == &h->dh.hitem) \ + return NULL; \ + return container_of(ditem->prev, type, field.di); \ +} \ +TYPESAFE_LAST_PREV(prefix, type) \ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ { \ if (!item) \ return NULL; \ return prefix ## _next(h, item); \ } \ +macro_pure type *prefix ## _prev_safe(struct prefix##_head *h, type *item) \ +{ \ + if (!item) \ + return NULL; \ + return prefix ## _prev(h, item); \ +} \ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->dh.count; \ diff --git a/lib/vty.c b/lib/vty.c index 8eaf13619..78ef9894d 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -65,7 +65,7 @@ DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history"); DECLARE_DLIST(vtys, struct vty, itm); /* Vty events */ -enum event { +enum vty_event { VTY_SERV, VTY_READ, VTY_WRITE, @@ -90,8 +90,8 @@ struct vty_serv { DECLARE_DLIST(vtyservs, struct vty_serv, itm); -static void vty_event_serv(enum event event, struct vty_serv *); -static void vty_event(enum event, struct vty *); +static void vty_event_serv(enum vty_event event, struct vty_serv *); +static void vty_event(enum vty_event, struct vty *); /* Extern host structure from command.c */ extern struct host host; @@ -1299,7 +1299,7 @@ static void vty_buffer_reset(struct vty *vty) } /* Read data via vty socket. */ -static int vty_read(struct thread *thread) +static void vty_read(struct thread *thread) { int i; int nbytes; @@ -1312,10 +1312,8 @@ static int vty_read(struct thread *thread) if (nbytes < 0) { if (ERRNO_IO_RETRY(errno)) { vty_event(VTY_READ, vty); - return 0; + return; } - vty->monitor = 0; /* disable monitoring to avoid - infinite recursion */ flog_err( EC_LIB_SOCKET, "%s: read error on vty client fd %d, closing: %s", @@ -1464,6 +1462,11 @@ static int vty_read(struct thread *thread) vty_out(vty, "\n"); buffer_flush_available(vty->obuf, vty->wfd); vty_execute(vty); + + if (vty->pass_fd != -1) { + close(vty->pass_fd); + vty->pass_fd = -1; + } break; case '\t': vty_complete_command(vty); @@ -1496,11 +1499,10 @@ static int vty_read(struct thread *thread) vty_event(VTY_WRITE, vty); vty_event(VTY_READ, vty); } - return 0; } /* Flush buffer to the vty. */ -static int vty_flush(struct thread *thread) +static void vty_flush(struct thread *thread) { int erase; buffer_status_t flushrc; @@ -1525,14 +1527,12 @@ static int vty_flush(struct thread *thread) vty->lines >= 0 ? vty->lines : vty->height, erase, 0); switch (flushrc) { case BUFFER_ERROR: - vty->monitor = - 0; /* disable monitoring to avoid infinite recursion */ zlog_info("buffer_flush failed on vty client fd %d/%d, closing", vty->fd, vty->wfd); buffer_reset(vty->lbuf); buffer_reset(vty->obuf); vty_close(vty); - return 0; + return; case BUFFER_EMPTY: if (vty->status == VTY_CLOSE) vty_close(vty); @@ -1549,8 +1549,6 @@ static int vty_flush(struct thread *thread) vty_event(VTY_WRITE, vty); break; } - - return 0; } /* Allocate new vty struct. */ @@ -1564,6 +1562,7 @@ struct vty *vty_new(void) new->obuf = buffer_new(0); /* Use default buffer size. */ new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ); new->max = VTY_BUFSIZ; + new->pass_fd = -1; return new; } @@ -1753,7 +1752,7 @@ struct vty *vty_stdio(void (*atclose)(int isexit)) } /* Accept connection from the network. */ -static int vty_accept(struct thread *thread) +static void vty_accept(struct thread *thread) { struct vty_serv *vtyserv = THREAD_ARG(thread); int vty_sock; @@ -1774,7 +1773,7 @@ static int vty_accept(struct thread *thread) if (vty_sock < 0) { flog_err(EC_LIB_SOCKET, "can't accept vty socket : %s", safe_strerror(errno)); - return -1; + return; } set_nonblocking(vty_sock); set_cloexec(vty_sock); @@ -1783,7 +1782,7 @@ static int vty_accept(struct thread *thread) close(vty_sock); zlog_info("Vty unable to convert prefix from sockunion %pSU", &su); - return -1; + return; } /* VTY's accesslist apply. */ @@ -1792,7 +1791,7 @@ static int vty_accept(struct thread *thread) && (access_list_apply(acl, &p) == FILTER_DENY)) { zlog_info("Vty connection refused from %pSU", &su); close(vty_sock); - return 0; + return; } } @@ -1803,7 +1802,7 @@ static int vty_accept(struct thread *thread) && (access_list_apply(acl, &p) == FILTER_DENY)) { zlog_info("Vty connection refused from %pSU", &su); close(vty_sock); - return 0; + return; } } @@ -1817,8 +1816,6 @@ static int vty_accept(struct thread *thread) zlog_info("Vty connection from %pSU", &su); vty_create(vty_sock, &su); - - return 0; } static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port) @@ -1968,7 +1965,7 @@ static void vty_serv_un(const char *path) /* #define VTYSH_DEBUG 1 */ -static int vtysh_accept(struct thread *thread) +static void vtysh_accept(struct thread *thread) { struct vty_serv *vtyserv = THREAD_ARG(thread); int accept_sock = vtyserv->sock; @@ -1988,7 +1985,7 @@ static int vtysh_accept(struct thread *thread) if (sock < 0) { flog_err(EC_LIB_SOCKET, "can't accept vty socket : %s", safe_strerror(errno)); - return -1; + return; } if (set_nonblocking(sock) < 0) { @@ -1997,7 +1994,7 @@ static int vtysh_accept(struct thread *thread) "vtysh_accept: could not set vty socket %d to non-blocking, %s, closing", sock, safe_strerror(errno)); close(sock); - return -1; + return; } set_cloexec(sock); @@ -2013,19 +2010,70 @@ static int vtysh_accept(struct thread *thread) vtys_add_tail(vtysh_sessions, vty); vty_event(VTYSH_READ, vty); +} - return 0; +static int vtysh_do_pass_fd(struct vty *vty) +{ + struct iovec iov[1] = { + { + .iov_base = vty->pass_fd_status, + .iov_len = sizeof(vty->pass_fd_status), + }, + }; + union { + uint8_t buf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr align; + } u; + struct msghdr mh = { + .msg_iov = iov, + .msg_iovlen = array_size(iov), + .msg_control = u.buf, + .msg_controllen = sizeof(u.buf), + }; + struct cmsghdr *cmh = CMSG_FIRSTHDR(&mh); + ssize_t ret; + + cmh->cmsg_level = SOL_SOCKET; + cmh->cmsg_type = SCM_RIGHTS; + cmh->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmh), &vty->pass_fd, sizeof(int)); + + ret = sendmsg(vty->wfd, &mh, 0); + if (ret < 0 && ERRNO_IO_RETRY(errno)) + return BUFFER_PENDING; + + close(vty->pass_fd); + vty->pass_fd = -1; + vty->status = VTY_NORMAL; + + if (ret <= 0) + return BUFFER_ERROR; + + /* resume accepting commands (suspended in vtysh_read) */ + vty_event(VTYSH_READ, vty); + + if ((size_t)ret < sizeof(vty->pass_fd_status)) { + size_t remains = sizeof(vty->pass_fd_status) - ret; + + buffer_put(vty->obuf, vty->pass_fd_status + ret, remains); + return BUFFER_PENDING; + } + return BUFFER_EMPTY; } static int vtysh_flush(struct vty *vty) { - switch (buffer_flush_available(vty->obuf, vty->wfd)) { + int ret; + + ret = buffer_flush_available(vty->obuf, vty->wfd); + if (ret == BUFFER_EMPTY && vty->status == VTY_PASSFD) + ret = vtysh_do_pass_fd(vty); + + switch (ret) { case BUFFER_PENDING: vty_event(VTYSH_WRITE, vty); break; case BUFFER_ERROR: - vty->monitor = - 0; /* disable monitoring to avoid infinite recursion */ flog_err(EC_LIB_SOCKET, "%s: write error to fd %d, closing", __func__, vty->fd); buffer_reset(vty->lbuf); @@ -2038,7 +2086,15 @@ static int vtysh_flush(struct vty *vty) return 0; } -static int vtysh_read(struct thread *thread) +void vty_pass_fd(struct vty *vty, int fd) +{ + if (vty->pass_fd != -1) + close(vty->pass_fd); + + vty->pass_fd = fd; +} + +static void vtysh_read(struct thread *thread) { int ret; int sock; @@ -2055,10 +2111,8 @@ static int vtysh_read(struct thread *thread) if (nbytes < 0) { if (ERRNO_IO_RETRY(errno)) { vty_event(VTYSH_READ, vty); - return 0; + return; } - vty->monitor = 0; /* disable monitoring to avoid - infinite recursion */ flog_err( EC_LIB_SOCKET, "%s: read failed on vtysh client fd %d, closing: %s", @@ -2070,7 +2124,7 @@ static int vtysh_read(struct thread *thread) #ifdef VTYSH_DEBUG printf("close vtysh\n"); #endif /* VTYSH_DEBUG */ - return 0; + return; } #ifdef VTYSH_DEBUG @@ -2097,6 +2151,26 @@ static int vtysh_read(struct thread *thread) printf("vtysh node: %d\n", vty->node); #endif /* VTYSH_DEBUG */ + if (vty->pass_fd != -1) { + memset(vty->pass_fd_status, 0, 4); + vty->pass_fd_status[3] = ret; + vty->status = VTY_PASSFD; + + if (!vty->t_write) + vty_event(VTYSH_WRITE, vty); + + /* this introduces a "sequence point" + * command output is written normally, + * read processing is suspended until + * buffer is empty + * then retcode + FD is written + * then normal processing resumes + * + * => skip vty_event(VTYSH_READ, vty)! + */ + return; + } + /* hack for asynchronous "write integrated" * - other commands in "buf" will be ditched * - input during pending config-write is @@ -2112,7 +2186,7 @@ static int vtysh_read(struct thread *thread) if (!vty->t_write && (vtysh_flush(vty) < 0)) /* Try to flush results; exit if a write * error occurs. */ - return 0; + return; } } } @@ -2121,16 +2195,13 @@ static int vtysh_read(struct thread *thread) vty_close(vty); else vty_event(VTYSH_READ, vty); - - return 0; } -static int vtysh_write(struct thread *thread) +static void vtysh_write(struct thread *thread) { struct vty *vty = THREAD_ARG(thread); vtysh_flush(vty); - return 0; } #endif /* VTYSH */ @@ -2171,6 +2242,12 @@ void vty_close(struct vty *vty) THREAD_OFF(vty->t_write); THREAD_OFF(vty->t_timeout); + if (vty->pass_fd != -1) { + close(vty->pass_fd); + vty->pass_fd = -1; + } + zlog_live_close(&vty->live_log); + /* Flush buffer. */ buffer_flush_all(vty->obuf, vty->wfd); @@ -2221,7 +2298,7 @@ void vty_close(struct vty *vty) } /* When time out occur output message then close connection. */ -static int vty_timeout(struct thread *thread) +static void vty_timeout(struct thread *thread) { struct vty *vty; @@ -2236,8 +2313,6 @@ static int vty_timeout(struct thread *thread) /* Close connection. */ vty->status = VTY_CLOSE; vty_close(vty); - - return 0; } /* Read up configuration file from file_name. */ @@ -2608,7 +2683,7 @@ int vty_config_node_exit(struct vty *vty) /* Master of the threads. */ static struct thread_master *vty_master; -static void vty_event_serv(enum event event, struct vty_serv *vty_serv) +static void vty_event_serv(enum vty_event event, struct vty_serv *vty_serv) { switch (event) { case VTY_SERV: @@ -2626,7 +2701,7 @@ static void vty_event_serv(enum event event, struct vty_serv *vty_serv) } } -static void vty_event(enum event event, struct vty *vty) +static void vty_event(enum vty_event event, struct vty *vty) { switch (event) { #ifdef VTYSH @@ -2673,8 +2748,9 @@ DEFUN_NOSH (config_who, struct vty *v; frr_each (vtys, vty_sessions, v) - vty_out(vty, "%svty[%d] connected from %s.\n", - v->config ? "*" : " ", v->fd, v->address); + vty_out(vty, "%svty[%d] connected from %s%s.\n", + v->config ? "*" : " ", v->fd, v->address, + zlog_live_is_null(&v->live_log) ? "" : ", live log"); return CMD_SUCCESS; } @@ -2867,35 +2943,56 @@ DEFUN (no_service_advanced_vty, return CMD_SUCCESS; } -DEFUN_NOSH (terminal_monitor, - terminal_monitor_cmd, - "terminal monitor", - "Set terminal line parameters\n" - "Copy debug output to the current terminal line\n") +DEFUN_NOSH(terminal_monitor, + terminal_monitor_cmd, + "terminal monitor [detach]", + "Set terminal line parameters\n" + "Copy debug output to the current terminal line\n" + "Keep logging feed open independent of VTY session\n") { - vty->monitor = 1; + int fd_ret = -1; + + if (vty->type != VTY_SHELL_SERV) { + vty_out(vty, "%% not supported\n"); + return CMD_WARNING; + } + + if (argc == 3) { + struct zlog_live_cfg detach_log = {}; + + zlog_live_open(&detach_log, LOG_DEBUG, &fd_ret); + zlog_live_disown(&detach_log); + } else + zlog_live_open(&vty->live_log, LOG_DEBUG, &fd_ret); + + if (fd_ret == -1) { + vty_out(vty, "%% error opening live log: %m\n"); + return CMD_WARNING; + } + + vty_pass_fd(vty, fd_ret); return CMD_SUCCESS; } -DEFUN_NOSH (terminal_no_monitor, - terminal_no_monitor_cmd, - "terminal no monitor", - "Set terminal line parameters\n" - NO_STR - "Copy debug output to the current terminal line\n") +DEFUN_NOSH(no_terminal_monitor, + no_terminal_monitor_cmd, + "no terminal monitor", + NO_STR + "Set terminal line parameters\n" + "Copy debug output to the current terminal line\n") { - vty->monitor = 0; + zlog_live_close(&vty->live_log); return CMD_SUCCESS; } -DEFUN_NOSH (no_terminal_monitor, - no_terminal_monitor_cmd, - "no terminal monitor", - NO_STR - "Set terminal line parameters\n" - "Copy debug output to the current terminal line\n") +DEFUN_NOSH(terminal_no_monitor, + terminal_no_monitor_cmd, + "terminal no monitor", + "Set terminal line parameters\n" + NO_STR + "Copy debug output to the current terminal line\n") { - return terminal_no_monitor(self, vty, argc, argv); + return no_terminal_monitor(self, vty, argc, argv); } diff --git a/lib/vty.h b/lib/vty.h index 9ffbce326..e42a3b210 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -34,6 +34,7 @@ #include "qobj.h" #include "compiler.h" #include "northbound.h" +#include "zlog_live.h" #ifdef __cplusplus extern "C" { @@ -161,7 +162,22 @@ struct vty { unsigned char escape; /* Current vty status. */ - enum { VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE } status; + enum { + VTY_NORMAL, + VTY_CLOSE, + VTY_MORE, + VTY_MORELINE, + VTY_PASSFD, + } status; + + /* vtysh socket/fd passing (for terminal monitor) */ + int pass_fd; + + /* CLI command return value (likely CMD_SUCCESS) when pass_fd != -1 */ + uint8_t pass_fd_status[4]; + + /* live logging target / terminal monitor */ + struct zlog_live_cfg live_log; /* IAC handling: was the last character received the IAC (interpret-as-command) escape character (and therefore the next @@ -186,9 +202,6 @@ struct vty { /* Configure lines. */ int lines; - /* Terminal monitor. */ - int monitor; - /* Read and write thread. */ struct thread *t_read; struct thread *t_write; @@ -329,6 +342,11 @@ extern bool vty_set_include(struct vty *vty, const char *regexp); */ extern int vty_json(struct vty *vty, struct json_object *json); +/* post fd to be passed to the vtysh client + * fd is owned by the VTY code after this and will be closed when done + */ +extern void vty_pass_fd(struct vty *vty, int fd); + extern bool vty_read_config(struct nb_config *config, const char *config_file, char *config_default_dir); extern void vty_time_print(struct vty *, int); diff --git a/lib/wheel.c b/lib/wheel.c index 1a0469b25..463410bea 100644 --- a/lib/wheel.c +++ b/lib/wheel.c @@ -29,9 +29,9 @@ DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List"); static int debug_timer_wheel = 0; -static int wheel_timer_thread(struct thread *t); +static void wheel_timer_thread(struct thread *t); -static int wheel_timer_thread_helper(struct thread *t) +static void wheel_timer_thread_helper(struct thread *t) { struct listnode *node, *nextnode; unsigned long long curr_slot; @@ -63,19 +63,15 @@ static int wheel_timer_thread_helper(struct thread *t) wheel->slots_to_skip = slots_to_skip; thread_add_timer_msec(wheel->master, wheel_timer_thread, wheel, wheel->nexttime * slots_to_skip, &wheel->timer); - - return 0; } -static int wheel_timer_thread(struct thread *t) +static void wheel_timer_thread(struct thread *t) { struct timer_wheel *wheel; wheel = THREAD_ARG(t); thread_execute(wheel->master, wheel_timer_thread_helper, wheel, 0); - - return 0; } struct timer_wheel *wheel_init(struct thread_master *master, int period, diff --git a/lib/workqueue.c b/lib/workqueue.c index 86afe4082..92869594d 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -238,7 +238,7 @@ void work_queue_unplug(struct work_queue *wq) * will reschedule itself if required, * otherwise work_queue_item_add */ -int work_queue_run(struct thread *thread) +void work_queue_run(struct thread *thread) { struct work_queue *wq; struct work_queue_item *item, *titem; @@ -388,6 +388,4 @@ stats: } else if (wq->spec.completion_func) wq->spec.completion_func(wq); - - return 0; } diff --git a/lib/workqueue.h b/lib/workqueue.h index b076ed0d2..39202dcda 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -177,7 +177,7 @@ extern void work_queue_unplug(struct work_queue *wq); bool work_queue_is_scheduled(struct work_queue *); /* Helpers, exported for thread.c and command.c */ -extern int work_queue_run(struct thread *); +extern void work_queue_run(struct thread *); extern void workqueue_cmd_init(void); diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c index 85aa003db..bee76c6e0 100644 --- a/lib/yang_wrappers.c +++ b/lib/yang_wrappers.c @@ -19,6 +19,7 @@ #include +#include "base64.h" #include "log.h" #include "lib_errors.h" #include "northbound.h" @@ -676,6 +677,64 @@ void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt, xpath); } +/* + * Primitive type: binary. + */ +struct yang_data *yang_data_new_binary(const char *xpath, const char *value, + size_t len) +{ + char *value_str; + struct base64_encodestate s; + int cnt; + char *c; + struct yang_data *data; + + value_str = (char *)malloc(len * 2); + base64_init_encodestate(&s); + cnt = base64_encode_block(value, len, value_str, &s); + c = value_str + cnt; + cnt = base64_encode_blockend(c, &s); + c += cnt; + *c = 0; + data = yang_data_new(xpath, value_str); + free(value_str); + return data; +} + +size_t yang_dnode_get_binary_buf(char *buf, size_t size, + const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const char *canon; + size_t cannon_len; + size_t decode_len; + size_t ret_len; + size_t cnt; + char *value_str; + struct base64_decodestate s; + + canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + cannon_len = strlen(canon); + decode_len = cannon_len; + value_str = (char *)malloc(decode_len); + base64_init_decodestate(&s); + cnt = base64_decode_block(canon, cannon_len, value_str, &s); + + ret_len = size > cnt ? cnt : size; + memcpy(buf, value_str, ret_len); + if (size < cnt) { + char xpath[XPATH_MAXLEN]; + + yang_dnode_get_path(dnode, xpath, sizeof(xpath)); + flog_warn(EC_LIB_YANG_DATA_TRUNCATED, + "%s: value was truncated [xpath %s]", __func__, + xpath); + } + free(value_str); + return ret_len; +} + + /* * Primitive type: empty. */ diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h index d781dfb1e..56b314876 100644 --- a/lib/yang_wrappers.h +++ b/lib/yang_wrappers.h @@ -118,6 +118,13 @@ extern const char *yang_get_default_string(const char *xpath_fmt, ...); extern void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt, ...); +/* binary */ +extern struct yang_data *yang_data_new_binary(const char *xpath, + const char *value, size_t len); +extern size_t yang_dnode_get_binary_buf(char *buf, size_t size, + const struct lyd_node *dnode, + const char *xpath_fmt, ...); + /* empty */ extern struct yang_data *yang_data_new_empty(const char *xpath); extern bool yang_dnode_get_empty(const struct lyd_node *dnode, diff --git a/lib/zclient.c b/lib/zclient.c index ab2dd0989..f6c5a8af0 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -47,10 +47,10 @@ DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient"); DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs"); /* Zebra client events. */ -enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT }; +enum zclient_event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT }; /* Prototype for event manager. */ -static void zclient_event(enum event, struct zclient *); +static void zclient_event(enum zclient_event, struct zclient *); static void zebra_interface_if_set_value(struct stream *s, struct interface *ifp); @@ -263,20 +263,21 @@ static enum zclient_send_status zclient_failed(struct zclient *zclient) return ZCLIENT_SEND_FAILURE; } -static int zclient_flush_data(struct thread *thread) +static void zclient_flush_data(struct thread *thread) { struct zclient *zclient = THREAD_ARG(thread); zclient->t_write = NULL; if (zclient->sock < 0) - return -1; + return; switch (buffer_flush_available(zclient->wb, zclient->sock)) { case BUFFER_ERROR: flog_err( EC_LIB_ZAPI_SOCKET, "%s: buffer_flush_available failed on zclient fd %d, closing", __func__, zclient->sock); - return zclient_failed(zclient); + zclient_failed(zclient); + return; case BUFFER_PENDING: zclient->t_write = NULL; thread_add_write(zclient->master, zclient_flush_data, zclient, @@ -287,7 +288,6 @@ static int zclient_flush_data(struct thread *thread) (*zclient->zebra_buffer_write_ready)(); break; } - return 0; } /* @@ -754,7 +754,7 @@ void zclient_init(struct zclient *zclient, int redist_default, /* This function is a wrapper function for calling zclient_start from timer or event thread. */ -static int zclient_connect(struct thread *t) +static void zclient_connect(struct thread *t) { struct zclient *zclient; @@ -764,7 +764,7 @@ static int zclient_connect(struct thread *t) if (zclient_debug) zlog_debug("zclient_connect is called"); - return zclient_start(zclient); + zclient_start(zclient); } enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command, @@ -1924,7 +1924,8 @@ const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf, /* * Decode the nexthop-tracking update message */ -bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) +bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, + struct zapi_route *nhr) { uint32_t i; @@ -1932,6 +1933,22 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) STREAM_GETL(s, nhr->message); STREAM_GETW(s, nhr->safi); + STREAM_GETW(s, match->family); + STREAM_GETC(s, match->prefixlen); + /* + * What we got told to match against + */ + switch (match->family) { + case AF_INET: + STREAM_GET(&match->u.prefix4.s_addr, s, IPV4_MAX_BYTELEN); + break; + case AF_INET6: + STREAM_GET(&match->u.prefix6, s, IPV6_MAX_BYTELEN); + break; + } + /* + * What we matched against + */ STREAM_GETW(s, nhr->prefix.family); STREAM_GETC(s, nhr->prefix.prefixlen); switch (nhr->prefix.family) { @@ -3864,7 +3881,7 @@ static zclient_handler *const lib_handlers[] = { }; /* Zebra client message read function. */ -static int zclient_read(struct thread *thread) +static void zclient_read(struct thread *thread) { size_t already; uint16_t length, command; @@ -3888,11 +3905,12 @@ static int zclient_read(struct thread *thread) zlog_debug( "zclient connection closed socket [%d].", zclient->sock); - return zclient_failed(zclient); + zclient_failed(zclient); + return; } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE - already)) { zclient_event(ZCLIENT_READ, zclient); - return 0; + return; } already = ZEBRA_HEADER_SIZE; } @@ -3912,14 +3930,16 @@ static int zclient_read(struct thread *thread) EC_LIB_ZAPI_MISSMATCH, "%s: socket %d version mismatch, marker %d, version %d", __func__, zclient->sock, marker, version); - return zclient_failed(zclient); + zclient_failed(zclient); + return; } if (length < ZEBRA_HEADER_SIZE) { flog_err(EC_LIB_ZAPI_MISSMATCH, "%s: socket %d message length %u is less than %d ", __func__, zclient->sock, length, ZEBRA_HEADER_SIZE); - return zclient_failed(zclient); + zclient_failed(zclient); + return; } /* Length check. */ @@ -3947,12 +3967,13 @@ static int zclient_read(struct thread *thread) zlog_debug( "zclient connection closed socket [%d].", zclient->sock); - return zclient_failed(zclient); + zclient_failed(zclient); + return; } if (nbyte != (ssize_t)(length - already)) { /* Try again later. */ zclient_event(ZCLIENT_READ, zclient); - return 0; + return; } } @@ -3969,13 +3990,11 @@ static int zclient_read(struct thread *thread) if (zclient->sock < 0) /* Connection was closed during packet processing. */ - return -1; + return; /* Register read thread. */ stream_reset(zclient->ibuf); zclient_event(ZCLIENT_READ, zclient); - - return 0; } void zclient_redistribute(int command, struct zclient *zclient, afi_t afi, @@ -4036,7 +4055,7 @@ void zclient_redistribute_default(int command, struct zclient *zclient, zebra_redistribute_default_send(command, zclient, afi, vrf_id); } -static void zclient_event(enum event event, struct zclient *zclient) +static void zclient_event(enum zclient_event event, struct zclient *zclient) { switch (event) { case ZCLIENT_SCHEDULE: diff --git a/lib/zclient.h b/lib/zclient.h index ca62b1afe..092754f60 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -1111,7 +1111,17 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, const struct nexthop *nh); int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh, const struct nexthop *nh); -extern bool zapi_nexthop_update_decode(struct stream *s, +/* + * match -> is the prefix that the calling daemon asked to be matched + * against. + * nhr->prefix -> is the actual prefix that was matched against in the + * rib itself. + * + * This distinction is made because a LPM can be made if there is a + * covering route. This way the upper level protocol can make a decision + * point about whether or not it wants to use the match or not. + */ +extern bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, struct zapi_route *nhr); const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf, int bufsize); diff --git a/lib/zebra.h b/lib/zebra.h index 139e47e8d..e8ddd869b 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -230,6 +230,26 @@ size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t destsize); #endif +#if !defined(HAVE_STRUCT_MMSGHDR_MSG_HDR) || !defined(HAVE_SENDMMSG) +/* avoid conflicts in case we have partial support */ +#define mmsghdr frr_mmsghdr +#define sendmmsg frr_sendmmsg + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +/* just go 1 at a time here, the loop this is used in will handle the rest */ +static inline int sendmmsg(int fd, struct mmsghdr *mmh, unsigned int len, + int flags) +{ + int rv = sendmsg(fd, &mmh->msg_hdr, 0); + + return rv > 0 ? 1 : rv; +} +#endif + /* * RFC 3542 defines several macros for using struct cmsghdr. * Here, we define those that are not present diff --git a/lib/zlog.c b/lib/zlog.c index 1b0751559..e0bb34a25 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -401,7 +401,7 @@ void zlog_tls_buffer_flush(void) return; rcu_read_lock(); - frr_each (zlog_targets, &zlog_targets, zt) { + frr_each_safe (zlog_targets, &zlog_targets, zt) { if (!zt->logfn) continue; @@ -431,7 +431,7 @@ static void vzlog_notls(const struct xref_logmsg *xref, int prio, msg->stackbufsz = sizeof(stackbuf); rcu_read_lock(); - frr_each (zlog_targets, &zlog_targets, zt) { + frr_each_safe (zlog_targets, &zlog_targets, zt) { if (prio > zt->prio_min) continue; if (!zt->logfn) @@ -908,6 +908,11 @@ size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out, uint32_t flags) return bputs(out, msg->ts_3164_str); } +void zlog_msg_tsraw(struct zlog_msg *msg, struct timespec *ts) +{ + memcpy(ts, &msg->ts, sizeof(*ts)); +} + void zlog_set_prefix_ec(bool enable) { atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed); diff --git a/lib/zlog.h b/lib/zlog.h index 6e84fe892..a530c589a 100644 --- a/lib/zlog.h +++ b/lib/zlog.h @@ -183,8 +183,11 @@ extern void zlog_msg_args(struct zlog_msg *msg, size_t *hdrlen, /* default is local time zone */ #define ZLOG_TS_UTC (1 << 10) +struct timespec; + extern size_t zlog_msg_ts(struct zlog_msg *msg, struct fbuf *out, uint32_t flags); +extern void zlog_msg_tsraw(struct zlog_msg *msg, struct timespec *ts); /* "mmm dd hh:mm:ss" for RFC3164 syslog. Only ZLOG_TS_UTC for flags. */ extern size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out, diff --git a/lib/zlog_5424.c b/lib/zlog_5424.c new file mode 100644 index 000000000..9da7c55fc --- /dev/null +++ b/lib/zlog_5424.c @@ -0,0 +1,1145 @@ +/* + * Copyright (c) 2015-21 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* when you work on this code, please install a fuzzer (e.g. AFL) and run + * tests/lib/fuzz_zlog.c + * + * The most likely type of bug in this code is an off-by-one error in the + * buffer management pieces, and this isn't easily covered by an unit test + * or topotests. Fuzzing is the best tool here, but the CI can't do that + * since it's quite resource intensive. + */ + +#include "zebra.h" + +#include "zlog_5424.h" + +#include +#include + +#include "memory.h" +#include "frrcu.h" +#include "printfrr.h" +#include "typerb.h" +#include "frr_pthread.h" +#include "command.h" +#include "monotime.h" +#include "thread.h" + +#include "lib/version.h" +#include "lib/lib_errors.h" + +DEFINE_MTYPE_STATIC(LOG, LOG_5424, "extended log target"); +DEFINE_MTYPE_STATIC(LOG, LOG_5424_ROTATE, "extended log rotate helper"); + +/* the actual log target data structure + * + * remember this is RCU'd by the core zlog functions. Changing anything + * works by allocating a new struct, filling it, adding it, and removing the + * old one. + */ +struct zlt_5424 { + struct zlog_target zt; + + atomic_uint_fast32_t fd; + + enum zlog_5424_format fmt; + uint32_t ts_flags; + int facility; + + /* the various extra pieces to add... */ + bool kw_version : 1; + bool kw_location : 1; + bool kw_uid : 1; + bool kw_ec : 1; + bool kw_args : 1; + + /* some formats may or may not include the trailing \n */ + bool use_nl : 1; + + /* for DGRAM & SEQPACKET sockets, send 1 log message per packet, since + * the socket preserves packet boundaries. On Linux, this uses + * sendmmsg() for efficiency, on other systems we need a syscall each. + */ + bool packets : 1; + + /* for DGRAM, in order to not have to reconnect, we need to use + * sendto()/sendmsg() with the destination given; otherwise we'll get + * ENOTCONN. (We do a connect(), which serves to verify the type of + * socket, but if the receiver goes away, the kernel disconnects the + * socket so writev() no longer works since the destination is now + * unspecified.) + */ + struct sockaddr_storage sa; + socklen_t sa_len; + + /* these are both getting set, but current_err is cleared on success, + * so we know whether the error is current or past. + */ + int last_err, current_err; + atomic_size_t lost_msgs; + struct timeval last_err_ts; + + struct rcu_head_close head_close; +}; + +static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type); + +/* rough header length estimate + * ============================ + * + * ^ = might grow + * + * 49^ longest filename (pceplib/test/pcep_utils_double_linked_list_test.h) + * 5^ highest line number (48530, bgpd/bgp_nb_config.c) + * 65^ longest function name + * (lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy) + * 11 unique id ("XXXXX-XXXXX") + * 10 EC ("4294967295" or "0xffffffff") + * 35 ISO8601 TS at full length ("YYYY-MM-DD HH:MM:SS.NNNNNNNNN+ZZ:ZZ") + * --- + * 175 + * + * rarely used (hopefully...): + * 26^ FRR_VERSION ("10.10.10-dev-gffffffffffff") + * --- + * 201 + * + * x16 highest number of format parameters currently + * 40 estimate for hostname + 2*daemon + pid + * + * specific format overhead: + * + * RFC3164 - shorter than the others + * RFC5424 - 175 + "<999>1 "=7 + 52 (location@50145) + 40 (host/...) + * rarely: + 65 + 26 (for [origin]) + * args: 16 * (8 + per-arg (20?)) = ~448 + * + * so without "args@", origin or (future) keywords, around 256 seems OK + * with args@ and/or origin and/or keywords, 512 seems more reasonable + * + * but - note the code allocates this amount multiplied by the number of + * messages in the incoming batch (minimum 3), this means short messages and + * long messages smooth each other out. + * + * Since the code handles space-exceeded by grabbing a bunch of stack memory, + * a reasonable middle ground estimate is desirable here, so ... + * *drumroll* + * let's go with 128 + args?128. (remember the minimum 3 multiplier) + * + * low_space is the point where we don't try to fit another message in & just + * submit what we have to the kernel. + * + * The zlog code only buffers debug & informational messages, so in production + * usage most of the calls will be writing out only 1 message. This makes + * the min *3 multiplier quite useful. + */ + +static inline size_t zlog_5424_bufsz(struct zlt_5424 *zte, size_t nmsgs, + size_t *low_space) +{ + size_t ret = 128; + + if (zte->kw_args) + ret += 128; + *low_space = ret; + return ret * MAX(nmsgs, 3); +} + +struct state { + struct fbuf *fbuf; + struct iovec *iov; +}; + +/* stack-based keyword support is likely to bump this to 3 or 4 */ +#define IOV_PER_MSG 2 +_Static_assert(IOV_MAX >= IOV_PER_MSG, + "this code won't work with IOV_MAX < IOV_PER_MSG"); + +/* the following functions are quite similar, but trying to merge them just + * makes a big mess. check the others when touching one. + * + * timestamp keywords hostname + * RFC5424 ISO8601 yes yes + * RFC3164 RFC3164 no yes + * local RFC3164 no no + * journald ISO8601(unused) yes (unused) + */ + +static size_t zlog_5424_one(struct zlt_5424 *zte, struct zlog_msg *msg, + struct state *state) +{ + size_t textlen; + struct fbuf *fbuf = state->fbuf; + char *orig_pos = fbuf->pos; + size_t need = 0; + int prio = zlog_msg_prio(msg); + intmax_t pid, tid; + + zlog_msg_pid(msg, &pid, &tid); + + need += bprintfrr(fbuf, "<%d>1 ", prio | zte->facility); + need += zlog_msg_ts(msg, fbuf, zte->ts_flags); + need += bprintfrr(fbuf, " %s %s %jd %.*s ", cmd_hostname_get() ?: "-", + zlog_progname, pid, (int)(zlog_prefixsz - 2), + zlog_prefix); + + if (zte->kw_version) + need += bprintfrr( + fbuf, + "[origin enterpriseId=\"50145\" software=\"FRRouting\" swVersion=\"%s\"]", + FRR_VERSION); + + const struct xref_logmsg *xref; + struct xrefdata *xrefdata; + + need += bprintfrr(fbuf, "[location@50145 tid=\"%jd\"", tid); + if (zlog_instance > 0) + need += bprintfrr(fbuf, " instance=\"%d\"", zlog_instance); + + xref = zlog_msg_xref(msg); + xrefdata = xref ? xref->xref.xrefdata : NULL; + if (xrefdata) { + if (zte->kw_uid) + need += bprintfrr(fbuf, " id=\"%s\"", xrefdata->uid); + if (zte->kw_ec && prio <= LOG_WARNING) + need += bprintfrr(fbuf, " ec=\"%u\"", xref->ec); + if (zte->kw_location) + need += bprintfrr( + fbuf, " file=\"%s\" line=\"%d\" func=\"%s\"", + xref->xref.file, xref->xref.line, + xref->xref.func); + } + need += bputch(fbuf, ']'); + + size_t hdrlen, n_argpos; + const struct fmt_outpos *argpos; + const char *text; + + text = zlog_msg_text(msg, &textlen); + zlog_msg_args(msg, &hdrlen, &n_argpos, &argpos); + + if (zte->kw_args && n_argpos) { + need += bputs(fbuf, "[args@50145"); + + for (size_t i = 0; i < n_argpos; i++) { + int len = argpos[i].off_end - argpos[i].off_start; + + need += bprintfrr(fbuf, " arg%zu=%*pSQsq", i + 1, len, + text + argpos[i].off_start); + } + + need += bputch(fbuf, ']'); + } + + need += bputch(fbuf, ' '); + + if (orig_pos + need > fbuf->buf + fbuf->len) { + /* not enough space in the buffer for headers. the loop in + * zlog_5424() will flush other messages that are already in + * the buffer, grab a bigger buffer if needed, and try again. + */ + fbuf->pos = orig_pos; + return need; + } + + /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */ + state->iov->iov_base = orig_pos; + state->iov->iov_len = fbuf->pos - orig_pos; + state->iov++; + + state->iov->iov_base = (char *)text + hdrlen; + state->iov->iov_len = textlen - hdrlen + zte->use_nl; + state->iov++; + return 0; +} + +static size_t zlog_3164_one(struct zlt_5424 *zte, struct zlog_msg *msg, + struct state *state) +{ + size_t textlen; + struct fbuf *fbuf = state->fbuf; + char *orig_pos = fbuf->pos; + size_t need = 0; + int prio = zlog_msg_prio(msg); + intmax_t pid, tid; + + zlog_msg_pid(msg, &pid, &tid); + + need += bprintfrr(fbuf, "<%d>", prio | zte->facility); + need += zlog_msg_ts_3164(msg, fbuf, zte->ts_flags); + if (zte->fmt != ZLOG_FMT_LOCAL) { + need += bputch(fbuf, ' '); + need += bputs(fbuf, cmd_hostname_get() ?: "-"); + } + need += bprintfrr(fbuf, " %s[%jd]: ", zlog_progname, pid); + + if (orig_pos + need > fbuf->buf + fbuf->len) { + /* not enough space in the buffer for headers. loop in + * zlog_5424() will flush other messages that are already in + * the buffer, grab a bigger buffer if needed, and try again. + */ + fbuf->pos = orig_pos; + return need; + } + + /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */ + state->iov->iov_base = orig_pos; + state->iov->iov_len = fbuf->pos - orig_pos; + state->iov++; + + state->iov->iov_base = (char *)zlog_msg_text(msg, &textlen); + state->iov->iov_len = textlen + zte->use_nl; + state->iov++; + return 0; +} + +static size_t zlog_journald_one(struct zlt_5424 *zte, struct zlog_msg *msg, + struct state *state) +{ + size_t textlen; + struct fbuf *fbuf = state->fbuf; + char *orig_pos = fbuf->pos; + size_t need = 0; + int prio = zlog_msg_prio(msg); + intmax_t pid, tid; + + zlog_msg_pid(msg, &pid, &tid); + + need += bprintfrr(fbuf, + "PRIORITY=%d\n" + "SYSLOG_FACILITY=%d\n" + "TID=%jd\n" + "FRR_DAEMON=%s\n" + "SYSLOG_TIMESTAMP=", + prio, zte->facility, tid, zlog_progname); + need += zlog_msg_ts(msg, fbuf, zte->ts_flags); + need += bputch(fbuf, '\n'); + if (zlog_instance > 0) + need += bprintfrr(fbuf, "FRR_INSTANCE=%d\n", zlog_instance); + + const struct xref_logmsg *xref; + struct xrefdata *xrefdata; + + xref = zlog_msg_xref(msg); + xrefdata = xref ? xref->xref.xrefdata : NULL; + if (xrefdata) { + if (zte->kw_uid && xrefdata->uid[0]) + need += bprintfrr(fbuf, "FRR_ID=%s\n", xrefdata->uid); + if (zte->kw_ec && prio <= LOG_WARNING) + need += bprintfrr(fbuf, "FRR_EC=%d\n", xref->ec); + if (zte->kw_location) + need += bprintfrr(fbuf, + "CODE_FILE=%s\n" + "CODE_LINE=%d\n" + "CODE_FUNC=%s\n", + xref->xref.file, xref->xref.line, + xref->xref.func); + } + + size_t hdrlen, n_argpos; + const struct fmt_outpos *argpos; + const char *text; + + text = zlog_msg_text(msg, &textlen); + zlog_msg_args(msg, &hdrlen, &n_argpos, &argpos); + + if (zte->kw_args && n_argpos) { + for (size_t i = 0; i < n_argpos; i++) { + int len = argpos[i].off_end - argpos[i].off_start; + + /* rather than escape the value, we could use + * journald's binary encoding, but that seems a bit + * excessive/unnecessary. 99% of things we print here + * will just output 1:1 with %pSE. + */ + need += bprintfrr(fbuf, "FRR_ARG%zu=%*pSE\n", i + 1, + len, text + argpos[i].off_start); + } + } + + need += bputs(fbuf, "MESSAGE="); + + if (orig_pos + need > fbuf->buf + fbuf->len) { + /* not enough space in the buffer for headers. loop in + * zlog_5424() will flush other messages that are already in + * the buffer, grab a bigger buffer if needed, and try again. + */ + fbuf->pos = orig_pos; + return need; + } + + /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */ + state->iov->iov_base = orig_pos; + state->iov->iov_len = fbuf->pos - orig_pos; + state->iov++; + + state->iov->iov_base = (char *)text + hdrlen; + state->iov->iov_len = textlen - hdrlen + 1; + state->iov++; + return 0; +} + +static size_t zlog_one(struct zlt_5424 *zte, struct zlog_msg *msg, + struct state *state) +{ + switch (zte->fmt) { + case ZLOG_FMT_5424: + return zlog_5424_one(zte, msg, state); + case ZLOG_FMT_3164: + case ZLOG_FMT_LOCAL: + return zlog_3164_one(zte, msg, state); + case ZLOG_FMT_JOURNALD: + return zlog_journald_one(zte, msg, state); + } + return 0; +} + +static void zlog_5424_err(struct zlt_5424 *zte, size_t count) +{ + if (!count) { + zte->current_err = 0; + return; + } + + /* only the counter is atomic because otherwise it'd be meaningless */ + atomic_fetch_add_explicit(&zte->lost_msgs, count, memory_order_relaxed); + + /* these are non-atomic and can provide wrong results when read, but + * since they're only for debugging / display, that's OK. + */ + zte->current_err = zte->last_err = errno; + monotime(&zte->last_err_ts); +} + +static void zlog_5424(struct zlog_target *zt, struct zlog_msg *msgs[], + size_t nmsgs) +{ + size_t i; + struct zlt_5424 *zte = container_of(zt, struct zlt_5424, zt); + int fd, ret; + size_t niov = MIN(IOV_PER_MSG * nmsgs, IOV_MAX); + struct iovec iov[niov], *iov_last = iov + niov; + struct mmsghdr mmsg[zte->packets ? nmsgs : 1], *mpos = mmsg; + size_t count = 0; + + /* refer to size estimate at top of file */ + size_t low_space; + char hdr_buf[zlog_5424_bufsz(zte, nmsgs, &low_space)]; + struct fbuf hdr_pos = { + .buf = hdr_buf, + .pos = hdr_buf, + .len = sizeof(hdr_buf), + }; + struct state state = { + .fbuf = &hdr_pos, + .iov = iov, + }; + + fd = atomic_load_explicit(&zte->fd, memory_order_relaxed); + + memset(mmsg, 0, sizeof(mmsg)); + if (zte->sa_len) { + for (i = 0; i < array_size(mmsg); i++) { + mmsg[i].msg_hdr.msg_name = (struct sockaddr *)&zte->sa; + mmsg[i].msg_hdr.msg_namelen = zte->sa_len; + } + } + mmsg[0].msg_hdr.msg_iov = iov; + + for (i = 0; i < nmsgs; i++) { + int prio = zlog_msg_prio(msgs[i]); + size_t need = 0; + + if (prio <= zte->zt.prio_min) { + if (zte->packets) + mpos->msg_hdr.msg_iov = state.iov; + + need = zlog_one(zte, msgs[i], &state); + + if (zte->packets) { + mpos->msg_hdr.msg_iovlen = + state.iov - mpos->msg_hdr.msg_iov; + mpos++; + } + count++; + } + + /* clang-format off */ + if ((need + || (size_t)(hdr_pos.buf + hdr_pos.len - hdr_pos.pos) + < low_space + || i + 1 == nmsgs + || state.iov + IOV_PER_MSG > iov_last) + && state.iov > iov) { + /* clang-format on */ + + if (zte->packets) { + struct mmsghdr *sendpos; + + for (sendpos = mmsg; sendpos < mpos;) { + ret = sendmmsg(fd, sendpos, + mpos - sendpos, 0); + if (ret <= 0) + break; + sendpos += ret; + } + zlog_5424_err(zte, mpos - sendpos); + mpos = mmsg; + } else { + if (!zte->sa_len) + ret = writev(fd, iov, state.iov - iov); + else { + mpos->msg_hdr.msg_iovlen = + state.iov - iov; + ret = sendmsg(fd, &mpos->msg_hdr, 0); + } + + if (ret < 0) + zlog_5424_err(zte, count); + else + zlog_5424_err(zte, 0); + } + + count = 0; + hdr_pos.pos = hdr_buf; + state.iov = iov; + } + + /* if need == 0, we just put a message (or nothing) in the + * buffer and are continuing for more to batch in a single + * writev() + */ + if (need == 0) + continue; + + if (need && need <= sizeof(hdr_buf)) { + /* don't need to allocate, just try this msg + * again without other msgs already using up + * buffer space + */ + i--; + continue; + } + + /* need > sizeof(hdr_buf), need to grab some memory. Taking + * it off the stack is fine here. + */ + char buf2[need]; + struct fbuf fbuf2 = { + .buf = buf2, + .pos = buf2, + .len = sizeof(buf2), + }; + + state.fbuf = &fbuf2; + need = zlog_one(zte, msgs[i], &state); + assert(need == 0); + + if (!zte->sa_len) + ret = writev(fd, iov, state.iov - iov); + else { + mpos->msg_hdr.msg_iovlen = state.iov - iov; + ret = sendmsg(fd, &mpos->msg_hdr, 0); + } + + if (ret < 0) + zlog_5424_err(zte, 1); + else + zlog_5424_err(zte, 0); + + count = 0; + state.fbuf = &hdr_pos; + state.iov = iov; + mpos = mmsg; + } + + assert(state.iov == iov); +} + +/* strftime(), gmtime_r() and localtime_r() aren't AS-Safe (they access locale + * data), but we need an AS-Safe timestamp below :( + */ +static void gmtime_assafe(time_t ts, struct tm *res) +{ + res->tm_sec = ts % 60; + ts /= 60; + res->tm_min = ts % 60; + ts /= 60; + res->tm_hour = ts % 24; + ts /= 24; + + ts -= 11017; /* start on 2020-03-01, 11017 days since 1970-01-01 */ + + /* 1461 days = 3 regular years + 1 leap year + * this works until 2100, which isn't a leap year + * + * struct tm.tm_year starts at 1900. + */ + res->tm_year = 2000 - 1900 + 4 * (ts / 1461); + ts = ts % 1461; + + if (ts == 1460) { + res->tm_year += 4; + res->tm_mon = 1; + res->tm_mday = 29; + return; + } + res->tm_year += ts / 365; + ts %= 365; + + /* note we're starting in march like the romans did... */ + if (ts >= 306) /* Jan 1 of next year */ + res->tm_year++; + + static unsigned int months[13] = { + 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 365, + }; + + for (size_t i = 0; i < array_size(months); i++) { + if ((unsigned int)ts < months[i + 1]) { + res->tm_mon = ((i + 2) % 12); + res->tm_mday = 1 + ts - months[i]; + break; + } + } +} + +/* one of the greatest advantages of this logging target: unlike syslog(), + * which is not AS-Safe, we can send crashlogs to syslog here. + */ +static void zlog_5424_sigsafe(struct zlog_target *zt, const char *text, + size_t len) +{ + static const char *const months_3164[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + + struct zlt_5424 *zte = container_of(zt, struct zlt_5424, zt); + struct iovec iov[3], *iovp = iov; + char buf[256]; + struct fbuf fbuf = { + .buf = buf, + .pos = buf, + .len = sizeof(buf), + }; + int fd; + intmax_t pid = (intmax_t)getpid(); + struct tm tm; + + switch (zte->fmt) { + case ZLOG_FMT_5424: + gmtime_assafe(time(NULL), &tm); + bprintfrr( + &fbuf, + "<%d>1 %04u-%02u-%02uT%02u:%02u:%02uZ - %s %jd %.*s ", + zte->facility | LOG_CRIT, tm.tm_year + 1900, + tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, + tm.tm_sec, zlog_progname, pid, (int)(zlog_prefixsz - 2), + zlog_prefix); + break; + + case ZLOG_FMT_3164: + case ZLOG_FMT_LOCAL: + /* this will unfortuantely be wrong by the timezone offset + * if the user selected non-UTC. But not much we can do + * about that... + */ + gmtime_assafe(time(NULL), &tm); + bprintfrr(&fbuf, "<%d>%3s %2u %02u:%02u:%02u %s%s[%jd]: ", + zte->facility | LOG_CRIT, months_3164[tm.tm_mon], + tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, + (zte->fmt == ZLOG_FMT_LOCAL) ? "" : "- ", + zlog_progname, pid); + break; + + case ZLOG_FMT_JOURNALD: + bprintfrr(&fbuf, + "PRIORITY=%d\n" + "SYSLOG_FACILITY=%d\n" + "FRR_DAEMON=%s\n" + "MESSAGE=", + LOG_CRIT, zte->facility, zlog_progname); + break; + } + + iovp->iov_base = fbuf.buf; + iovp->iov_len = fbuf.pos - fbuf.buf; + iovp++; + + iovp->iov_base = (char *)text; + iovp->iov_len = len; + iovp++; + + if (zte->use_nl) { + iovp->iov_base = (char *)"\n"; + iovp->iov_len = 1; + iovp++; + } + + fd = atomic_load_explicit(&zte->fd, memory_order_relaxed); + + if (!zte->sa_len) + writev(fd, iov, iovp - iov); + else { + struct msghdr mh = {}; + + mh.msg_name = (struct sockaddr *)&zte->sa; + mh.msg_namelen = zte->sa_len; + mh.msg_iov = iov; + mh.msg_iovlen = iovp - iov; + sendmsg(fd, &mh, 0); + } +} + +/* housekeeping & configuration */ + +void zlog_5424_init(struct zlog_cfg_5424 *zcf) +{ + pthread_mutex_init(&zcf->cfg_mtx, NULL); +} + +static void zlog_5424_target_free(struct zlt_5424 *zlt) +{ + if (!zlt) + return; + + rcu_close(&zlt->head_close, zlt->fd); + rcu_free(MTYPE_LOG_5424, zlt, zt.rcu_head); +} + +void zlog_5424_fini(struct zlog_cfg_5424 *zcf, bool keepopen) +{ + if (keepopen) + zcf->active = NULL; + + if (zcf->active) { + struct zlt_5424 *ztf; + struct zlog_target *zt; + + zt = zlog_target_replace(&zcf->active->zt, NULL); + ztf = container_of(zt, struct zlt_5424, zt); + zlog_5424_target_free(ztf); + } + pthread_mutex_destroy(&zcf->cfg_mtx); +} + +static void zlog_5424_cycle(struct zlog_cfg_5424 *zcf, int fd) +{ + struct zlog_target *old; + struct zlt_5424 *zlt = NULL, *oldt; + + if (fd >= 0) { + struct zlog_target *zt; + + /* all of this is swapped in by zlog_target_replace() below, + * the old target is RCU-freed afterwards. + */ + zt = zlog_target_clone(MTYPE_LOG_5424, &zcf->active->zt, + sizeof(*zlt)); + zlt = container_of(zt, struct zlt_5424, zt); + + zlt->fd = fd; + zlt->kw_version = zcf->kw_version; + zlt->kw_location = zcf->kw_location; + zlt->kw_uid = zcf->kw_uid; + zlt->kw_ec = zcf->kw_ec; + zlt->kw_args = zcf->kw_args; + zlt->use_nl = true; + zlt->facility = zcf->facility; + + /* DGRAM & SEQPACKET = 1 log message per packet */ + zlt->packets = (zcf->sock_type == SOCK_DGRAM) || + (zcf->sock_type == SOCK_SEQPACKET); + zlt->sa = zcf->sa; + zlt->sa_len = zcf->sa_len; + zlt->fmt = zcf->fmt; + zlt->zt.prio_min = zcf->prio_min; + zlt->zt.logfn = zlog_5424; + zlt->zt.logfn_sigsafe = zlog_5424_sigsafe; + + switch (zcf->fmt) { + case ZLOG_FMT_5424: + case ZLOG_FMT_JOURNALD: + zlt->ts_flags = zcf->ts_flags; + zlt->ts_flags &= ZLOG_TS_PREC | ZLOG_TS_UTC; + zlt->ts_flags |= ZLOG_TS_ISO8601; + break; + case ZLOG_FMT_3164: + case ZLOG_FMT_LOCAL: + zlt->ts_flags = zcf->ts_flags & ZLOG_TS_UTC; + if (zlt->packets) + zlt->use_nl = false; + break; + } + } + + old = zcf->active ? &zcf->active->zt : NULL; + old = zlog_target_replace(old, &zlt->zt); + zcf->active = zlt; + + /* oldt->fd == fd happens for zlog_5424_apply_meta() */ + oldt = container_of(old, struct zlt_5424, zt); + if (oldt && oldt->fd != (unsigned int)fd) + rcu_close(&oldt->head_close, oldt->fd); + rcu_free(MTYPE_LOG_5424, oldt, zt.rcu_head); +} + +static void zlog_5424_reconnect(struct thread *t) +{ + struct zlog_cfg_5424 *zcf = THREAD_ARG(t); + int fd = THREAD_FD(t); + char dummy[256]; + ssize_t ret; + + if (zcf->active) { + ret = read(fd, dummy, sizeof(dummy)); + if (ret > 0) { + /* logger is sending us something?!?! */ + thread_add_read(t->master, zlog_5424_reconnect, zcf, fd, + &zcf->t_reconnect); + return; + } + + if (ret == 0) + zlog_warn("logging socket %pSE closed by peer", + zcf->filename); + else + zlog_warn("logging socket %pSE error: %m", + zcf->filename); + } + + /* do NOT close() anything here; other threads may still be writing + * and their messages need to be lost rather than end up on a random + * other fd that got reassigned the same number, like a BGP session! + */ + fd = zlog_5424_open(zcf, -1); + + frr_with_mutex (&zcf->cfg_mtx) { + zlog_5424_cycle(zcf, fd); + } +} + +static int zlog_5424_unix(struct sockaddr_un *suna, int sock_type) +{ + int fd; + int size = 1 * 1024 * 1024, prev_size; + socklen_t opt_size; + int save_errno; + + fd = socket(AF_UNIX, sock_type, 0); + if (fd < 0) + return -1; + + if (connect(fd, (struct sockaddr *)suna, sizeof(*suna))) { + /* zlog_5424_open() will print the error for connect() */ + save_errno = errno; + close(fd); + errno = save_errno; + return -1; + } + + opt_size = sizeof(prev_size); + if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &prev_size, &opt_size)) + return fd; + + /* setsockopt_so_sendbuf() logs on error; we don't really care that + * much here. Also, never shrink the buffer below the initial size. + */ + while (size > prev_size && + setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1) + size /= 2; + + return fd; +} + +static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) +{ + int fd = -1; + int flags = 0; + int err; + socklen_t optlen; + bool do_chown = false; + bool need_reconnect = false; + static const int unix_types[] = { + SOCK_STREAM, + SOCK_SEQPACKET, + SOCK_DGRAM, + }; + struct sockaddr_un sa; + + zcf->sock_type = -1; + zcf->sa_len = 0; + + switch (zcf->dst) { + case ZLOG_5424_DST_NONE: + break; + + case ZLOG_5424_DST_FD: + fd = dup(zcf->fd); + + optlen = sizeof(sock_type); + if (!getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &optlen)) { + zcf->sock_type = sock_type; + need_reconnect = (zcf->sock_type != SOCK_DGRAM); + } + break; + + case ZLOG_5424_DST_FIFO: + if (!zcf->filename) + break; + + if (!zcf->file_nocreate) { + frr_with_privs (lib_privs) { + mode_t prevmask; + + prevmask = umask(0777 ^ zcf->file_mode); + err = mkfifo(zcf->filename, 0666); + umask(prevmask); + } + if (err == 0) + do_chown = true; + else if (errno != EEXIST) + break; + } + + flags = O_NONBLOCK; + /* fallthru */ + + case ZLOG_5424_DST_FILE: + if (!zcf->filename) + break; + + frr_with_privs (lib_privs) { + fd = open(zcf->filename, flags | O_WRONLY | O_APPEND | + O_CLOEXEC | O_NOCTTY); + } + if (fd >= 0) + break; + if (zcf->file_nocreate || flags) { + flog_err_sys(EC_LIB_SYSTEM_CALL, + "could not open log file %pSE: %m", + zcf->filename); + break; + } + + frr_with_privs (lib_privs) { + mode_t prevmask; + + prevmask = umask(0777 ^ zcf->file_mode); + fd = open(zcf->filename, + O_WRONLY | O_APPEND | O_CLOEXEC | O_NOCTTY | + O_CREAT | O_EXCL, + zcf->file_mode); + umask(prevmask); + } + if (fd >= 0) { + do_chown = true; + break; + } + + frr_with_privs (lib_privs) { + fd = open(zcf->filename, + O_WRONLY | O_APPEND | O_CLOEXEC | O_NOCTTY); + } + if (fd >= 0) + break; + + flog_err_sys(EC_LIB_SYSTEM_CALL, + "could not open or create log file %pSE: %m", + zcf->filename); + break; + + case ZLOG_5424_DST_UNIX: + if (!zcf->filename) + break; + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + strlcpy(sa.sun_path, zcf->filename, sizeof(sa.sun_path)); + + /* check if ZLOG_5424_DST_FD needs a touch when changing + * something here. the user can pass in a pre-opened unix + * socket through a fd at startup. + */ + frr_with_privs (lib_privs) { + if (sock_type != -1) + fd = zlog_5424_unix(&sa, sock_type); + else { + for (size_t i = 0; i < array_size(unix_types); + i++) { + fd = zlog_5424_unix(&sa, unix_types[i]); + if (fd != -1) { + zcf->sock_type = unix_types[i]; + break; + } + } + } + } + if (fd == -1) { + zcf->sock_type = -1; + + flog_err_sys( + EC_LIB_SYSTEM_CALL, + "could not connect to log unix path %pSE: %m", + zcf->filename); + need_reconnect = true; + } else { + /* datagram sockets are connectionless, restarting + * the receiver may lose some packets but will resume + * working afterwards without any action from us. + */ + need_reconnect = (zcf->sock_type != SOCK_DGRAM); + } + break; + } + + /* viable on both DST_FD and DST_UNIX path */ + if (zcf->sock_type == SOCK_DGRAM) { + zcf->sa_len = sizeof(zcf->sa); + if (getpeername(fd, (struct sockaddr *)&zcf->sa, + &zcf->sa_len)) { + flog_err_sys( + EC_LIB_SYSTEM_CALL, + "could not get remote address for log socket. logging may break if log receiver restarts."); + zcf->sa_len = 0; + } + } + + if (do_chown) { + uid_t uid = zcf->file_uid; + gid_t gid = zcf->file_gid; + + if (uid != (uid_t)-1 || gid != (gid_t)-1) { + frr_with_privs (lib_privs) { + err = fchown(fd, uid, gid); + } + if (err) + flog_err_sys( + EC_LIB_SYSTEM_CALL, + "failed to chown() log file %pSE: %m", + zcf->filename); + } + } + + if (need_reconnect) { + assert(zcf->master); + + if (fd != -1) { + thread_add_read(zcf->master, zlog_5424_reconnect, zcf, + fd, &zcf->t_reconnect); + zcf->reconn_backoff_cur = zcf->reconn_backoff; + + } else { + thread_add_timer_msec(zcf->master, zlog_5424_reconnect, + zcf, zcf->reconn_backoff_cur, + &zcf->t_reconnect); + + zcf->reconn_backoff_cur += zcf->reconn_backoff_cur / 2; + if (zcf->reconn_backoff_cur > zcf->reconn_backoff_max) + zcf->reconn_backoff_cur = + zcf->reconn_backoff_max; + } + } + + return fd; +} + +bool zlog_5424_apply_dst(struct zlog_cfg_5424 *zcf) +{ + int fd = -1; + + thread_cancel(&zcf->t_reconnect); + + if (zcf->prio_min != ZLOG_DISABLED) + fd = zlog_5424_open(zcf, -1); + + frr_with_mutex (&zcf->cfg_mtx) { + zlog_5424_cycle(zcf, fd); + } + return fd != -1; +} + + +bool zlog_5424_apply_meta(struct zlog_cfg_5424 *zcf) +{ + frr_with_mutex (&zcf->cfg_mtx) { + if (zcf->active) + zlog_5424_cycle(zcf, zcf->active->fd); + } + + return true; +} + +void zlog_5424_state(struct zlog_cfg_5424 *zcf, size_t *lost_msgs, + int *last_errno, bool *stale_errno, struct timeval *err_ts) +{ + if (lost_msgs) + *lost_msgs = + zcf->active + ? atomic_load_explicit(&zcf->active->lost_msgs, + memory_order_relaxed) + : 0; + if (last_errno) + *last_errno = zcf->active ? zcf->active->last_err : 0; + if (stale_errno) + *stale_errno = zcf->active ? !zcf->active->current_err : 0; + if (err_ts && zcf->active) + *err_ts = zcf->active->last_err_ts; +} + +struct rcu_close_rotate { + struct rcu_head_close head_close; + struct rcu_head head_self; +}; + +bool zlog_5424_rotate(struct zlog_cfg_5424 *zcf) +{ + struct rcu_close_rotate *rcr; + int fd; + + frr_with_mutex (&zcf->cfg_mtx) { + if (!zcf->active) + return true; + + thread_cancel(&zcf->t_reconnect); + + /* need to retain the socket type because it also influences + * other fields (packets) and we can't atomically swap these + * out. But we really want the atomic swap so we neither lose + * nor duplicate log messages, particularly for file targets. + * + * (zlog_5424_apply_dst / zlog_target_replace will cause + * duplicate log messages if another thread logs something + * while we're right in the middle of swapping out the log + * target) + */ + fd = zlog_5424_open(zcf, zcf->sock_type); + if (fd < 0) + return false; + + fd = atomic_exchange_explicit(&zcf->active->fd, + (uint_fast32_t)fd, + memory_order_relaxed); + } + + rcr = XCALLOC(MTYPE_LOG_5424_ROTATE, sizeof(*rcr)); + rcu_close(&rcr->head_close, fd); + rcu_free(MTYPE_LOG_5424_ROTATE, rcr, head_self); + + return true; +} diff --git a/lib/zlog_5424.h b/lib/zlog_5424.h new file mode 100644 index 000000000..b4a12ccbf --- /dev/null +++ b/lib/zlog_5424.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2021 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _FRR_ZLOG_5424_H +#define _FRR_ZLOG_5424_H + +#include + +#include "typerb.h" +#include "zlog.h" +#include "zlog_targets.h" +#include "qobj.h" + +struct thread; +struct thread_master; + +enum zlog_5424_dst { + /* can be used to disable a target temporarily */ + ZLOG_5424_DST_NONE = 0, + + ZLOG_5424_DST_FD, + ZLOG_5424_DST_FILE, + ZLOG_5424_DST_FIFO, + ZLOG_5424_DST_UNIX, + +#define ZLOG_5424_DST_LAST ZLOG_5424_DST_UNIX +}; + +enum zlog_5424_format { + ZLOG_FMT_5424 = 0, + ZLOG_FMT_3164, + ZLOG_FMT_LOCAL, + ZLOG_FMT_JOURNALD, + +#define ZLOG_FMT_LAST ZLOG_FMT_JOURNALD +}; + +/* actual RCU'd logging backend */ +struct zlt_5424; + +struct zlog_cfg_5424 { + struct zlt_5424 *active; + + pthread_mutex_t cfg_mtx; + + /* general settings for all dsts */ + int facility; + int prio_min; + bool kw_version; + bool kw_location; + bool kw_uid; + bool kw_ec; + bool kw_args; + + uint32_t ts_flags; + + enum zlog_5424_format fmt; + + /* destination specifics */ + enum zlog_5424_dst dst; + + /* pre-opened FD. not the actual fd we log to */ + int fd; + + /* file, fifo, unix */ + bool file_nocreate; + + const char *filename; + mode_t file_mode; + /* -1 = no change */ + uid_t file_uid; + gid_t file_gid; + + /* remaining fields are internally used & updated by the 5424 + * code - *not* config. don't set these. + */ + + /* sockets only - read handler to reconnect on errors */ + struct thread_master *master; + struct thread *t_reconnect; + unsigned int reconn_backoff, reconn_backoff_cur, reconn_backoff_max; + int sock_type; + struct sockaddr_storage sa; + socklen_t sa_len; +}; + +/* these don't do malloc/free to allow using a static global */ +extern void zlog_5424_init(struct zlog_cfg_5424 *zcf); + +/* keepopen = true => for shutdown, just zap the config, keep logging */ +extern void zlog_5424_fini(struct zlog_cfg_5424 *zcf, bool keepopen); + +/* apply metadata/config changes */ +extern bool zlog_5424_apply_meta(struct zlog_cfg_5424 *zcf); + +/* apply changes requiring (re-)opening the destination + * + * also does log cycling/rotate & applies _meta at the same time + */ +extern bool zlog_5424_apply_dst(struct zlog_cfg_5424 *zcf); + +/* SIGHUP log rotation */ +extern bool zlog_5424_rotate(struct zlog_cfg_5424 *zcf); + +extern void zlog_5424_state(struct zlog_cfg_5424 *zcf, size_t *lost_msgs, + int *last_errno, bool *stale_errno, + struct timeval *err_ts); + +/* this is the dynamically allocated "variant" */ +PREDECL_RBTREE_UNIQ(targets); + +struct zlog_cfg_5424_user { + struct targets_item targets_item; + char *name; + + struct zlog_cfg_5424 cfg; + + char *envvar; + + /* non-const, always same as cfg.filename */ + char *filename; + + /* uid/gid strings to write back out in show config */ + char *file_user; + char *file_group; + + bool reconf_dst; + bool reconf_meta; + + int unix_special; + + QOBJ_FIELDS; +}; + +DECLARE_QOBJ_TYPE(zlog_cfg_5424_user); + +extern void log_5424_cmd_init(void); + +#endif /* _FRR_ZLOG_5424_H */ diff --git a/lib/zlog_5424_cli.c b/lib/zlog_5424_cli.c new file mode 100644 index 000000000..dd8dbfaff --- /dev/null +++ b/lib/zlog_5424_cli.c @@ -0,0 +1,1006 @@ +/* + * Copyright (C) 2021 David Lamparter for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "zebra.h" +#include "zlog_5424.h" + +#include +#include +#include + +#include "lib/command.h" +#include "lib/libfrr.h" +#include "lib/log_vty.h" + +DEFINE_MTYPE_STATIC(LOG, LOG_5424_CONFIG, "extended syslog config"); +DEFINE_MTYPE_STATIC(LOG, LOG_5424_DATA, "extended syslog config items"); + +static int target_cmp(const struct zlog_cfg_5424_user *a, + const struct zlog_cfg_5424_user *b) +{ + return strcmp(a->name, b->name); +} + +DECLARE_RBTREE_UNIQ(targets, struct zlog_cfg_5424_user, targets_item, + target_cmp); +DEFINE_QOBJ_TYPE(zlog_cfg_5424_user); + +static struct targets_head targets = INIT_RBTREE_UNIQ(targets); +static struct thread_master *log_5424_master; + +static void clear_dst(struct zlog_cfg_5424_user *cfg); + +struct log_option { + const char *name; + ptrdiff_t offs; + bool dflt; +}; + +/* clang-format off */ +static struct log_option log_opts[] = { + { "code-location", offsetof(struct zlog_cfg_5424, kw_location) }, + { "version", offsetof(struct zlog_cfg_5424, kw_version) }, + { "unique-id", offsetof(struct zlog_cfg_5424, kw_uid), true }, + { "error-category", offsetof(struct zlog_cfg_5424, kw_ec), true }, + { "format-args", offsetof(struct zlog_cfg_5424, kw_args) }, + {}, +}; + +#define DFLT_TS_FLAGS (6 | ZLOG_TS_UTC) +#define DFLT_FACILITY LOG_DAEMON +#define DFLT_PRIO_MIN LOG_DEBUG +/* clang-format on */ + +enum unix_special { + SPECIAL_NONE = 0, + SPECIAL_SYSLOG, + SPECIAL_JOURNALD, +}; + +static struct zlog_cfg_5424_user *log_5424_alloc(const char *name) +{ + struct zlog_cfg_5424_user *cfg; + + cfg = XCALLOC(MTYPE_LOG_5424_CONFIG, sizeof(*cfg)); + cfg->name = XSTRDUP(MTYPE_LOG_5424_DATA, name); + + cfg->cfg.master = log_5424_master; + cfg->cfg.kw_location = true; + cfg->cfg.kw_version = false; + cfg->cfg.facility = DFLT_FACILITY; + cfg->cfg.prio_min = DFLT_PRIO_MIN; + cfg->cfg.ts_flags = DFLT_TS_FLAGS; + clear_dst(cfg); + + for (struct log_option *opt = log_opts; opt->name; opt++) { + bool *ptr = (bool *)(((char *)&cfg->cfg) + opt->offs); + *ptr = opt->dflt; + } + + zlog_5424_init(&cfg->cfg); + + QOBJ_REG(cfg, zlog_cfg_5424_user); + targets_add(&targets, cfg); + return cfg; +} + +static void log_5424_free(struct zlog_cfg_5424_user *cfg, bool keepopen) +{ + targets_del(&targets, cfg); + QOBJ_UNREG(cfg); + + zlog_5424_fini(&cfg->cfg, keepopen); + clear_dst(cfg); + + XFREE(MTYPE_LOG_5424_DATA, cfg->filename); + XFREE(MTYPE_LOG_5424_DATA, cfg->name); + XFREE(MTYPE_LOG_5424_CONFIG, cfg); +} + +static void clear_dst(struct zlog_cfg_5424_user *cfg) +{ + XFREE(MTYPE_LOG_5424_DATA, cfg->filename); + cfg->cfg.filename = cfg->filename; + + XFREE(MTYPE_LOG_5424_DATA, cfg->file_user); + XFREE(MTYPE_LOG_5424_DATA, cfg->file_group); + XFREE(MTYPE_LOG_5424_DATA, cfg->envvar); + + cfg->cfg.fd = -1; + cfg->cfg.file_uid = -1; + cfg->cfg.file_gid = -1; + cfg->cfg.file_mode = LOGFILE_MASK & 0666; + cfg->cfg.file_nocreate = false; + cfg->cfg.dst = ZLOG_5424_DST_NONE; +} + +static int reconf_dst(struct zlog_cfg_5424_user *cfg, struct vty *vty) +{ + if (!cfg->reconf_dst && !cfg->reconf_meta && vty->type != VTY_FILE) + vty_out(vty, + "%% Changes will be applied when exiting this config block\n"); + + cfg->reconf_dst = true; + return CMD_SUCCESS; +} + +static int reconf_meta(struct zlog_cfg_5424_user *cfg, struct vty *vty) +{ + if (!cfg->reconf_dst && !cfg->reconf_meta && vty->type != VTY_FILE) + vty_out(vty, + "%% Changes will be applied when exiting this config block\n"); + + cfg->reconf_meta = true; + return CMD_SUCCESS; +} + +static int reconf_clear_dst(struct zlog_cfg_5424_user *cfg, struct vty *vty) +{ + if (cfg->cfg.dst == ZLOG_5424_DST_NONE) + return CMD_SUCCESS; + + clear_dst(cfg); + return reconf_dst(cfg, vty); +} + +#ifndef VTYSH_EXTRACT_PL +#include "lib/zlog_5424_cli_clippy.c" +#endif + +DEFPY_NOSH(log_5424_target, + log_5424_target_cmd, + "log extended-syslog EXTLOGNAME", + "Logging control\n" + "Extended RFC5424 syslog (including file targets)\n" + "Name identifying this syslog target\n") +{ + struct zlog_cfg_5424_user *cfg, ref; + + ref.name = (char *)extlogname; + cfg = targets_find(&targets, &ref); + + if (!cfg) + cfg = log_5424_alloc(extlogname); + + VTY_PUSH_CONTEXT(EXTLOG_NODE, cfg); + return CMD_SUCCESS; +} + +DEFPY(no_log_5424_target, + no_log_5424_target_cmd, + "no log extended-syslog EXTLOGNAME", + NO_STR + "Logging control\n" + "Extended RFC5424 syslog (including file targets)\n" + "Name identifying this syslog target\n") +{ + struct zlog_cfg_5424_user *cfg, ref; + + ref.name = (char *)extlogname; + cfg = targets_find(&targets, &ref); + + if (!cfg) { + vty_out(vty, "%% No extended syslog target named \"%s\"\n", + extlogname); + return CMD_WARNING; + } + + log_5424_free(cfg, false); + return CMD_SUCCESS; +} + +/* "format $fmt" */ +#define FORMAT_HELP \ + "Select log message formatting\n" \ + "RFC3164 (legacy) syslog\n" \ + "RFC5424 (modern) syslog, supports structured data (default)\n" \ + "modified RFC3164 without hostname for local syslogd (/dev/log)\n" \ + "journald (systemd log) native format\n" \ + /* end */ + +static enum zlog_5424_format log_5424_fmt(const char *fmt, + enum zlog_5424_format dflt) +{ + if (!fmt) + return dflt; + else if (!strcmp(fmt, "rfc5424")) + return ZLOG_FMT_5424; + else if (!strcmp(fmt, "rfc3164")) + return ZLOG_FMT_3164; + else if (!strcmp(fmt, "local-syslogd")) + return ZLOG_FMT_LOCAL; + else if (!strcmp(fmt, "journald")) + return ZLOG_FMT_JOURNALD; + + return dflt; +} + +DEFPY(log_5424_destination_file, + log_5424_destination_file_cmd, + "[no] destination file$type PATH " + "[create$create [{user WORD|group WORD|mode PERMS}]" + "|no-create$nocreate] " + "[format $fmt]", + NO_STR + "Log destination setup\n" + "Log to file\n" + "Path to destination\n" + "Create file if it does not exist\n" + "Set file owner\n" + "User name\n" + "Set file group\n" + "Group name\n" + "Set permissions\n" + "File permissions (octal)\n" + "Do not create file if it does not exist\n" + FORMAT_HELP) +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + enum zlog_5424_dst dst; + bool reconf = true, warn_perm = false; + char *prev_user, *prev_group; + mode_t perm_val = LOGFILE_MASK & 0666; + enum zlog_5424_format fmtv; + + if (no) + return reconf_clear_dst(cfg, vty); + + fmtv = log_5424_fmt(fmt, ZLOG_FMT_5424); + + if (perms) { + char *errp = (char *)perms; + + perm_val = strtoul(perms, &errp, 8); + if (*errp || errp == perms || perm_val == 0 || + (perm_val & ~0666)) { + vty_out(vty, "%% Invalid permissions value \"%s\"\n", + perms); + return CMD_WARNING; + } + } + + dst = (strcmp(type, "fifo") == 0) ? ZLOG_5424_DST_FIFO + : ZLOG_5424_DST_FILE; + + if (cfg->filename && !strcmp(path, cfg->filename) && + dst == cfg->cfg.dst && cfg->cfg.active && cfg->cfg.fmt == fmtv) + reconf = false; + + /* keep for compare below */ + prev_user = cfg->file_user; + prev_group = cfg->file_group; + cfg->file_user = NULL; + cfg->file_group = NULL; + + clear_dst(cfg); + + cfg->filename = XSTRDUP(MTYPE_LOG_5424_DATA, path); + cfg->cfg.dst = dst; + cfg->cfg.filename = cfg->filename; + cfg->cfg.fmt = fmtv; + + if (nocreate) + cfg->cfg.file_nocreate = true; + else { + if (user) { + struct passwd *pwent; + + warn_perm |= (prev_user && strcmp(user, prev_user)); + cfg->file_user = XSTRDUP(MTYPE_LOG_5424_DATA, user); + + errno = 0; + pwent = getpwnam(user); + if (!pwent) + vty_out(vty, + "%% Could not look up user \"%s\" (%s), file owner will be left untouched!\n", + user, + errno ? safe_strerror(errno) + : "No entry by this user name"); + else + cfg->cfg.file_uid = pwent->pw_uid; + } + if (group) { + struct group *grent; + + warn_perm |= (prev_group && strcmp(group, prev_group)); + cfg->file_group = XSTRDUP(MTYPE_LOG_5424_DATA, group); + + errno = 0; + grent = getgrnam(group); + if (!grent) + vty_out(vty, + "%% Could not look up group \"%s\" (%s), file group will be left untouched!\n", + group, + errno ? safe_strerror(errno) + : "No entry by this group name"); + else + cfg->cfg.file_gid = grent->gr_gid; + } + } + XFREE(MTYPE_LOG_5424_DATA, prev_user); + XFREE(MTYPE_LOG_5424_DATA, prev_group); + + if (cfg->cfg.file_uid != (uid_t)-1 || cfg->cfg.file_gid != (gid_t)-1) { + struct stat st; + + if (stat(cfg->filename, &st) == 0) { + warn_perm |= (st.st_uid != cfg->cfg.file_uid); + warn_perm |= (st.st_gid != cfg->cfg.file_gid); + } + } + if (warn_perm) + vty_out(vty, + "%% Warning: ownership and permission bits are only applied when creating\n" + "%% log files. Use system tools to change existing files.\n" + "%% FRR may also be missing necessary privileges to set these.\n"); + + if (reconf) + return reconf_dst(cfg, vty); + + return CMD_SUCCESS; +} + +/* FIFOs are for legacy /dev/log implementations; using this is very much not + * recommended since it can unexpectedly block in logging calls. Also the fd + * would need to be reopened when the process at the other end restarts. None + * of this is handled - use at your own caution. It's _HIDDEN for a purpose. + */ +ALIAS_HIDDEN(log_5424_destination_file, + log_5424_destination_fifo_cmd, + "[no] destination fifo$type PATH " + "[create$create [{owner WORD|group WORD|permissions PERMS}]" + "|no-create$nocreate] " + "[format $fmt]", + NO_STR + "Log destination setup\n" + "Log to filesystem FIFO\n" + "Path to destination\n" + "Create file if it does not exist\n" + "Set file owner\n" + "User name\n" + "Set file group\n" + "Group name\n" + "Set permissions\n" + "File permissions (octal)\n" + "Do not create file if it does not exist\n" + FORMAT_HELP) + +static int dst_unix(struct vty *vty, const char *no, const char *path, + enum zlog_5424_format fmt, enum unix_special special) +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + + if (no) + return reconf_clear_dst(cfg, vty); + + cfg->unix_special = special; + + if (cfg->cfg.dst == ZLOG_5424_DST_UNIX && cfg->filename && + !strcmp(path, cfg->filename) && cfg->cfg.active && + cfg->cfg.fmt == fmt) + return CMD_SUCCESS; + + clear_dst(cfg); + + cfg->filename = XSTRDUP(MTYPE_LOG_5424_DATA, path); + cfg->cfg.dst = ZLOG_5424_DST_UNIX; + cfg->cfg.filename = cfg->filename; + cfg->cfg.fmt = fmt; + + cfg->cfg.reconn_backoff = 25; + cfg->cfg.reconn_backoff_cur = 25; + cfg->cfg.reconn_backoff_max = 10000; + return reconf_dst(cfg, vty); +} + +DEFPY(log_5424_destination_unix, + log_5424_destination_unix_cmd, + "[no] destination unix PATH " + "[format $fmt]", + NO_STR + "Log destination setup\n" + "Log to unix socket\n" + "Unix socket path\n" + FORMAT_HELP) +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + enum zlog_5424_format fmtv = log_5424_fmt(fmt, ZLOG_FMT_5424); + + return dst_unix(vty, no, path, fmtv, SPECIAL_NONE); +} + +DEFPY(log_5424_destination_journald, + log_5424_destination_journald_cmd, + "[no] destination journald", + NO_STR + "Log destination setup\n" + "Log directly to systemd's journald\n") +{ + return dst_unix(vty, no, "/run/systemd/journal/socket", + ZLOG_FMT_JOURNALD, SPECIAL_JOURNALD); +} + +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 1200061) +#define ZLOG_FMT_DEV_LOG ZLOG_FMT_5424 +#elif defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 500000000) +#define ZLOG_FMT_DEV_LOG ZLOG_FMT_5424 +#else +#define ZLOG_FMT_DEV_LOG ZLOG_FMT_LOCAL +#endif + +DEFPY(log_5424_destination_syslog, + log_5424_destination_syslog_cmd, + "[no] destination syslog [supports-rfc5424]$supp5424", + NO_STR + "Log destination setup\n" + "Log directly to syslog\n" + "Use RFC5424 format (please refer to documentation)\n") +{ + int format = supp5424 ? ZLOG_FMT_5424 : ZLOG_FMT_DEV_LOG; + + /* unfortunately, there is no way to detect 5424 support */ + return dst_unix(vty, no, "/dev/log", format, SPECIAL_SYSLOG); +} + +/* could add something like + * "destination $proto (1-65535)$port" + * here, but there are 2 reasons not to do that: + * + * - each FRR daemon would open its own connection, there's no system level + * aggregation. That's the system's syslogd's job. It likely also + * supports directing & filtering log messages with configurable rules. + * - we're likely not going to support DTLS or TLS for more secure logging; + * adding this would require a considerable amount of additional config + * and an entire TLS library to begin with. A proper syslogd implements + * all of this, why reinvent the wheel? + */ + +DEFPY(log_5424_destination_fd, + log_5424_destination_fd_cmd, + "[no] destination |stdout$fd1|stderr$fd2>" + "[format $fmt]", + NO_STR + "Log destination setup\n" + "Log to pre-opened file descriptor\n" + "File descriptor number (must be open at startup)\n" + "Read file descriptor number from environment variable\n" + "Environment variable name\n" + "Log to standard output\n" + "Log to standard error output\n" + FORMAT_HELP) +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + bool envvar_problem = false; + enum zlog_5424_format fmtv; + + if (no) + return reconf_clear_dst(cfg, vty); + + fmtv = log_5424_fmt(fmt, ZLOG_FMT_5424); + + if (envvar) { + char *envval; + + envval = getenv(envvar); + if (!envval) + envvar_problem = true; + else { + char *errp = envval; + + fd = strtoul(envval, &errp, 0); + if (errp == envval || *errp) + envvar_problem = true; + } + + if (envvar_problem) + fd = -1; + } else if (fd1) + fd = 1; + else if (fd2) + fd = 2; + + if (cfg->cfg.dst == ZLOG_5424_DST_FD && cfg->cfg.fd == fd && + cfg->cfg.active && cfg->cfg.fmt == fmtv) + return CMD_SUCCESS; + + clear_dst(cfg); + + cfg->cfg.dst = ZLOG_5424_DST_FD; + cfg->cfg.fd = fd; + cfg->cfg.fmt = fmtv; + if (envvar) + cfg->envvar = XSTRDUP(MTYPE_LOG_5424_DATA, envvar); + + if (envvar_problem) + vty_out(vty, + "%% environment variable \"%s\" not present or invalid.\n", + envvar); + if (!frr_is_startup_fd(fd)) + vty_out(vty, + "%% file descriptor %d was not open when this process was started\n", + (int)fd); + if (envvar_problem || !frr_is_startup_fd(fd)) + vty_out(vty, + "%% configuration will be saved but has no effect currently\n"); + + return reconf_dst(cfg, vty); +} + +DEFPY(log_5424_destination_none, + log_5424_destination_none_cmd, + "[no] destination [none]", + NO_STR + "Log destination setup\n" + "Deconfigure destination\n") +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + + return reconf_clear_dst(cfg, vty); +} + +/* end of destinations */ + +DEFPY(log_5424_prio, + log_5424_prio_cmd, + "[no] priority $levelarg", + NO_STR + "Set minimum message priority to include for this target\n" + LOG_LEVEL_DESC) +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + int prio_min = log_level_match(levelarg); + + if (prio_min == cfg->cfg.prio_min) + return CMD_SUCCESS; + + cfg->cfg.prio_min = prio_min; + return reconf_meta(cfg, vty); +} + +DEFPY(log_5424_facility, + log_5424_facility_cmd, + "[no] facility $facilityarg", + NO_STR + "Set syslog facility to use\n" + LOG_FACILITY_DESC) +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + int facility = facility_match(facilityarg); + + if (cfg->cfg.facility == facility) + return CMD_SUCCESS; + + cfg->cfg.facility = facility; + return reconf_meta(cfg, vty); +} + +DEFPY(log_5424_meta, + log_5424_meta_cmd, + "[no] structured-data $option", + NO_STR + "Select structured data (key/value pairs) to include in each message\n" + "FRR source code location\n" + "FRR version\n" + "Unique message identifier (XXXXX-XXXXX)\n" + "Error category (EC numeric)\n" + "Individual formatted log message arguments\n") +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + bool val = !no, *ptr; + struct log_option *opt = log_opts; + + while (opt->name && strcmp(opt->name, option)) + opt++; + if (!opt->name) + return CMD_WARNING; + + ptr = (bool *)(((char *)&cfg->cfg) + opt->offs); + if (*ptr == val) + return CMD_SUCCESS; + + *ptr = val; + return reconf_meta(cfg, vty); +} + +DEFPY(log_5424_ts_prec, + log_5424_ts_prec_cmd, + "[no] timestamp precision (0-9)", + NO_STR + "Timestamp options\n" + "Number of sub-second digits to include\n" + "Number of sub-second digits to include\n") +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + uint32_t ts_flags = cfg->cfg.ts_flags; + + ts_flags &= ~ZLOG_TS_PREC; + if (no) + ts_flags |= DFLT_TS_FLAGS & ZLOG_TS_PREC; + else + ts_flags |= precision; + + if (ts_flags == cfg->cfg.ts_flags) + return CMD_SUCCESS; + + cfg->cfg.ts_flags = ts_flags; + return reconf_meta(cfg, vty); +} + +DEFPY(log_5424_ts_local, + log_5424_ts_local_cmd, + "[no] timestamp local-time", + NO_STR + "Timestamp options\n" + "Use local system time zone rather than UTC\n") +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + uint32_t ts_flags = cfg->cfg.ts_flags; + + ts_flags &= ~ZLOG_TS_UTC; + if (no) + ts_flags |= DFLT_TS_FLAGS & ZLOG_TS_UTC; + else + ts_flags |= (~DFLT_TS_FLAGS) & ZLOG_TS_UTC; + + if (ts_flags == cfg->cfg.ts_flags) + return CMD_SUCCESS; + + cfg->cfg.ts_flags = ts_flags; + return reconf_meta(cfg, vty); +} + +static int log_5424_node_exit(struct vty *vty) +{ + VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg); + + if ((cfg->reconf_dst || cfg->reconf_meta) && vty->type != VTY_FILE) + vty_out(vty, "%% applying changes.\n"); + + if (cfg->reconf_dst) + zlog_5424_apply_dst(&cfg->cfg); + else if (cfg->reconf_meta) + zlog_5424_apply_meta(&cfg->cfg); + + cfg->reconf_dst = cfg->reconf_meta = false; + return 1; +} + +static int log_5424_config_write(struct vty *vty) +{ + struct zlog_cfg_5424_user *cfg; + + frr_each (targets, &targets, cfg) { + const char *fmt_str = ""; + + vty_out(vty, "log extended %s\n", cfg->name); + + switch (cfg->cfg.fmt) { + case ZLOG_FMT_5424: + fmt_str = " format rfc5424"; + break; + case ZLOG_FMT_3164: + fmt_str = " format rfc3164"; + break; + case ZLOG_FMT_LOCAL: + fmt_str = " format local-syslogd"; + break; + case ZLOG_FMT_JOURNALD: + fmt_str = " format journald"; + break; + } + + switch (cfg->cfg.dst) { + case ZLOG_5424_DST_NONE: + vty_out(vty, " ! no destination configured\n"); + break; + + case ZLOG_5424_DST_FD: + if (cfg->cfg.fmt == ZLOG_FMT_5424) + fmt_str = ""; + + if (cfg->envvar) + vty_out(vty, " destination fd envvar %s%s\n", + cfg->envvar, fmt_str); + else if (cfg->cfg.fd == 1) + vty_out(vty, " destination stdout%s\n", + fmt_str); + else if (cfg->cfg.fd == 2) + vty_out(vty, " destination stderr%s\n", + fmt_str); + else + vty_out(vty, " destination fd %d%s\n", + cfg->cfg.fd, fmt_str); + break; + + case ZLOG_5424_DST_FILE: + case ZLOG_5424_DST_FIFO: + if (cfg->cfg.fmt == ZLOG_FMT_5424) + fmt_str = ""; + + vty_out(vty, " destination %s %s", + (cfg->cfg.dst == ZLOG_5424_DST_FIFO) ? "fifo" + : "file", + cfg->filename); + + if (cfg->cfg.file_nocreate) + vty_out(vty, " no-create"); + else if (cfg->file_user || cfg->file_group || + cfg->cfg.file_mode != (LOGFILE_MASK & 0666)) { + vty_out(vty, " create"); + + if (cfg->file_user) + vty_out(vty, " user %s", + cfg->file_user); + if (cfg->file_group) + vty_out(vty, " group %s", + cfg->file_group); + if (cfg->cfg.file_mode != (LOGFILE_MASK & 0666)) + vty_out(vty, " mode %04o", + cfg->cfg.file_mode); + } + vty_out(vty, "%s\n", fmt_str); + break; + + case ZLOG_5424_DST_UNIX: + switch (cfg->unix_special) { + case SPECIAL_NONE: + vty_out(vty, " destination unix %s%s\n", + cfg->filename, fmt_str); + break; + case SPECIAL_SYSLOG: + if (cfg->cfg.fmt == ZLOG_FMT_DEV_LOG) + vty_out(vty, " destination syslog\n"); + else + vty_out(vty, + " destination syslog supports-rfc5424\n"); + break; + case SPECIAL_JOURNALD: + vty_out(vty, " destination journald\n"); + break; + } + break; + } + + if (cfg->cfg.prio_min != LOG_DEBUG) + vty_out(vty, " priority %s\n", + zlog_priority_str(cfg->cfg.prio_min)); + if (cfg->cfg.facility != DFLT_FACILITY) + vty_out(vty, " facility %s\n", + facility_name(cfg->cfg.facility)); + + for (struct log_option *opt = log_opts; opt->name; opt++) { + bool *ptr = (bool *)(((char *)&cfg->cfg) + opt->offs); + + if (*ptr != opt->dflt) + vty_out(vty, " %sstructured-data %s\n", + *ptr ? "" : "no ", opt->name); + } + + if ((cfg->cfg.ts_flags ^ DFLT_TS_FLAGS) & ZLOG_TS_PREC) + vty_out(vty, " timestamp precision %u\n", + cfg->cfg.ts_flags & ZLOG_TS_PREC); + + if ((cfg->cfg.ts_flags ^ DFLT_TS_FLAGS) & ZLOG_TS_UTC) { + if (cfg->cfg.ts_flags & ZLOG_TS_UTC) + vty_out(vty, " no timestamp local-time\n"); + else + vty_out(vty, " timestamp local-time\n"); + } + + vty_out(vty, "!\n"); + } + return 0; +} + +static int log_5424_show(struct vty *vty) +{ + struct zlog_cfg_5424_user *cfg; + + frr_each (targets, &targets, cfg) { + vty_out(vty, "\nExtended log target %pSQq\n", cfg->name); + + switch (cfg->cfg.dst) { + case ZLOG_5424_DST_NONE: + vty_out(vty, + " Inactive (no destination configured)\n"); + break; + + case ZLOG_5424_DST_FD: + if (cfg->envvar) + vty_out(vty, + " logging to fd %d from environment variable %pSE\n", + cfg->cfg.fd, cfg->envvar); + else if (cfg->cfg.fd == 1) + vty_out(vty, " logging to stdout\n"); + else if (cfg->cfg.fd == 2) + vty_out(vty, " logging to stderr\n"); + else + vty_out(vty, " logging to fd %d\n", + cfg->cfg.fd); + break; + + case ZLOG_5424_DST_FILE: + case ZLOG_5424_DST_FIFO: + case ZLOG_5424_DST_UNIX: + vty_out(vty, " logging to %s: %pSE\n", + (cfg->cfg.dst == ZLOG_5424_DST_FIFO) ? "fifo" + : (cfg->cfg.dst == ZLOG_5424_DST_UNIX) + ? "unix socket" + : "file", + cfg->filename); + break; + } + + vty_out(vty, " log level: %s, facility: %s\n", + zlog_priority_str(cfg->cfg.prio_min), + facility_name(cfg->cfg.facility)); + + bool any_meta = false, first = true; + + for (struct log_option *opt = log_opts; opt->name; opt++) { + bool *ptr = (bool *)(((char *)&cfg->cfg) + opt->offs); + + any_meta |= *ptr; + } + + if (!any_meta) + continue; + + switch (cfg->cfg.fmt) { + case ZLOG_FMT_5424: + case ZLOG_FMT_JOURNALD: + vty_out(vty, " structured data: "); + + for (struct log_option *opt = log_opts; opt->name; + opt++) { + bool *ptr = (bool *)(((char *)&cfg->cfg) + + opt->offs); + + if (*ptr) { + vty_out(vty, "%s%s", first ? "" : ", ", + opt->name); + first = false; + } + } + break; + + default: + vty_out(vty, + " structured data is not supported by the selected format\n"); + break; + } + + vty_out(vty, "\n"); + + size_t lost_msgs; + int last_errno; + bool stale_errno; + struct timeval err_ts; + int64_t since; + + zlog_5424_state(&cfg->cfg, &lost_msgs, &last_errno, + &stale_errno, &err_ts); + vty_out(vty, " number of lost messages: %zu\n", lost_msgs); + + if (last_errno == 0) + since = 0; + else + since = monotime_since(&err_ts, NULL); + vty_out(vty, + " last error: %s (%lld.%06llds ago, currently %s)\n", + last_errno ? safe_strerror(last_errno) : "none", + since / 1000000LL, since % 1000000LL, + stale_errno ? "OK" : "erroring"); + } + return 0; +} + +static struct cmd_node extlog_node = { + .name = "extended", + .node = EXTLOG_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-ext-log)# ", + + .config_write = log_5424_config_write, + .node_exit = log_5424_node_exit, +}; + +static void log_5424_autocomplete(vector comps, struct cmd_token *token) +{ + struct zlog_cfg_5424_user *cfg; + + frr_each (targets, &targets, cfg) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, cfg->name)); +} + +static const struct cmd_variable_handler log_5424_var_handlers[] = { + {.tokenname = "EXTLOGNAME", .completions = log_5424_autocomplete}, + {.completions = NULL}, +}; + +void log_5424_cmd_init(void) +{ + hook_register(zlog_cli_show, log_5424_show); + + cmd_variable_handler_register(log_5424_var_handlers); + + /* CLI commands. */ + install_node(&extlog_node); + install_default(EXTLOG_NODE); + + install_element(CONFIG_NODE, &log_5424_target_cmd); + install_element(CONFIG_NODE, &no_log_5424_target_cmd); + + install_element(EXTLOG_NODE, &log_5424_destination_file_cmd); + install_element(EXTLOG_NODE, &log_5424_destination_fifo_cmd); + install_element(EXTLOG_NODE, &log_5424_destination_unix_cmd); + install_element(EXTLOG_NODE, &log_5424_destination_journald_cmd); + install_element(EXTLOG_NODE, &log_5424_destination_syslog_cmd); + install_element(EXTLOG_NODE, &log_5424_destination_fd_cmd); + + install_element(EXTLOG_NODE, &log_5424_meta_cmd); + install_element(EXTLOG_NODE, &log_5424_prio_cmd); + install_element(EXTLOG_NODE, &log_5424_facility_cmd); + install_element(EXTLOG_NODE, &log_5424_ts_prec_cmd); + install_element(EXTLOG_NODE, &log_5424_ts_local_cmd); +} + +/* hooks */ + +static int log_5424_early_init(struct thread_master *master); +static int log_5424_rotate(void); +static int log_5424_fini(void); + +__attribute__((_CONSTRUCTOR(475))) static void zlog_5424_startup_init(void) +{ + hook_register(frr_early_init, log_5424_early_init); + hook_register(zlog_rotate, log_5424_rotate); + hook_register(frr_fini, log_5424_fini); +} + +static int log_5424_early_init(struct thread_master *master) +{ + log_5424_master = master; + + return 0; +} + +static int log_5424_rotate(void) +{ + struct zlog_cfg_5424_user *cfg; + + frr_each (targets, &targets, cfg) + if (!zlog_5424_rotate(&cfg->cfg)) + zlog_err( + "log rotation on extended log target %s failed", + cfg->name); + + return 0; +} + +static int log_5424_fini(void) +{ + struct zlog_cfg_5424_user *cfg; + + while ((cfg = targets_pop(&targets))) + log_5424_free(cfg, true); + + log_5424_master = NULL; + + return 0; +} diff --git a/lib/zlog_live.c b/lib/zlog_live.c new file mode 100644 index 000000000..931aa3461 --- /dev/null +++ b/lib/zlog_live.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2019-22 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "zebra.h" + +#include "zlog_live.h" + +#include "memory.h" +#include "frrcu.h" +#include "zlog.h" +#include "printfrr.h" +#include "network.h" + +DEFINE_MTYPE_STATIC(LOG, LOG_LIVE, "log vtysh live target"); + +enum { + STATE_NORMAL = 0, + STATE_FD_DEAD, + STATE_DISOWNED, +}; + +struct zlt_live { + struct zlog_target zt; + + atomic_uint_fast32_t fd; + struct rcu_head_close head_close; + struct rcu_head head_self; + + atomic_uint_fast32_t state; + atomic_uint_fast32_t lost_msgs; +}; + +static void zlog_live(struct zlog_target *zt, struct zlog_msg *msgs[], + size_t nmsgs) +{ + struct zlt_live *zte = container_of(zt, struct zlt_live, zt); + struct zlog_live_hdr hdrs[nmsgs], *hdr = hdrs; + struct mmsghdr mmhs[nmsgs], *mmh = mmhs; + struct iovec iovs[nmsgs * 3], *iov = iovs; + struct timespec ts; + size_t i, textlen; + int fd; + uint_fast32_t state; + + fd = atomic_load_explicit(&zte->fd, memory_order_relaxed); + + if (fd < 0) + return; + + memset(mmhs, 0, sizeof(mmhs)); + memset(hdrs, 0, sizeof(hdrs)); + + for (i = 0; i < nmsgs; i++) { + const struct fmt_outpos *argpos; + size_t n_argpos, texthdrlen; + struct zlog_msg *msg = msgs[i]; + int prio = zlog_msg_prio(msg); + const struct xref_logmsg *xref; + intmax_t pid, tid; + + if (prio > zt->prio_min) + continue; + + zlog_msg_args(msg, &texthdrlen, &n_argpos, &argpos); + + mmh->msg_hdr.msg_iov = iov; + + iov->iov_base = hdr; + iov->iov_len = sizeof(*hdr); + iov++; + + if (n_argpos) { + iov->iov_base = (char *)argpos; + iov->iov_len = sizeof(*argpos) * n_argpos; + iov++; + } + + iov->iov_base = (char *)zlog_msg_text(msg, &textlen); + iov->iov_len = textlen; + iov++; + + zlog_msg_tsraw(msg, &ts); + zlog_msg_pid(msg, &pid, &tid); + xref = zlog_msg_xref(msg); + + hdr->ts_sec = ts.tv_sec; + hdr->ts_nsec = ts.tv_nsec; + hdr->pid = pid; + hdr->tid = tid; + hdr->lost_msgs = atomic_load_explicit(&zte->lost_msgs, + memory_order_relaxed); + hdr->prio = prio; + hdr->flags = 0; + hdr->textlen = textlen; + hdr->texthdrlen = texthdrlen; + hdr->n_argpos = n_argpos; + if (xref) { + memcpy(hdr->uid, xref->xref.xrefdata->uid, + sizeof(hdr->uid)); + hdr->ec = xref->ec; + } else { + memset(hdr->uid, 0, sizeof(hdr->uid)); + hdr->ec = 0; + } + hdr->hdrlen = sizeof(*hdr) + sizeof(*argpos) * n_argpos; + + mmh->msg_hdr.msg_iovlen = iov - mmh->msg_hdr.msg_iov; + mmh++; + hdr++; + } + + size_t msgtotal = mmh - mmhs; + ssize_t sent; + + for (size_t msgpos = 0; msgpos < msgtotal; msgpos += sent) { + sent = sendmmsg(fd, mmhs + msgpos, msgtotal - msgpos, 0); + + if (sent <= 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + atomic_fetch_add_explicit(&zte->lost_msgs, + msgtotal - msgpos, + memory_order_relaxed); + break; + } + if (sent <= 0) + goto out_err; + } + return; + +out_err: + fd = atomic_exchange_explicit(&zte->fd, -1, memory_order_relaxed); + if (fd < 0) + return; + + rcu_close(&zte->head_close, fd); + zlog_target_replace(zt, NULL); + + state = STATE_NORMAL; + atomic_compare_exchange_strong_explicit( + &zte->state, &state, STATE_FD_DEAD, memory_order_relaxed, + memory_order_relaxed); + if (state == STATE_DISOWNED) + rcu_free(MTYPE_LOG_LIVE, zte, head_self); +} + +static void zlog_live_sigsafe(struct zlog_target *zt, const char *text, + size_t len) +{ + struct zlt_live *zte = container_of(zt, struct zlt_live, zt); + struct zlog_live_hdr hdr[1] = {}; + struct iovec iovs[2], *iov = iovs; + struct timespec ts; + int fd; + + fd = atomic_load_explicit(&zte->fd, memory_order_relaxed); + if (fd < 0) + return; + + clock_gettime(CLOCK_REALTIME, &ts); + + hdr->ts_sec = ts.tv_sec; + hdr->ts_nsec = ts.tv_nsec; + hdr->prio = LOG_CRIT; + hdr->textlen = len; + + iov->iov_base = (char *)hdr; + iov->iov_len = sizeof(hdr); + iov++; + + iov->iov_base = (char *)text; + iov->iov_len = len; + iov++; + + writev(fd, iovs, iov - iovs); +} + +void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min, int *other_fd) +{ + int sockets[2]; + + if (cfg->target) + zlog_live_close(cfg); + + *other_fd = -1; + if (prio_min == ZLOG_DISABLED) + return; + + /* the only reason for SEQPACKET here is getting close notifications. + * otherwise if you open a bunch of vtysh connections with live logs + * and close them all, the fds will stick around until we get an error + * when trying to log something to them at some later point -- which + * eats up fds and might be *much* later for some daemons. + */ + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) < 0) { + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) { + zlog_warn("%% could not open socket pair: %m"); + return; + } + } else + /* SEQPACKET only: try to zap read direction */ + shutdown(sockets[0], SHUT_RD); + + *other_fd = sockets[1]; + zlog_live_open_fd(cfg, prio_min, sockets[0]); +} + +void zlog_live_open_fd(struct zlog_live_cfg *cfg, int prio_min, int fd) +{ + struct zlt_live *zte; + struct zlog_target *zt; + + if (cfg->target) + zlog_live_close(cfg); + + zt = zlog_target_clone(MTYPE_LOG_LIVE, NULL, sizeof(*zte)); + zte = container_of(zt, struct zlt_live, zt); + cfg->target = zte; + + set_nonblocking(fd); + zte->fd = fd; + zte->zt.prio_min = prio_min; + zte->zt.logfn = zlog_live; + zte->zt.logfn_sigsafe = zlog_live_sigsafe; + + zlog_target_replace(NULL, zt); +} + +void zlog_live_close(struct zlog_live_cfg *cfg) +{ + struct zlt_live *zte; + int fd; + + if (!cfg->target) + return; + + zte = cfg->target; + cfg->target = NULL; + + fd = atomic_exchange_explicit(&zte->fd, -1, memory_order_relaxed); + + if (fd >= 0) { + rcu_close(&zte->head_close, fd); + zlog_target_replace(&zte->zt, NULL); + } + rcu_free(MTYPE_LOG_LIVE, zte, head_self); +} + +void zlog_live_disown(struct zlog_live_cfg *cfg) +{ + struct zlt_live *zte; + uint_fast32_t state; + + if (!cfg->target) + return; + + zte = cfg->target; + cfg->target = NULL; + + state = STATE_NORMAL; + atomic_compare_exchange_strong_explicit( + &zte->state, &state, STATE_DISOWNED, memory_order_relaxed, + memory_order_relaxed); + if (state == STATE_FD_DEAD) + rcu_free(MTYPE_LOG_LIVE, zte, head_self); +} diff --git a/lib/zlog_live.h b/lib/zlog_live.h new file mode 100644 index 000000000..55e60ae67 --- /dev/null +++ b/lib/zlog_live.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019-22 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _FRR_ZLOG_LIVE_H +#define _FRR_ZLOG_LIVE_H + +#include "printfrr.h" + +struct zlog_live_hdr { + /* timestamp (CLOCK_REALTIME) */ + uint64_t ts_sec; + uint32_t ts_nsec; + + /* length of zlog_live_hdr, including variable length bits and + * possible future extensions - aka start of text + */ + uint32_t hdrlen; + + /* process & thread ID, meaning depends on OS */ + int64_t pid; + int64_t tid; + + /* number of lost messages due to best-effort non-blocking mode */ + uint32_t lost_msgs; + /* syslog priority value */ + uint32_t prio; + /* flags: currently unused */ + uint32_t flags; + /* length of message text - extra data (e.g. future key/value metadata) + * may follow after it + */ + uint32_t textlen; + /* length of "[XXXXX-XXXXX][EC 0] " header; consumer may want to skip + * over it if using the raw values below. Note that this text may be + * absent depending on "log error-category" and "log unique-id" + * settings + */ + uint32_t texthdrlen; + + /* xref unique identifier, "XXXXX-XXXXX\0" = 12 bytes */ + char uid[12]; + /* EC value */ + uint32_t ec; + + /* recorded printf formatting argument positions (variable length) */ + uint32_t n_argpos; + struct fmt_outpos argpos[0]; +}; + +struct zlt_live; + +struct zlog_live_cfg { + struct zlt_live *target; + + /* nothing else here */ +}; + +extern void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min, + int *other_fd); +extern void zlog_live_open_fd(struct zlog_live_cfg *cfg, int prio_min, int fd); + +static inline bool zlog_live_is_null(struct zlog_live_cfg *cfg) +{ + return cfg->target == NULL; +} + +extern void zlog_live_close(struct zlog_live_cfg *cfg); +extern void zlog_live_disown(struct zlog_live_cfg *cfg); + +#endif /* _FRR_ZLOG_5424_H */ diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index 3658cb16b..cd7fb7aed 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -100,7 +100,7 @@ static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb) nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl); } -static int netlink_log_recv(struct thread *t) +static void netlink_log_recv(struct thread *t) { uint8_t buf[ZNL_BUFFER_SIZE]; int fd = THREAD_FD(t); @@ -124,8 +124,6 @@ static int netlink_log_recv(struct thread *t) thread_add_read(master, netlink_log_recv, 0, netlink_log_fd, &netlink_log_thread); - - return 0; } void netlink_set_nflog_group(int nlgroup) diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c index 3823464a7..81d9bb255 100644 --- a/nhrpd/nhrp_cache.c +++ b/nhrpd/nhrp_cache.c @@ -197,16 +197,15 @@ struct nhrp_cache *nhrp_cache_get(struct interface *ifp, create ? nhrp_cache_alloc : NULL); } -static int nhrp_cache_do_free(struct thread *t) +static void nhrp_cache_do_free(struct thread *t) { struct nhrp_cache *c = THREAD_ARG(t); c->t_timeout = NULL; nhrp_cache_free(c); - return 0; } -static int nhrp_cache_do_timeout(struct thread *t) +static void nhrp_cache_do_timeout(struct thread *t) { struct nhrp_cache *c = THREAD_ARG(t); @@ -214,7 +213,6 @@ static int nhrp_cache_do_timeout(struct thread *t) if (c->cur.type != NHRP_CACHE_INVALID) nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL, NULL); - return 0; } static void nhrp_cache_update_route(struct nhrp_cache *c) @@ -392,12 +390,11 @@ static void nhrp_cache_authorize_binding(struct nhrp_reqid *r, void *arg) nhrp_cache_update_timers(c); } -static int nhrp_cache_do_auth_timeout(struct thread *t) +static void nhrp_cache_do_auth_timeout(struct thread *t) { struct nhrp_cache *c = THREAD_ARG(t); c->t_auth = NULL; nhrp_cache_authorize_binding(&c->eventid, (void *)"timeout"); - return 0; } static void nhrp_cache_newpeer_notifier(struct notifier_block *n, diff --git a/nhrpd/nhrp_event.c b/nhrpd/nhrp_event.c index 206b2cacc..e46a6d17c 100644 --- a/nhrpd/nhrp_event.c +++ b/nhrpd/nhrp_event.c @@ -31,7 +31,7 @@ struct event_manager { uint8_t ibuf_data[4 * 1024]; }; -static int evmgr_reconnect(struct thread *t); +static void evmgr_reconnect(struct thread *t); static void evmgr_connection_error(struct event_manager *evmgr) { @@ -78,7 +78,7 @@ static void evmgr_recv_message(struct event_manager *evmgr, struct zbuf *zb) } } -static int evmgr_read(struct thread *t) +static void evmgr_read(struct thread *t) { struct event_manager *evmgr = THREAD_ARG(t); struct zbuf *ibuf = &evmgr->ibuf; @@ -86,7 +86,7 @@ static int evmgr_read(struct thread *t) if (zbuf_read(ibuf, evmgr->fd, (size_t)-1) < 0) { evmgr_connection_error(evmgr); - return 0; + return; } /* Process all messages in buffer */ @@ -94,10 +94,9 @@ static int evmgr_read(struct thread *t) evmgr_recv_message(evmgr, &msg); thread_add_read(master, evmgr_read, evmgr, evmgr->fd, &evmgr->t_read); - return 0; } -static int evmgr_write(struct thread *t) +static void evmgr_write(struct thread *t) { struct event_manager *evmgr = THREAD_ARG(t); int r; @@ -109,8 +108,6 @@ static int evmgr_write(struct thread *t) } else if (r < 0) { evmgr_connection_error(evmgr); } - - return 0; } static void evmgr_hexdump(struct zbuf *zb, const uint8_t *val, size_t vallen) @@ -186,13 +183,13 @@ static void evmgr_submit(struct event_manager *evmgr, struct zbuf *obuf) &evmgr->t_write); } -static int evmgr_reconnect(struct thread *t) +static void evmgr_reconnect(struct thread *t) { struct event_manager *evmgr = THREAD_ARG(t); int fd; if (evmgr->fd >= 0 || !nhrp_event_socket_path) - return 0; + return; fd = sock_open_unix(nhrp_event_socket_path); if (fd < 0) { @@ -201,14 +198,12 @@ static int evmgr_reconnect(struct thread *t) zbufq_reset(&evmgr->obuf); thread_add_timer(master, evmgr_reconnect, evmgr, 10, &evmgr->t_reconnect); - return 0; + return; } zlog_info("Connected to Event Manager"); evmgr->fd = fd; thread_add_read(master, evmgr_read, evmgr, evmgr->fd, &evmgr->t_read); - - return 0; } static struct event_manager evmgr_connection; diff --git a/nhrpd/nhrp_multicast.c b/nhrpd/nhrp_multicast.c index d8372ae8a..89be13b60 100644 --- a/nhrpd/nhrp_multicast.c +++ b/nhrpd/nhrp_multicast.c @@ -142,7 +142,7 @@ static void netlink_mcast_log_handler(struct nlmsghdr *msg, struct zbuf *zb) } } -static int netlink_mcast_log_recv(struct thread *t) +static void netlink_mcast_log_recv(struct thread *t) { uint8_t buf[65535]; /* Max OSPF Packet size */ int fd = THREAD_FD(t); @@ -166,8 +166,6 @@ static int netlink_mcast_log_recv(struct thread *t) thread_add_read(master, netlink_mcast_log_recv, 0, netlink_mcast_log_fd, &netlink_mcast_log_thread); - - return 0; } static void netlink_mcast_log_register(int fd, int group) diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index 3733910a6..63eaf1e39 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -17,8 +17,8 @@ DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server"); DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries"); -static int nhrp_nhs_resolve(struct thread *t); -static int nhrp_reg_send_req(struct thread *t); +static void nhrp_nhs_resolve(struct thread *t); +static void nhrp_reg_send_req(struct thread *t); static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) { @@ -107,7 +107,7 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) &cie_nbma_nhs); } -static int nhrp_reg_timeout(struct thread *t) +static void nhrp_reg_timeout(struct thread *t) { struct nhrp_registration *r = THREAD_ARG(t); struct nhrp_cache *c; @@ -138,8 +138,6 @@ static int nhrp_reg_timeout(struct thread *t) r->timeout = 2; } thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register); - - return 0; } static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd) @@ -161,7 +159,7 @@ static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd) } } -static int nhrp_reg_send_req(struct thread *t) +static void nhrp_reg_send_req(struct thread *t) { struct nhrp_registration *r = THREAD_ARG(t); struct nhrp_nhs *nhs = r->nhs; @@ -180,7 +178,7 @@ static int nhrp_reg_send_req(struct thread *t) &r->peer->vc->remote.nbma); thread_add_timer(master, nhrp_reg_send_req, r, 120, &r->t_register); - return 0; + return; } thread_add_timer(master, nhrp_reg_timeout, r, r->timeout, @@ -198,7 +196,7 @@ static int nhrp_reg_send_req(struct thread *t) /* No protocol address configured for tunnel interface */ if (sockunion_family(&if_ad->addr) == AF_UNSPEC) - return 0; + return; zb = zbuf_alloc(1400); hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST, @@ -246,8 +244,6 @@ static int nhrp_reg_send_req(struct thread *t) nhrp_packet_complete(zb, hdr); nhrp_peer_send(r->peer, zb); zbuf_free(zb); - - return 0; } static void nhrp_reg_delete(struct nhrp_registration *r) @@ -320,14 +316,12 @@ static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr, nhrp_reg_delete(reg); } -static int nhrp_nhs_resolve(struct thread *t) +static void nhrp_nhs_resolve(struct thread *t) { struct nhrp_nhs *nhs = THREAD_ARG(t); resolver_resolve(&nhs->dns_resolve, AF_INET, VRF_DEFAULT, nhs->nbma_fqdn, nhrp_nhs_resolve_cb); - - return 0; } int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c index fd77533c8..2407a8d36 100644 --- a/nhrpd/nhrp_packet.c +++ b/nhrpd/nhrp_packet.c @@ -290,7 +290,7 @@ err: return -1; } -static int nhrp_packet_recvraw(struct thread *t) +static void nhrp_packet_recvraw(struct thread *t) { int fd = THREAD_FD(t), ifindex; struct zbuf *zb; @@ -304,7 +304,7 @@ static int nhrp_packet_recvraw(struct thread *t) zb = zbuf_alloc(1500); if (!zb) - return 0; + return; len = zbuf_size(zb); addrlen = sizeof(addr); @@ -332,11 +332,10 @@ static int nhrp_packet_recvraw(struct thread *t) nhrp_peer_recv(p, zb); nhrp_peer_unref(p); - return 0; + return; err: zbuf_free(zb); - return 0; } int nhrp_packet_init(void) diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 51cae44bd..67d12cbcf 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -54,7 +54,7 @@ static void nhrp_peer_check_delete(struct nhrp_peer *p) XFREE(MTYPE_NHRP_PEER, p); } -static int nhrp_peer_notify_up(struct thread *t) +static void nhrp_peer_notify_up(struct thread *t) { struct nhrp_peer *p = THREAD_ARG(t); struct nhrp_vc *vc = p->vc; @@ -68,8 +68,6 @@ static int nhrp_peer_notify_up(struct thread *t) notifier_call(&p->notifier_list, NOTIFY_PEER_UP); nhrp_peer_unref(p); } - - return 0; } static void __nhrp_peer_check(struct nhrp_peer *p) @@ -258,7 +256,7 @@ void nhrp_peer_unref(struct nhrp_peer *p) } } -static int nhrp_peer_request_timeout(struct thread *t) +static void nhrp_peer_request_timeout(struct thread *t) { struct nhrp_peer *p = THREAD_ARG(t); struct nhrp_vc *vc = p->vc; @@ -267,7 +265,7 @@ static int nhrp_peer_request_timeout(struct thread *t) if (p->online) - return 0; + return; if (nifp->ipsec_fallback_profile && !p->prio && !p->fallback_requested) { @@ -279,11 +277,9 @@ static int nhrp_peer_request_timeout(struct thread *t) } else { p->requested = p->fallback_requested = 0; } - - return 0; } -static int nhrp_peer_defer_vici_request(struct thread *t) +static void nhrp_peer_defer_vici_request(struct thread *t) { struct nhrp_peer *p = THREAD_ARG(t); struct nhrp_vc *vc = p->vc; @@ -304,7 +300,6 @@ static int nhrp_peer_defer_vici_request(struct thread *t) (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30, &p->t_fallback); } - return 0; } int nhrp_peer_check(struct nhrp_peer *p, int establish) diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index 244273cd5..71b6dd870 100644 --- a/nhrpd/nhrp_shortcut.c +++ b/nhrpd/nhrp_shortcut.c @@ -22,7 +22,7 @@ DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut"); static struct route_table *shortcut_rib[AFI_MAX]; -static int nhrp_shortcut_do_purge(struct thread *t); +static void nhrp_shortcut_do_purge(struct thread *t); static void nhrp_shortcut_delete(struct nhrp_shortcut *s); static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s); @@ -35,7 +35,7 @@ static void nhrp_shortcut_check_use(struct nhrp_shortcut *s) } } -static int nhrp_shortcut_do_expire(struct thread *t) +static void nhrp_shortcut_do_expire(struct thread *t) { struct nhrp_shortcut *s = THREAD_ARG(t); @@ -43,8 +43,6 @@ static int nhrp_shortcut_do_expire(struct thread *t) &s->t_timer); s->expiring = 1; nhrp_shortcut_check_use(s); - - return 0; } static void nhrp_shortcut_cache_notify(struct notifier_block *n, @@ -166,12 +164,11 @@ static void nhrp_shortcut_delete(struct nhrp_shortcut *s) } } -static int nhrp_shortcut_do_purge(struct thread *t) +static void nhrp_shortcut_do_purge(struct thread *t) { struct nhrp_shortcut *s = THREAD_ARG(t); s->t_timer = NULL; nhrp_shortcut_delete(s); - return 0; } static struct nhrp_shortcut *nhrp_shortcut_get(struct prefix *p) diff --git a/nhrpd/vici.c b/nhrpd/vici.c index 8fce82866..56adde406 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -60,7 +60,7 @@ struct vici_message_ctx { int nsections; }; -static int vici_reconnect(struct thread *t); +static void vici_reconnect(struct thread *t); static void vici_submit_request(struct vici_conn *vici, const char *name, ...); static void vici_zbuf_puts(struct zbuf *obuf, const char *str) @@ -355,7 +355,7 @@ static void vici_recv_message(struct vici_conn *vici, struct zbuf *msg) } } -static int vici_read(struct thread *t) +static void vici_read(struct thread *t) { struct vici_conn *vici = THREAD_ARG(t); struct zbuf *ibuf = &vici->ibuf; @@ -363,7 +363,7 @@ static int vici_read(struct thread *t) if (zbuf_read(ibuf, vici->fd, (size_t)-1) < 0) { vici_connection_error(vici); - return 0; + return; } /* Process all messages in buffer */ @@ -383,10 +383,9 @@ static int vici_read(struct thread *t) } while (1); thread_add_read(master, vici_read, vici, vici->fd, &vici->t_read); - return 0; } -static int vici_write(struct thread *t) +static void vici_write(struct thread *t) { struct vici_conn *vici = THREAD_ARG(t); int r; @@ -398,8 +397,6 @@ static int vici_write(struct thread *t) } else if (r < 0) { vici_connection_error(vici); } - - return 0; } static void vici_submit(struct vici_conn *vici, struct zbuf *obuf) @@ -501,14 +498,14 @@ static char *vici_get_charon_filepath(void) return buff; } -static int vici_reconnect(struct thread *t) +static void vici_reconnect(struct thread *t) { struct vici_conn *vici = THREAD_ARG(t); int fd; char *file_path; if (vici->fd >= 0) - return 0; + return; fd = sock_open_unix(VICI_SOCKET); if (fd < 0) { @@ -522,7 +519,7 @@ static int vici_reconnect(struct thread *t) strerror(errno)); thread_add_timer(master, vici_reconnect, vici, 2, &vici->t_reconnect); - return 0; + return; } debugf(NHRP_DEBUG_COMMON, "VICI: Connected"); @@ -537,8 +534,6 @@ static int vici_reconnect(struct thread *t) vici_register_event(vici, "child-state-destroying"); vici_register_event(vici, "list-sa"); vici_submit_request(vici, "list-sas", VICI_END); - - return 0; } static struct vici_conn vici_connection; diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index a612f7d1b..a0cb45579 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -455,6 +455,11 @@ void ospf6_area_show(struct vty *vty, struct ospf6_area *oa, json_object_int_add(json_area, "numberOfAreaScopedLsa", oa->lsdb->count); + json_object_object_add( + json_area, "lsaStatistics", + JSON_OBJECT_NEW_ARRAY(json_object_new_int, + oa->lsdb->stats, + OSPF6_LSTYPE_SIZE)); /* Interfaces Attached */ array_interfaces = json_object_new_array(); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 203ae14f2..40afd716c 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -197,7 +197,7 @@ struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route, return lsa; } -int ospf6_orig_as_external_lsa(struct thread *thread) +void ospf6_orig_as_external_lsa(struct thread *thread) { struct ospf6_interface *oi; struct ospf6_lsa *lsa; @@ -206,9 +206,9 @@ int ospf6_orig_as_external_lsa(struct thread *thread) oi = (struct ospf6_interface *)THREAD_ARG(thread); if (oi->state == OSPF6_INTERFACE_DOWN) - return 0; + return; if (IS_AREA_NSSA(oi->area) || IS_AREA_STUB(oi->area)) - return 0; + return; type = htons(OSPF6_LSTYPE_AS_EXTERNAL); adv_router = oi->area->ospf6->router_id; @@ -222,8 +222,6 @@ int ospf6_orig_as_external_lsa(struct thread *thread) ospf6_flood_interface(NULL, lsa, oi); } - - return 0; } static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa) @@ -1084,7 +1082,7 @@ static void ospf6_asbr_routemap_unset(struct ospf6_redist *red) ROUTEMAP(red) = NULL; } -static int ospf6_asbr_routemap_update_timer(struct thread *thread) +static void ospf6_asbr_routemap_update_timer(struct thread *thread) { struct ospf6 *ospf6 = THREAD_ARG(thread); struct ospf6_redist *red; @@ -1116,8 +1114,6 @@ static int ospf6_asbr_routemap_update_timer(struct thread *thread) UNSET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED); } - - return 0; } void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6, @@ -2874,7 +2870,7 @@ ospf6_originate_summary_lsa(struct ospf6 *ospf6, if (IS_OSPF6_DEBUG_AGGR) zlog_debug("%s: Aggr LSA ID: %d flags %x.", __func__, aggr->id, aggr->aggrflags); - /* Dont originate external LSA, + /* Don't originate external LSA, * If it is configured not to advertise. */ if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) { @@ -3248,11 +3244,11 @@ static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6, /* Handling the case where the external route prefix * and aggegate prefix is same - * If same dont flush the originated external LSA. + * If same don't flush the originated external LSA. */ if (prefix_same(&aggr->p, &rt->prefix)) { if (IS_OSPF6_DEBUG_AGGR) - zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so dont flush.", + zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so don't flush.", __func__, &rt->prefix); @@ -3331,7 +3327,7 @@ ospf6_handle_external_aggr_add(struct ospf6 *ospf6) } } -static int ospf6_asbr_summary_process(struct thread *thread) +static void ospf6_asbr_summary_process(struct thread *thread) { struct ospf6 *ospf6 = THREAD_ARG(thread); int operation = 0; @@ -3354,8 +3350,6 @@ static int ospf6_asbr_summary_process(struct thread *thread) default: break; } - - return OSPF6_SUCCESS; } static void @@ -3623,7 +3617,7 @@ void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6, /* Handling the case where the * external route prefix * and aggegate prefix is same - * If same dont flush the + * If same don't flush the * originated * external LSA. */ diff --git a/ospf6d/ospf6_auth_trailer.c b/ospf6d/ospf6_auth_trailer.c new file mode 100644 index 000000000..1095473f4 --- /dev/null +++ b/ospf6d/ospf6_auth_trailer.c @@ -0,0 +1,1000 @@ +/* + * Copyright (C) 2021 Abhinay Ramesh + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "zebra.h" +#include "config.h" +#include "memory.h" +#include "ospf6d.h" +#include "vty.h" +#include "command.h" +#include "md5.h" +#include "sha256.h" +#include "lib/zlog.h" +#include "ospf6_message.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_proto.h" +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_auth_trailer.h" +#include "ospf6_route.h" +#include "ospf6_zebra.h" +#include "lib/keychain.h" + +unsigned char conf_debug_ospf6_auth[2]; +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AUTH_HASH_XOR, "OSPF6 auth hash xor"); + +/*Apad is the hexadecimal value 0x878FE1F3. */ +const uint8_t ospf6_hash_apad_max[KEYCHAIN_MAX_HASH_SIZE] = { + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, + 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, + 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, + 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, + 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, +}; + +const uint8_t ospf6_hash_ipad_max[KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE] = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +}; + +const uint8_t ospf6_hash_opad_max[KEYCHAIN_ALGO_MAX_INTERNAL_BLK_SIZE] = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, +}; + +void ospf6_auth_hdr_dump_send(struct ospf6_header *ospfh, uint16_t length) +{ + struct ospf6_auth_hdr *ospf6_at_hdr; + uint16_t at_len, oh_len, at_hdr_len, hash_len; + unsigned char temp[KEYCHAIN_MAX_HASH_SIZE + 1]; + + oh_len = htons(ospfh->length); + at_len = length - oh_len; + if (at_len > 0) { + ospf6_at_hdr = (struct ospf6_auth_hdr *) + ((uint8_t *)ospfh + oh_len); + at_hdr_len = htons(ospf6_at_hdr->length); + hash_len = at_hdr_len - OSPF6_AUTH_HDR_MIN_SIZE; + memcpy(temp, ospf6_at_hdr->data, hash_len); + temp[hash_len] = '\0'; + zlog_debug("OSPF6 Authentication Trailer"); + zlog_debug(" Type %d", htons(ospf6_at_hdr->type)); + zlog_debug(" Length %d", at_hdr_len); + zlog_debug(" Reserved %d", ospf6_at_hdr->reserved); + zlog_debug(" SA ID %d", htons(ospf6_at_hdr->id)); + zlog_debug(" seqnum high 0x%08x", + htonl(ospf6_at_hdr->seqnum_h)); + zlog_debug(" seqnum high 0x%08x", + htonl(ospf6_at_hdr->seqnum_l)); + zlog_debug(" Data %s", temp); + } +} + +void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length, + unsigned int lls_len) +{ + struct ospf6_auth_hdr *ospf6_at_hdr; + uint16_t at_len, oh_len, at_hdr_len, hash_len; + unsigned char temp[KEYCHAIN_MAX_HASH_SIZE + 1]; + + oh_len = ntohs(ospfh->length); + at_len = length - (oh_len + lls_len); + if (at_len > 0) { + ospf6_at_hdr = + (struct ospf6_auth_hdr *)((uint8_t *)ospfh + oh_len); + at_hdr_len = ntohs(ospf6_at_hdr->length); + hash_len = at_hdr_len - OSPF6_AUTH_HDR_MIN_SIZE; + memcpy(temp, ospf6_at_hdr->data, hash_len); + temp[hash_len] = '\0'; + zlog_debug("OSPF6 Authentication Trailer"); + zlog_debug(" Type %d", ntohs(ospf6_at_hdr->type)); + zlog_debug(" Length %d", at_hdr_len); + zlog_debug(" Reserved %d", ospf6_at_hdr->reserved); + zlog_debug(" SA ID %d", ntohs(ospf6_at_hdr->id)); + zlog_debug(" seqnum high 0x%08x", + ntohl(ospf6_at_hdr->seqnum_h)); + zlog_debug(" seqnum high 0x%08x", + ntohl(ospf6_at_hdr->seqnum_l)); + zlog_debug(" Data %s", temp); + } +} + +unsigned char *ospf6_hash_message_xor(unsigned char *mes1, + unsigned char *mes2, + uint32_t len) +{ + unsigned char *result; + uint32_t i; + + result = XCALLOC(MTYPE_OSPF6_AUTH_HASH_XOR, len); + if (!result) + return NULL; + + for (i = 0; i < len; i++) + result[i] = mes1[i] ^ mes2[i]; + + return result; +} + +static void md5_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ +#ifdef CRYPTO_OPENSSL + unsigned int size = KEYCHAIN_MD5_HASH_SIZE; + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL + MD5_CTX ctx; +#endif + +#ifdef CRYPTO_OPENSSL + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_md5()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + MD5Update(&ctx, mes, len); + MD5Final(digest, &ctx); +#endif +} + +static void sha256_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ +#ifdef CRYPTO_OPENSSL + unsigned int size = KEYCHAIN_HMAC_SHA256_HASH_SIZE; + EVP_MD_CTX *ctx; +#elif CRYPTO_INTERNAL + SHA256_CTX ctx; +#endif + +#ifdef CRYPTO_OPENSSL + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_sha256()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +#elif CRYPTO_INTERNAL + memset(&ctx, 0, sizeof(ctx)); + SHA256_Init(&ctx); + SHA256_Update(&ctx, mes, len); + SHA256_Final(digest, &ctx); +#endif +} + +#ifdef CRYPTO_OPENSSL +static void sha1_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ + EVP_MD_CTX *ctx; + unsigned int size = KEYCHAIN_HMAC_SHA1_HASH_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_sha1()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +} + +static void sha384_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ + EVP_MD_CTX *ctx; + unsigned int size = KEYCHAIN_HMAC_SHA384_HASH_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_sha384()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +} + +static void sha512_digest(unsigned char *mes, uint32_t len, + unsigned char *digest) +{ + EVP_MD_CTX *ctx; + unsigned int size = KEYCHAIN_HMAC_SHA512_HASH_SIZE; + + ctx = EVP_MD_CTX_new(); + EVP_DigestInit(ctx, EVP_sha512()); + EVP_DigestUpdate(ctx, mes, len); + EVP_DigestFinal(ctx, digest, &size); + EVP_MD_CTX_free(ctx); +} +#endif /* CRYPTO_OPENSSL */ + +static void ospf6_hash_hmac_sha_digest(enum keychain_hash_algo key, + unsigned char *mes, uint32_t len, + unsigned char *digest) +{ + if ((key < KEYCHAIN_ALGO_NULL) || (key > KEYCHAIN_ALGO_MAX)) + return; + + switch (key) { + case KEYCHAIN_ALGO_MD5: + md5_digest(mes, len, digest); + break; + case KEYCHAIN_ALGO_HMAC_SHA1: +#ifdef CRYPTO_OPENSSL + sha1_digest(mes, len, digest); +#endif + break; + case KEYCHAIN_ALGO_HMAC_SHA256: + sha256_digest(mes, len, digest); + break; + case KEYCHAIN_ALGO_HMAC_SHA384: +#ifdef CRYPTO_OPENSSL + sha384_digest(mes, len, digest); +#endif + break; + case KEYCHAIN_ALGO_HMAC_SHA512: +#ifdef CRYPTO_OPENSSL + sha512_digest(mes, len, digest); +#endif + break; + case KEYCHAIN_ALGO_NULL: + case KEYCHAIN_ALGO_MAX: + default: + /* no action */ + break; + } +} + +uint16_t ospf6_auth_len_get(struct ospf6_interface *oi) +{ + uint16_t at_len = 0; + char *keychain_name = NULL; + struct keychain *keychain = NULL; + struct key *key = NULL; + + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { + if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) { + at_len = OSPF6_AUTH_HDR_MIN_SIZE + + keychain_get_hash_len(oi->at_data.hash_algo); + } else { + keychain_name = oi->at_data.keychain; + keychain = keychain_lookup(keychain_name); + if (keychain) { + key = key_lookup_for_send(keychain); + if (key && key->string + && key->hash_algo != KEYCHAIN_ALGO_NULL) { + at_len = OSPF6_AUTH_HDR_MIN_SIZE + + keychain_get_hash_len( + key->hash_algo); + } + } + } + } else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + at_len = OSPF6_AUTH_HDR_MIN_SIZE + + keychain_get_hash_len(oi->at_data.hash_algo); + } + + return at_len; +} + +int ospf6_auth_validate_pkt(struct ospf6_interface *oi, unsigned int *pkt_len, + struct ospf6_header *oh, unsigned int *at_len, + unsigned int *lls_block_len) +{ + struct ospf6_hello *hello = NULL; + struct ospf6_dbdesc *dbdesc = NULL; + struct ospf6_neighbor *on = NULL; + struct ospf6_auth_hdr ospf6_auth_info; + uint16_t hdr_len = 0; + uint32_t oh_seqnum_h = 0; + uint32_t oh_seqnum_l = 0; + bool auth_present = false; + bool lls_present = false; + struct ospf6_lls_hdr *lls_hdr = NULL; + + on = ospf6_neighbor_lookup(oh->router_id, oi); + hdr_len = ntohs(oh->length); + if (*pkt_len < hdr_len) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] Received incomplete %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } else if (*pkt_len == hdr_len) { + if (oi->at_data.flags != 0) + return OSPF6_AUTH_VALIDATE_FAILURE; + /* No auth info to be considered. + */ + return OSPF6_AUTH_PROCESS_NORMAL; + } + + switch (oh->type) { + case OSPF6_MESSAGE_TYPE_HELLO: + hello = (struct ospf6_hello *)((uint8_t *)oh + + sizeof(struct ospf6_header)); + if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_L)) + lls_present = true; + + if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT)) + auth_present = true; + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + dbdesc = (struct ospf6_dbdesc *)((uint8_t *)oh + + sizeof(struct ospf6_header)); + if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_L)) + lls_present = true; + + if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT)) + auth_present = true; + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + case OSPF6_MESSAGE_TYPE_LSUPDATE: + case OSPF6_MESSAGE_TYPE_LSACK: + if (on) { + lls_present = on->lls_present; + auth_present = on->auth_present; + } + break; + default: + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong packet type %d", + oi->interface->name, oh->type); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + if ((oh->type == OSPF6_MESSAGE_TYPE_HELLO) + || (oh->type == OSPF6_MESSAGE_TYPE_DBDESC)) { + if (on) { + on->auth_present = auth_present; + on->lls_present = lls_present; + } + } + + if ((!auth_present && (oi->at_data.flags != 0)) + || (auth_present && (oi->at_data.flags == 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Auth option miss-match in %s pkt", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + if (lls_present) { + lls_hdr = (struct ospf6_lls_hdr *)(oh + hdr_len); + *lls_block_len = ntohs(lls_hdr->length) * 4; + } + + if (*lls_block_len > (*pkt_len - hdr_len)) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong lls data in %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + memset(&ospf6_auth_info, 0, sizeof(struct ospf6_auth_hdr)); + if ((*pkt_len - hdr_len - (*lls_block_len)) > sizeof(ospf6_auth_info)) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong auth data in %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + memcpy(&ospf6_auth_info, ((uint8_t *)oh + hdr_len + (*lls_block_len)), + (*pkt_len - hdr_len - (*lls_block_len))); + if (ntohs(ospf6_auth_info.length) > OSPF6_AUTH_HDR_FULL) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong auth header length in %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + /* after authentication header validation is done + * reduce the auth hdr size from the packet length + */ + *at_len = ntohs(ospf6_auth_info.length); + *pkt_len = (*pkt_len) - (*at_len) - (*lls_block_len); + + if (on) { + oh_seqnum_h = ntohl(ospf6_auth_info.seqnum_h); + oh_seqnum_l = ntohl(ospf6_auth_info.seqnum_l); + if ((oh_seqnum_h >= on->seqnum_h[oh->type]) + && (oh_seqnum_l > on->seqnum_l[oh->type])) { + /* valid sequence number received */ + on->seqnum_h[oh->type] = oh_seqnum_h; + on->seqnum_l[oh->type] = oh_seqnum_l; + } else { + if (IS_OSPF6_DEBUG_AUTH_RX) { + zlog_err( + "RECV[%s] : Nbr(%s) Auth Sequence number mismatch in %s ", + oi->interface->name, on->name, + ospf6_message_type(oh->type)); + zlog_err( + "nbr_seq_l %u, nbr_seq_h %u, hdr_seq_l %u, hdr_seq_h %u", + on->seqnum_l[oh->type], + on->seqnum_h[oh->type], oh_seqnum_l, + oh_seqnum_h); + } + + return OSPF6_AUTH_VALIDATE_FAILURE; + } + } + + return OSPF6_AUTH_VALIDATE_SUCCESS; +} + +/* Starting point of packet process function. */ +int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, + struct in6_addr *src, unsigned int lls_block_len) +{ + uint32_t hash_len = KEYCHAIN_MAX_HASH_SIZE; + unsigned char apad[hash_len]; + unsigned char temp_hash[hash_len]; + struct ospf6_auth_hdr *ospf6_auth; + uint32_t ipv6_addr_size = sizeof(struct in6_addr); + struct keychain *keychain = NULL; + struct key *key = NULL; + char *auth_str = NULL; + uint16_t auth_len = 0; + uint8_t hash_algo = 0; + uint16_t oh_len = ntohs(oh->length); + int ret = 0; + + if (oi->at_data.flags == 0) + return OSPF6_AUTH_PROCESS_NORMAL; + + ospf6_auth = (struct ospf6_auth_hdr *)((uint8_t *)oh + + (oh_len + lls_block_len)); + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { + keychain = keychain_lookup(oi->at_data.keychain); + if (!keychain) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err( + "RECV[%s]: Keychain doesn't exist for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + key = key_lookup_for_accept(keychain, ntohs(ospf6_auth->id)); + if (!key) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s]: Auth, Invalid SA for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + if (key && key->string + && key->hash_algo != KEYCHAIN_ALGO_NULL) { + auth_str = key->string; + hash_algo = key->hash_algo; + } else { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err( + "RECV[%s]: Incomplete keychain config for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + } else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + auth_str = oi->at_data.auth_key; + hash_algo = oi->at_data.hash_algo; + } + + if (!auth_str) + return OSPF6_AUTH_VALIDATE_FAILURE; + + hash_len = keychain_get_hash_len(hash_algo); + memset(apad, 0, sizeof(apad)); + memset(temp_hash, 0, sizeof(temp_hash)); + + /* start digest verification */ + memcpy(apad, src, ipv6_addr_size); + memcpy(apad + ipv6_addr_size, ospf6_hash_apad_max, + (hash_len - ipv6_addr_size)); + + auth_len = ntohs(ospf6_auth->length); + + memcpy(temp_hash, ospf6_auth->data, hash_len); + memcpy(ospf6_auth->data, apad, hash_len); + + ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, + (oh_len + auth_len + lls_block_len), + hash_algo); + +#ifdef CRYPTO_OPENSSL + ret = CRYPTO_memcmp(temp_hash, ospf6_auth->data, hash_len); +#else + ret = memcmp(temp_hash, ospf6_auth->data, hash_len); +#endif + if (ret == 0) + return OSPF6_AUTH_VALIDATE_SUCCESS; + + return OSPF6_AUTH_VALIDATE_FAILURE; +} + +void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, + struct ospf6_header *oh, uint16_t auth_len, + uint32_t pkt_len) +{ + struct ospf6_auth_hdr *ospf6_auth; + char *keychain_name = NULL; + struct keychain *keychain = NULL; + struct key *key = NULL; + char *auth_str = NULL; + uint16_t key_id = 0; + enum keychain_hash_algo hash_algo = KEYCHAIN_ALGO_NULL; + uint32_t hash_len = KEYCHAIN_MAX_HASH_SIZE; + unsigned char apad[hash_len]; + int ipv6_addr_size = sizeof(struct in6_addr); + struct ospf6 *ospf6 = NULL; + + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { + if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) { + auth_str = oi->at_data.auth_key; + hash_algo = oi->at_data.hash_algo; + key_id = oi->at_data.key_id; + } else { + keychain_name = oi->at_data.keychain; + keychain = keychain_lookup(keychain_name); + if (keychain) { + key = key_lookup_for_send(keychain); + if (key && key->string + && key->hash_algo != KEYCHAIN_ALGO_NULL) { + auth_str = key->string; + hash_algo = key->hash_algo; + key_id = key->index; + } + } + } + } else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + auth_str = oi->at_data.auth_key; + hash_algo = oi->at_data.hash_algo; + key_id = oi->at_data.key_id; + } else { + if (IS_OSPF6_DEBUG_AUTH_TX) + zlog_warn("SEND[%s]: Authentication not configured for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return; + } + + if (!auth_str) { + if (IS_OSPF6_DEBUG_AUTH_TX) + zlog_warn("SEND[%s]: Authentication key is not configured for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return; + } + + hash_len = keychain_get_hash_len(hash_algo); + if (oi->area && oi->area->ospf6) + ospf6 = oi->area->ospf6; + else + return; + + ospf6->seqnum_l++; + if (ospf6->seqnum_l == 0xFFFFFFFF) { + ospf6->seqnum_h++; + ospf6->seqnum_l = 0; + ospf6_auth_seqno_nvm_update(ospf6); + } + + /* Key must be reset. which is not handled as of now. */ + if ((ospf6->seqnum_l == 0xFFFFFFFF) + && (ospf6->seqnum_h == 0xFFFFFFFF)) { + ospf6->seqnum_l = 0; + ospf6->seqnum_h = 0; + zlog_err( + "Both Higher and Lower sequence number has wrapped. Need to reset the key"); + } + + memset(apad, 0, sizeof(apad)); + + if (src) + memcpy(apad, src, ipv6_addr_size); + + memcpy(apad + ipv6_addr_size, ospf6_hash_apad_max, + (hash_len - ipv6_addr_size)); + + ospf6_auth = + (struct ospf6_auth_hdr *)((uint8_t *)oh + ntohs(oh->length)); + ospf6_auth->type = htons(OSPF6_AUTHENTICATION_CRYPTOGRAPHIC); + ospf6_auth->length = htons(auth_len); + ospf6_auth->reserved = 0; + ospf6_auth->id = htons(key_id); + ospf6_auth->seqnum_h = htonl(ospf6->seqnum_h); + ospf6_auth->seqnum_l = htonl(ospf6->seqnum_l); + memcpy(ospf6_auth->data, apad, hash_len); + + ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, pkt_len, + hash_algo); + + /* There is a optimisation that is done to ensure that + * for every packet flow keychain lib API are called + * only once and the result are stored in oi->at_data. + * So, After processing the flow it is reset back here. + */ + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) { + oi->at_data.hash_algo = KEYCHAIN_ALGO_NULL; + if (oi->at_data.auth_key) { + XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, + oi->at_data.auth_key); + oi->at_data.auth_key = NULL; + } + + oi->at_data.key_id = 0; + UNSET_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID); + } +} + +void ospf6_auth_update_digest(struct ospf6_interface *oi, + struct ospf6_header *oh, + struct ospf6_auth_hdr *ospf6_auth, char *auth_str, + uint32_t pkt_len, enum keychain_hash_algo algo) +{ + static const uint16_t cpid = 1; + uint32_t hash_len = keychain_get_hash_len(algo); + uint32_t block_s = keychain_get_block_size(algo); + uint32_t k_len = strlen(auth_str); + uint32_t ks_len = strlen(auth_str) + sizeof(cpid); + unsigned char ipad[block_s]; + unsigned char opad[block_s]; + unsigned char ko[block_s], ks[ks_len], tmp[hash_len]; + unsigned char *first = NULL; + unsigned char *second = NULL; + unsigned char first_mes[block_s + pkt_len]; + unsigned char second_mes[block_s + pkt_len]; + unsigned char first_hash[hash_len]; + unsigned char second_hash[hash_len]; + + memset(ko, 0, sizeof(ko)); + memcpy(ks, auth_str, k_len); + memcpy(ks + k_len, &cpid, sizeof(cpid)); + if (ks_len > hash_len) { + ospf6_hash_hmac_sha_digest(algo, ks, ks_len, tmp); + memcpy(ko, tmp, hash_len); + } else + memcpy(ko, ks, ks_len); + + memcpy(ipad, ospf6_hash_ipad_max, block_s); + memcpy(opad, ospf6_hash_opad_max, block_s); + + first = ospf6_hash_message_xor((unsigned char *)&ipad, ko, block_s); + second = ospf6_hash_message_xor((unsigned char *)&opad, ko, block_s); + + memcpy(first_mes, first, block_s); + memcpy(first_mes + block_s, oh, pkt_len); + + ospf6_hash_hmac_sha_digest(algo, first_mes, (block_s + pkt_len), + first_hash); + + memcpy(second_mes, second, block_s); + memcpy(second_mes + block_s, first_hash, hash_len); + + ospf6_hash_hmac_sha_digest(algo, second_mes, (block_s + hash_len), + second_hash); + + memcpy(ospf6_auth->data, second_hash, hash_len); + XFREE(MTYPE_OSPF6_AUTH_HASH_XOR, first); + XFREE(MTYPE_OSPF6_AUTH_HASH_XOR, second); +} + +DEFUN (debug_ospf6_auth, + debug_ospf6_auth_cmd, + "debug ospf6 authentication []", + DEBUG_STR + OSPF6_STR + "debug OSPF6 authentication\n" + "debug authentication tx\n" + "debug authentication rx\n") +{ + int auth_opt_idx = 3; + + if (argc == 4) { + if (!strncmp(argv[auth_opt_idx]->arg, "t", 1)) + OSPF6_DEBUG_AUTH_TX_ON(); + else if (!strncmp(argv[auth_opt_idx]->arg, "r", 1)) + OSPF6_DEBUG_AUTH_RX_ON(); + } else { + OSPF6_DEBUG_AUTH_TX_ON(); + OSPF6_DEBUG_AUTH_RX_ON(); + } + + return CMD_SUCCESS; +} + +DEFUN (no_debug_ospf6_auth, + no_debug_ospf6_auth_cmd, + "no debug ospf6 authentication []", + NO_STR + DEBUG_STR + OSPF6_STR + "debug OSPF6 authentication\n" + "debug authentication tx\n" + "debug authentication rx\n") +{ + int auth_opt_idx = 3; + + if (argc == 5) { + if (!strncmp(argv[auth_opt_idx]->arg, "t", 1)) + OSPF6_DEBUG_AUTH_TX_OFF(); + else if (!strncmp(argv[auth_opt_idx]->arg, "r", 1)) + OSPF6_DEBUG_AUTH_RX_OFF(); + } else { + OSPF6_DEBUG_AUTH_TX_OFF(); + OSPF6_DEBUG_AUTH_RX_OFF(); + } + + return CMD_SUCCESS; +} + +int config_write_ospf6_debug_auth(struct vty *vty) +{ + if (IS_OSPF6_DEBUG_AUTH_TX) + vty_out(vty, "debug ospf6 authentication tx\n"); + if (IS_OSPF6_DEBUG_AUTH_RX) + vty_out(vty, "debug ospf6 authentication rx\n"); + return 0; +} + +void install_element_ospf6_debug_auth(void) +{ + install_element(ENABLE_NODE, &debug_ospf6_auth_cmd); + install_element(ENABLE_NODE, &no_debug_ospf6_auth_cmd); + install_element(CONFIG_NODE, &debug_ospf6_auth_cmd); + install_element(CONFIG_NODE, &no_debug_ospf6_auth_cmd); +} + +/* Clear the specified interface structure */ +static void ospf6_intf_auth_clear(struct vty *vty, struct interface *ifp) +{ + struct ospf6_interface *oi; + + if (!if_is_operative(ifp)) + return; + + if (ifp->info == NULL) + return; + + oi = (struct ospf6_interface *)ifp->info; + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_debug( + "Interface %s: clear authentication rx/tx drop counters", + ifp->name); + + /* Reset the interface rx/tx drop counters */ + oi->at_data.tx_drop = 0; + oi->at_data.rx_drop = 0; +} + +/* Clear interface */ +DEFUN(clear_ipv6_ospf6_intf_auth, clear_ipv6_ospf6_intf_auth_cmd, + "clear ipv6 ospf6 [vrf VRF] auth-counters interface [IFNAME]", + CLEAR_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + "authentication rx/tx drop counters\n" INTERFACE_STR IFNAME_STR) +{ + int idx_ifname = 0; + int idx_vrf = 0; + struct interface *ifp; + struct listnode *node; + struct ospf6 *ospf6 = NULL; + char *vrf_name = NULL; + vrf_id_t vrf_id = VRF_DEFAULT; + struct vrf *vrf = NULL; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) + vrf_name = argv[idx_vrf + 1]->arg; + + if (vrf_name && strmatch(vrf_name, VRF_DEFAULT_NAME)) + vrf_name = NULL; + + if (vrf_name) { + vrf = vrf_lookup_by_name(vrf_name); + if (vrf) + vrf_id = vrf->vrf_id; + } + + if (!argv_find(argv, argc, "IFNAME", &idx_ifname)) { + /* Clear all the ospfv3 interfaces auth data. */ + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (vrf_id != ospf6->vrf_id) + continue; + + if (!vrf) + vrf = vrf_lookup_by_id(ospf6->vrf_id); + FOR_ALL_INTERFACES (vrf, ifp) + ospf6_intf_auth_clear(vty, ifp); + } + } else { + /* Interface name is specified. */ + ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id); + if (ifp == NULL) + vty_out(vty, "No such interface name\n"); + else + ospf6_intf_auth_clear(vty, ifp); + } + + return CMD_SUCCESS; +} + +void install_element_ospf6_clear_intf_auth(void) +{ + install_element(ENABLE_NODE, &clear_ipv6_ospf6_intf_auth_cmd); +} + +enum ospf6_auth_err ospf6_auth_nvm_file_exist(void) +{ + struct stat buffer; + int exist; + + exist = stat(OSPF6_AUTH_SEQ_NUM_FILE, &buffer); + if (exist == 0) + return OSPF6_AUTH_FILE_EXIST; + else + return OSPF6_AUTH_FILE_DO_NOT_EXIST; +} + +/* + * Record in non-volatile memory the given ospf6 process, + * authentication trailer higher order sequence number. + */ +void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + json_object *json_instance; + + zlog_err("Higher order sequence number %d update for %s process", + ospf6->seqnum_h, ospf6->name); + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_get_ex(json_instances, inst_name, &json_instance); + if (!json_instance) { + json_instance = json_object_new_object(); + json_object_object_add(json_instances, inst_name, + json_instance); + } + + /* + * Record higher order sequence number in non volatile memory. + */ + json_object_int_add(json_instance, "sequence_number", ospf6->seqnum_h); + + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} + +/* + * Delete authentication sequence number for a given OSPF6 process + * from non-volatile memory. + */ +void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + + zlog_err("Higher order sequence number delete for %s process", + ospf6->name); + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_del(json_instances, inst_name); + + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} + + +/* + * Fetch from non-volatile memory the stored ospf6 process + * authentication sequence number. + */ +void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + json_object *json_instance; + json_object *json_seqnum; + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_get_ex(json_instances, inst_name, &json_instance); + if (!json_instance) { + json_instance = json_object_new_object(); + json_object_object_add(json_instances, inst_name, + json_instance); + } + + json_object_object_get_ex(json_instance, "sequence_number", + &json_seqnum); + ospf6->seqnum_h = json_object_get_int(json_seqnum); + + zlog_err("Higher order sequence number %d read for %s process %s", + ospf6->seqnum_h, ospf6->name, strerror(errno)); + + json_object_object_del(json_instances, inst_name); + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} diff --git a/ospf6d/ospf6_auth_trailer.h b/ospf6d/ospf6_auth_trailer.h new file mode 100644 index 000000000..dea4a6e16 --- /dev/null +++ b/ospf6d/ospf6_auth_trailer.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 Abhinay Ramesh + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __OSPF6_AUTH_TRAILER_H__ +#define __OSPF6_AUTH_TRAILER_H__ + +#include "lib/keychain.h" +#include "ospf6_message.h" + +#define OSPF6_AUTH_HDR_MIN_SIZE 16 +#define OSPF6_AUTH_HDR_FULL KEYCHAIN_MAX_HASH_SIZE + OSPF6_AUTH_HDR_MIN_SIZE + +#define OSPF6_AUTHENTICATION_NULL 0 +#define OSPF6_AUTHENTICATION_CRYPTOGRAPHIC 1 + +/* Auth debug options */ +extern unsigned char conf_debug_ospf6_auth[2]; + +#define OSPF6_AUTH_TX 0 +#define OSPF6_AUTH_RX 1 +#define OSPF6_DEBUG_AUTH_TX_ON() (conf_debug_ospf6_auth[OSPF6_AUTH_TX] = 1) +#define OSPF6_DEBUG_AUTH_TX_OFF() (conf_debug_ospf6_auth[OSPF6_AUTH_TX] = 0) +#define OSPF6_DEBUG_AUTH_RX_ON() (conf_debug_ospf6_auth[OSPF6_AUTH_RX] = 1) +#define OSPF6_DEBUG_AUTH_RX_OFF() (conf_debug_ospf6_auth[OSPF6_AUTH_RX] = 0) +#define IS_OSPF6_DEBUG_AUTH_TX (conf_debug_ospf6_auth[OSPF6_AUTH_TX]) +#define IS_OSPF6_DEBUG_AUTH_RX (conf_debug_ospf6_auth[OSPF6_AUTH_RX]) + +#define OSPF6_AUTH_TRAILER_KEYCHAIN (1 << 0) +#define OSPF6_AUTH_TRAILER_MANUAL_KEY (1 << 1) +#define OSPF6_AUTH_TRAILER_KEYCHAIN_VALID (1 << 2) + +/* According to sesion 4.1 of RFC7166 defining the trailer struct */ +struct ospf6_auth_hdr { + uint16_t type; + uint16_t length; + uint16_t reserved; + uint16_t id; + uint32_t seqnum_h; + uint32_t seqnum_l; + unsigned char data[KEYCHAIN_MAX_HASH_SIZE]; +}; + +enum ospf6_auth_err { + OSPF6_AUTH_VALIDATE_SUCCESS = 0, + OSPF6_AUTH_VALIDATE_FAILURE, + OSPF6_AUTH_PROCESS_NORMAL, + OSPF6_AUTH_FILE_EXIST, + OSPF6_AUTH_FILE_DO_NOT_EXIST +}; + +void ospf6_auth_hdr_dump_send(struct ospf6_header *ospfh, uint16_t length); +void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length, + unsigned int lls_len); +unsigned char *ospf6_hash_message_xor(unsigned char *mes1, unsigned char *mes2, + uint32_t len); +uint16_t ospf6_auth_len_get(struct ospf6_interface *oi); +int ospf6_auth_validate_pkt(struct ospf6_interface *oi, unsigned int *pkt_len, + struct ospf6_header *oh, unsigned int *at_len, + unsigned int *lls_block_len); +int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, + struct in6_addr *src, unsigned int lls_len); +void ospf6_auth_update_digest(struct ospf6_interface *oi, + struct ospf6_header *oh, + struct ospf6_auth_hdr *ospf6_auth, char *auth_str, + uint32_t pkt_len, enum keychain_hash_algo algo); +void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, + struct ospf6_header *oh, uint16_t auth_len, + uint32_t pkt_len); +void install_element_ospf6_debug_auth(void); +int config_write_ospf6_debug_auth(struct vty *vty); +void install_element_ospf6_clear_intf_auth(void); +enum ospf6_auth_err ospf6_auth_nvm_file_exist(void); +void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6); +void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6); +void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6); +#endif /* __OSPF6_AUTH_TRAILER_H__ */ diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c index c3e6f62f0..87407245b 100644 --- a/ospf6d/ospf6_gr.c +++ b/ospf6d/ospf6_gr.c @@ -455,14 +455,12 @@ static bool ospf6_gr_check_adjs(struct ospf6 *ospf6) } /* Handling of grace period expiry. */ -static int ospf6_gr_grace_period_expired(struct thread *thread) +static void ospf6_gr_grace_period_expired(struct thread *thread) { struct ospf6 *ospf6 = THREAD_ARG(thread); ospf6->gr_info.t_grace_period = NULL; ospf6_gr_restart_exit(ospf6, "grace period has expired"); - - return 0; } /* @@ -691,7 +689,7 @@ DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd, "graceful-restart prepare ipv6 ospf", "Graceful Restart commands\n" "Prepare upcoming graceful restart\n" IPV6_STR - "Prepare to restart the OSPFv3 process") + "Prepare to restart the OSPFv3 process\n") { ospf6_gr_prepare(); diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index dff6849e9..7b5ffc920 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -208,12 +208,11 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, * Returns: * Nothing */ -static int ospf6_handle_grace_timer_expiry(struct thread *thread) +static void ospf6_handle_grace_timer_expiry(struct thread *thread) { struct ospf6_neighbor *nbr = THREAD_ARG(thread); ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT); - return OSPF6_SUCCESS; } /* diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 0d9f15d08..b9ee3c340 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -46,8 +46,13 @@ #include "ospf6_zebra.h" #include "ospf6_gr.h" #include "lib/json.h" +#include "ospf6_proto.h" +#include "lib/keychain.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface"); +DEFINE_MTYPE(OSPF6D, OSPF6_AUTH_KEYCHAIN, "OSPF6 auth keychain"); +DEFINE_MTYPE(OSPF6D, OSPF6_AUTH_MANUAL_KEY, "OSPF6 auth key"); DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names"); DEFINE_QOBJ_TYPE(ospf6_interface); DEFINE_HOOK(ospf6_interface_change, @@ -252,6 +257,8 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp) /* Compute cost. */ oi->cost = ospf6_interface_get_cost(oi); + oi->at_data.flags = 0; + return oi; } @@ -724,7 +731,7 @@ static bool ifmaddr_check(ifindex_t ifindex, struct in6_addr *addr) #endif /* __FreeBSD__ */ /* Interface State Machine */ -int interface_up(struct thread *thread) +void interface_up(struct thread *thread) { struct ospf6_interface *oi; struct ospf6 *ospf6; @@ -745,7 +752,7 @@ int interface_up(struct thread *thread) if (!if_is_operative(oi->interface)) { zlog_warn("Interface %s is down, can't execute [InterfaceUp]", oi->interface->name); - return 0; + return; } /* check interface has a link-local address */ @@ -754,7 +761,7 @@ int interface_up(struct thread *thread) zlog_warn( "Interface %s has no link local address, can't execute [InterfaceUp]", oi->interface->name); - return 0; + return; } /* Recompute cost */ @@ -765,7 +772,7 @@ int interface_up(struct thread *thread) if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug("Interface %s already enabled", oi->interface->name); - return 0; + return; } /* If no area assigned, return */ @@ -773,7 +780,7 @@ int interface_up(struct thread *thread) zlog_warn( "%s: Not scheduling Hello for %s as there is no area assigned yet", __func__, oi->interface->name); - return 0; + return; } #ifdef __FreeBSD__ @@ -792,7 +799,7 @@ int interface_up(struct thread *thread) thread_add_timer(master, interface_up, oi, OSPF6_INTERFACE_SSO_RETRY_INT, &oi->thread_sso); - return 0; + return; } #endif /* __FreeBSD__ */ @@ -810,7 +817,7 @@ int interface_up(struct thread *thread) OSPF6_INTERFACE_SSO_RETRY_INT, &oi->thread_sso); } - return 0; + return; } oi->sso_try_cnt = 0; /* Reset on success */ @@ -836,11 +843,9 @@ int interface_up(struct thread *thread) thread_add_timer(master, wait_timer, oi, oi->dead_interval, &oi->thread_wait_timer); } - - return 0; } -int wait_timer(struct thread *thread) +void wait_timer(struct thread *thread) { struct ospf6_interface *oi; @@ -853,11 +858,9 @@ int wait_timer(struct thread *thread) if (oi->state == OSPF6_INTERFACE_WAITING) ospf6_interface_state_change(dr_election(oi), oi); - - return 0; } -int backup_seen(struct thread *thread) +void backup_seen(struct thread *thread) { struct ospf6_interface *oi; @@ -870,11 +873,9 @@ int backup_seen(struct thread *thread) if (oi->state == OSPF6_INTERFACE_WAITING) ospf6_interface_state_change(dr_election(oi), oi); - - return 0; } -int neighbor_change(struct thread *thread) +void neighbor_change(struct thread *thread) { struct ospf6_interface *oi; @@ -889,11 +890,9 @@ int neighbor_change(struct thread *thread) || oi->state == OSPF6_INTERFACE_BDR || oi->state == OSPF6_INTERFACE_DR) ospf6_interface_state_change(dr_election(oi), oi); - - return 0; } -int interface_down(struct thread *thread) +void interface_down(struct thread *thread) { struct ospf6_interface *oi; struct listnode *node, *nnode; @@ -935,7 +934,7 @@ int interface_down(struct thread *thread) oi->bdrouter = oi->prev_bdrouter = htonl(0); if (oi->area == NULL) - return 0; + return; ospf6 = oi->area->ospf6; /* Leave AllSPFRouters */ @@ -953,8 +952,6 @@ int interface_down(struct thread *thread) } ospf6_interface_state_change(OSPF6_INTERFACE_DOWN, oi); - - return 0; } @@ -990,6 +987,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, struct ospf6_lsa *lsa, *lsanext; json_object *json_arr; json_object *json_addr; + struct json_object *json_auth = NULL; default_iftype = ospf6_default_iftype(ifp); @@ -1238,6 +1236,48 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, } } + json_auth = json_object_new_object(); + if (oi->at_data.flags != 0) { + if (use_json) { + if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN)) { + json_object_string_add(json_auth, "authType", + "keychain"); + json_object_string_add(json_auth, + "keychainName", + oi->at_data.keychain); + } else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) + json_object_string_add(json_auth, "authType", + "manualkey"); + json_object_int_add(json_auth, "txPktDrop", + oi->at_data.tx_drop); + json_object_int_add(json_auth, "rxPktDrop", + oi->at_data.rx_drop); + } else { + if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN)) + vty_out(vty, + " Authentication Trailer is enabled with key-chain %s\n", + oi->at_data.keychain); + else if (CHECK_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_MANUAL_KEY)) + vty_out(vty, + " Authentication trailer is enabled with manual key\n"); + vty_out(vty, + " Packet drop Tx %u, Packet drop Rx %u\n", + oi->at_data.tx_drop, oi->at_data.rx_drop); + } + } else { + if (use_json) + json_object_string_add(json_auth, "authType", "NULL"); + else + vty_out(vty, " Authentication Trailer is disabled\n"); + } + + if (use_json) + json_object_object_add(json_obj, "authInfo", json_auth); + return 0; } @@ -2577,6 +2617,7 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf) ospf6_bfd_write_config(vty, oi); + ospf6_auth_write_config(vty, &oi->at_data); if_vty_config_end(vty); } return 0; @@ -2815,3 +2856,195 @@ void install_element_ospf6_debug_interface(void) install_element(CONFIG_NODE, &debug_ospf6_interface_cmd); install_element(CONFIG_NODE, &no_debug_ospf6_interface_cmd); } + +void ospf6_auth_write_config(struct vty *vty, struct ospf6_auth_data *at_data) +{ + if (CHECK_FLAG(at_data->flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) + vty_out(vty, " ipv6 ospf6 authentication keychain %s\n", + at_data->keychain); + else if (CHECK_FLAG(at_data->flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) + vty_out(vty, + " ipv6 ospf6 authentication key-id %d hash-algo %s key %s\n", + at_data->key_id, + keychain_get_algo_name_by_id(at_data->hash_algo), + at_data->auth_key); +} + +DEFUN(ipv6_ospf6_intf_auth_trailer_keychain, + ipv6_ospf6_intf_auth_trailer_keychain_cmd, + "ipv6 ospf6 authentication keychain KEYCHAIN_NAME", + IP6_STR OSPF6_STR + "Enable authentication on this interface\n" + "Keychain\n" + "Keychain name\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + int keychain_idx = 4; + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + + assert(oi); + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + vty_out(vty, + "Manual key configured, unconfigure it before configuring key chain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + SET_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN); + if (oi->at_data.keychain) + XFREE(MTYPE_OSPF6_AUTH_KEYCHAIN, oi->at_data.keychain); + + oi->at_data.keychain = + XSTRDUP(MTYPE_OSPF6_AUTH_KEYCHAIN, argv[keychain_idx]->arg); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_ospf6_intf_auth_trailer_keychain, + no_ipv6_ospf6_intf_auth_trailer_keychain_cmd, + "no ipv6 ospf6 authentication keychain [KEYCHAIN_NAME]", + NO_STR IP6_STR OSPF6_STR + "Enable authentication on this interface\n" + "Keychain\n" + "Keychain name\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi; + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + + assert(oi); + if (!CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) + return CMD_SUCCESS; + + if (oi->at_data.keychain) { + oi->at_data.flags = 0; + XFREE(MTYPE_OSPF6_AUTH_KEYCHAIN, oi->at_data.keychain); + oi->at_data.keychain = NULL; + } + + return CMD_SUCCESS; +} + +DEFUN(ipv6_ospf6_intf_auth_trailer_key, ipv6_ospf6_intf_auth_trailer_key_cmd, + "ipv6 ospf6 authentication key-id (1-65535) hash-algo " + " " + "key WORD", + IP6_STR OSPF6_STR + "Authentication\n" + "Key ID\n" + "Key ID value\n" + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n" + "Password\n" + "Password string (key)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + int key_id_idx = 4; + int hash_algo_idx = 6; + int password_idx = 8; + struct ospf6_interface *oi; + uint8_t hash_algo = KEYCHAIN_ALGO_NULL; + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + + assert(oi); + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { + vty_out(vty, + "key chain configured, unconfigure it before configuring manual key\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + hash_algo = keychain_get_algo_id_by_name(argv[hash_algo_idx]->arg); +#ifndef CRYPTO_OPENSSL + if (hash_algo == KEYCHAIN_ALGO_NULL) { + vty_out(vty, + "Hash algorithm not supported, compile with --with-crypto=openssl\n"); + return CMD_WARNING_CONFIG_FAILED; + } +#endif /* CRYPTO_OPENSSL */ + + SET_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY); + oi->at_data.hash_algo = hash_algo; + oi->at_data.key_id = (uint16_t)strtol(argv[key_id_idx]->arg, NULL, 10); + if (oi->at_data.auth_key) + XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, oi->at_data.auth_key); + oi->at_data.auth_key = + XSTRDUP(MTYPE_OSPF6_AUTH_MANUAL_KEY, argv[password_idx]->arg); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_ospf6_intf_auth_trailer_key, + no_ipv6_ospf6_intf_auth_trailer_key_cmd, + "no ipv6 ospf6 authentication key-id [(1-65535) hash-algo " + " " + "key WORD]", + NO_STR IP6_STR OSPF6_STR + "Authentication\n" + "Key ID\n" + "Key ID value\n" + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n" + "Password\n" + "Password string (key)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi; +#ifndef CRYPTO_OPENSSL + int hash_algo_idx = 7; + uint8_t hash_algo = KEYCHAIN_ALGO_NULL; +#endif /* CRYPTO_OPENSSL */ + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + + assert(oi); + if (!CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) + return CMD_SUCCESS; + +#ifndef CRYPTO_OPENSSL + hash_algo = keychain_get_algo_id_by_name(argv[hash_algo_idx]->arg); + if (hash_algo == KEYCHAIN_ALGO_NULL) { + vty_out(vty, + "Hash algorithm not supported, compile with --with-crypto=openssl\n"); + return CMD_WARNING_CONFIG_FAILED; + } +#endif /* CRYPTO_OPENSSL */ + + if (oi->at_data.auth_key) { + oi->at_data.flags = 0; + XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, oi->at_data.auth_key); + oi->at_data.auth_key = NULL; + } + + return CMD_SUCCESS; +} + +void ospf6_interface_auth_trailer_cmd_init(void) +{ + /*Install OSPF6 auth trailer commands at interface level */ + install_element(INTERFACE_NODE, + &ipv6_ospf6_intf_auth_trailer_keychain_cmd); + install_element(INTERFACE_NODE, + &no_ipv6_ospf6_intf_auth_trailer_keychain_cmd); + install_element(INTERFACE_NODE, &ipv6_ospf6_intf_auth_trailer_key_cmd); + install_element(INTERFACE_NODE, + &no_ipv6_ospf6_intf_auth_trailer_key_cmd); +} diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index ee24b989b..9a57a7f4d 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -24,6 +24,9 @@ #include "qobj.h" #include "hook.h" #include "if.h" +#include "ospf6d.h" + +DECLARE_MTYPE(OSPF6_AUTH_MANUAL_KEY); /* Debug option */ extern unsigned char conf_debug_ospf6_interface; @@ -31,6 +34,21 @@ extern unsigned char conf_debug_ospf6_interface; #define OSPF6_DEBUG_INTERFACE_OFF() (conf_debug_ospf6_interface = 0) #define IS_OSPF6_DEBUG_INTERFACE (conf_debug_ospf6_interface) +struct ospf6_auth_data { + /* config data */ + uint8_t hash_algo; /* hash algorithm type */ + uint16_t key_id; /* key-id used as SA in auth packet */ + char *auth_key; /* Auth key */ + char *keychain; /* keychain name */ + + /* operational data */ + uint8_t flags; /* Flags related to auth config */ + + /* Counters and Statistics */ + uint32_t tx_drop; /* Pkt drop due to auth fail while sending */ + uint32_t rx_drop; /* Pkt drop due to auth fail while reading */ +}; + /* Interface structure */ struct ospf6_interface { /* IF info from zebra */ @@ -95,6 +113,9 @@ struct ospf6_interface { /* MTU mismatch check */ uint8_t mtu_ignore; + /* Authentication trailer related config */ + struct ospf6_auth_data at_data; + /* Decision of DR Election */ in_addr_t drouter; in_addr_t bdrouter; @@ -205,11 +226,11 @@ extern struct in6_addr * ospf6_interface_get_global_address(struct interface *ifp); /* interface event */ -extern int interface_up(struct thread *thread); -extern int interface_down(struct thread *thread); -extern int wait_timer(struct thread *thread); -extern int backup_seen(struct thread *thread); -extern int neighbor_change(struct thread *thread); +extern void interface_up(struct thread *thread); +extern void interface_down(struct thread *thread); +extern void wait_timer(struct thread *thread); +extern void backup_seen(struct thread *thread); +extern void neighbor_change(struct thread *thread); extern void ospf6_interface_init(void); extern void ospf6_interface_clear(struct interface *ifp); @@ -221,6 +242,9 @@ extern void install_element_ospf6_debug_interface(void); extern int ospf6_interface_neighbor_count(struct ospf6_interface *oi); extern uint8_t dr_election(struct ospf6_interface *oi); +extern void ospf6_interface_auth_trailer_cmd_init(void); +extern void ospf6_auth_write_config(struct vty *vty, + struct ospf6_auth_data *at_data); DECLARE_HOOK(ospf6_interface_change, (struct ospf6_interface * oi, int state, int old_state), (oi, state, old_state)); diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 6626b4bed..f3fd9dab6 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -224,7 +224,7 @@ int ospf6_router_is_stub_router(struct ospf6_lsa *lsa) return OSPF6_NOT_STUB_ROUTER; } -int ospf6_router_lsa_originate(struct thread *thread) +void ospf6_router_lsa_originate(struct thread *thread) { struct ospf6_area *oa; @@ -249,7 +249,7 @@ int ospf6_router_lsa_originate(struct thread *thread) if (IS_DEBUG_OSPF6_GR) zlog_debug( "Graceful Restart in progress, don't originate LSA"); - return 0; + return; } if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) @@ -294,7 +294,7 @@ int ospf6_router_lsa_originate(struct thread *thread) + sizeof(struct ospf6_router_lsa)) { zlog_warn( "Size limit setting for Router-LSA too short"); - return 0; + return; } /* Fill LSA Header */ @@ -433,8 +433,6 @@ int ospf6_router_lsa_originate(struct thread *thread) if (count && !link_state_id) ospf6_spf_schedule(oa->ospf6, OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED); - - return 0; } /*******************************/ @@ -511,7 +509,7 @@ static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, return 0; } -int ospf6_network_lsa_originate(struct thread *thread) +void ospf6_network_lsa_originate(struct thread *thread) { struct ospf6_interface *oi; @@ -538,7 +536,7 @@ int ospf6_network_lsa_originate(struct thread *thread) if (IS_DEBUG_OSPF6_GR) zlog_debug( "Graceful Restart in progress, don't originate LSA"); - return 0; + return; } old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK), @@ -558,7 +556,7 @@ int ospf6_network_lsa_originate(struct thread *thread) oi->area->ospf6, OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED); } - return 0; + return; } if (IS_OSPF6_DEBUG_ORIGINATE(NETWORK)) @@ -577,7 +575,7 @@ int ospf6_network_lsa_originate(struct thread *thread) zlog_debug("Interface stub, ignore"); if (old) ospf6_lsa_purge(old); - return 0; + return; } /* prepare buffer */ @@ -635,8 +633,6 @@ int ospf6_network_lsa_originate(struct thread *thread) /* Originate */ ospf6_lsa_originate_area(lsa, oi->area); - - return 0; } @@ -765,7 +761,7 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, return 0; } -int ospf6_link_lsa_originate(struct thread *thread) +void ospf6_link_lsa_originate(struct thread *thread) { struct ospf6_interface *oi; @@ -785,7 +781,7 @@ int ospf6_link_lsa_originate(struct thread *thread) if (IS_DEBUG_OSPF6_GR) zlog_debug( "Graceful Restart in progress, don't originate LSA"); - return 0; + return; } @@ -797,7 +793,7 @@ int ospf6_link_lsa_originate(struct thread *thread) if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { if (old) ospf6_lsa_purge(old); - return 0; + return; } if (IS_OSPF6_DEBUG_ORIGINATE(LINK)) @@ -812,7 +808,7 @@ int ospf6_link_lsa_originate(struct thread *thread) oi->interface->name); if (old) ospf6_lsa_purge(old); - return 0; + return; } /* prepare buffer */ @@ -860,8 +856,6 @@ int ospf6_link_lsa_originate(struct thread *thread) /* Originate */ ospf6_lsa_originate_interface(lsa, oi); - - return 0; } @@ -1003,7 +997,7 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, return 0; } -int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) +void ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) { struct ospf6_area *oa; @@ -1028,7 +1022,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) if (IS_DEBUG_OSPF6_GR) zlog_debug( "Graceful Restart in progress, don't originate LSA"); - return 0; + return; } /* find previous LSA */ @@ -1051,7 +1045,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) oa->lsdb); } } - return 0; + return; } if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX)) @@ -1127,7 +1121,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) } } ospf6_route_table_delete(route_advertise); - return 0; + return; } /* Neighbor change to FULL, if INTRA-AREA-PREFIX LSA @@ -1212,7 +1206,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX)) zlog_debug( "Quit to Advertise Intra-Prefix: no route to advertise"); - return 0; + return; } intra_prefix_lsa->prefix_num = htons(prefix_num); @@ -1235,12 +1229,10 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) /* Originate */ ospf6_lsa_originate_area(lsa, oa); - - return 0; } -int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) +void ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) { struct ospf6_interface *oi; @@ -1268,7 +1260,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) if (IS_DEBUG_OSPF6_GR) zlog_debug( "Graceful Restart in progress, don't originate LSA"); - return 0; + return; } /* find previous LSA */ @@ -1279,7 +1271,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { if (old) ospf6_lsa_purge(old); - return 0; + return; } if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX)) @@ -1304,7 +1296,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) zlog_debug(" Interface is not DR"); if (old) ospf6_lsa_purge(old); - return 0; + return; } full_count = 0; @@ -1317,7 +1309,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) zlog_debug(" Interface is stub"); if (old) ospf6_lsa_purge(old); - return 0; + return; } /* connected prefix to advertise */ @@ -1406,7 +1398,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX)) zlog_debug( "Quit to Advertise Intra-Prefix: no route to advertise"); - return 0; + return; } intra_prefix_lsa->prefix_num = htons(prefix_num); @@ -1429,8 +1421,6 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) /* Originate */ ospf6_lsa_originate_area(lsa, oi->area); - - return 0; } static void ospf6_intra_prefix_update_route_origin(struct ospf6_route *oa_route, @@ -2148,7 +2138,7 @@ static void ospf6_brouter_debug_print(struct ospf6_route *brouter) char installed[64], changed[64]; struct timeval now, res; char id[16], adv_router[16]; - char capa[16], options[16]; + char capa[16], options[32]; brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix); inet_ntop(AF_INET, &brouter_id, brouter_name, sizeof(brouter_name)); diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h index f15bf0b9b..73cc77a56 100644 --- a/ospf6d/ospf6_intra.h +++ b/ospf6d/ospf6_intra.h @@ -235,14 +235,14 @@ extern char *ospf6_network_lsdesc_lookup(uint32_t router_id, struct ospf6_lsa *lsa); extern int ospf6_router_is_stub_router(struct ospf6_lsa *lsa); -extern int ospf6_router_lsa_originate(struct thread *thread); -extern int ospf6_network_lsa_originate(struct thread *thread); -extern int ospf6_link_lsa_originate(struct thread *thread); -extern int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread); -extern int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread); +extern void ospf6_router_lsa_originate(struct thread *thread); +extern void ospf6_network_lsa_originate(struct thread *thread); +extern void ospf6_link_lsa_originate(struct thread *thread); +extern void ospf6_intra_prefix_lsa_originate_transit(struct thread *thread); +extern void ospf6_intra_prefix_lsa_originate_stub(struct thread *thread); extern void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa); extern void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa); -extern int ospf6_orig_as_external_lsa(struct thread *thread); +extern void ospf6_orig_as_external_lsa(struct thread *thread); extern void ospf6_intra_route_calculation(struct ospf6_area *oa); extern void ospf6_intra_brouter_calculation(struct ospf6_area *oa); extern void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa, diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index b07b87737..779076f38 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -833,7 +833,7 @@ struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *lsa) /* ospf6 lsa expiry */ -int ospf6_lsa_expire(struct thread *thread) +void ospf6_lsa_expire(struct thread *thread) { struct ospf6_lsa *lsa; struct ospf6 *ospf6; @@ -852,7 +852,7 @@ int ospf6_lsa_expire(struct thread *thread) } if (CHECK_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY)) - return 0; /* dbexchange will do something ... */ + return; /* dbexchange will do something ... */ ospf6 = ospf6_get_by_lsdb(lsa); assert(ospf6); @@ -864,11 +864,9 @@ int ospf6_lsa_expire(struct thread *thread) /* schedule maxage remover */ ospf6_maxage_remove(ospf6); - - return 0; } -int ospf6_lsa_refresh(struct thread *thread) +void ospf6_lsa_refresh(struct thread *thread) { struct ospf6_lsa *old, *self, *new; struct ospf6_lsdb *lsdb_self; @@ -886,7 +884,7 @@ int ospf6_lsa_refresh(struct thread *thread) zlog_debug("Refresh: could not find self LSA, flush %s", old->name); ospf6_lsa_premature_aging(old); - return 0; + return; } /* Reset age, increment LS sequence number. */ @@ -911,8 +909,6 @@ int ospf6_lsa_refresh(struct thread *thread) ospf6_install_lsa(new); ospf6_flood(NULL, new); - - return 0; } void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6) diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index aa1150afc..fea9aba27 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -256,8 +256,8 @@ extern struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsa_lock(struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *lsa); -extern int ospf6_lsa_expire(struct thread *thread); -extern int ospf6_lsa_refresh(struct thread *thread); +extern void ospf6_lsa_expire(struct thread *thread); +extern void ospf6_lsa_refresh(struct thread *thread); extern unsigned short ospf6_lsa_checksum(struct ospf6_lsa_header *lsah); extern int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *lsah); diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 039c65d73..889ab16b1 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -92,6 +92,16 @@ static void _lsdb_count_assert(struct ospf6_lsdb *lsdb) #define ospf6_lsdb_count_assert(t) ((void) 0) #endif /*DEBUG*/ +static inline void ospf6_lsdb_stats_update(struct ospf6_lsa *lsa, + struct ospf6_lsdb *lsdb, int count) +{ + uint16_t stat = ntohs(lsa->header->type) & OSPF6_LSTYPE_FCODE_MASK; + + if (stat >= OSPF6_LSTYPE_SIZE) + stat = OSPF6_LSTYPE_UNKNOWN; + lsdb->stats[stat] += count; +} + void ospf6_lsdb_add(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) { struct prefix_ipv6 key; @@ -112,6 +122,7 @@ void ospf6_lsdb_add(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) if (!old) { lsdb->count++; + ospf6_lsdb_stats_update(lsa, lsdb, 1); if (OSPF6_LSA_IS_MAXAGE(lsa)) { if (lsdb->hook_remove) @@ -161,6 +172,7 @@ void ospf6_lsdb_remove(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) node->info = NULL; lsdb->count--; + ospf6_lsdb_stats_update(lsa, lsdb, -1); if (lsdb->hook_remove) (*lsdb->hook_remove)(lsa); diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h index 9789e8c4e..07c331af6 100644 --- a/ospf6d/ospf6_lsdb.h +++ b/ospf6d/ospf6_lsdb.h @@ -29,6 +29,7 @@ struct ospf6_lsdb { void *data; /* data structure that holds this lsdb */ struct route_table *table; uint32_t count; + uint32_t stats[OSPF6_LSTYPE_SIZE]; void (*hook_add)(struct ospf6_lsa *); void (*hook_remove)(struct ospf6_lsa *); }; diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 165a764c3..120f307ad 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "getopt.h" @@ -223,6 +224,7 @@ int main(int argc, char *argv[], char *envp[]) /* thread master */ master = om6->master; + keychain_init(); ospf6_vrf_init(); access_list_init(); prefix_list_init(); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 352cb137e..6645f83b0 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -27,6 +27,7 @@ #include "thread.h" #include "linklist.h" #include "lib_errors.h" +#include "checksum.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -48,19 +49,34 @@ #include "ospf6d.h" #include "ospf6_gr.h" #include +#include "lib/libospf.h" +#include "lib/keychain.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PACKET, "OSPF6 packet"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_FIFO, "OSPF6 FIFO queue"); unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; -static const struct message ospf6_message_type_str[] = { - {OSPF6_MESSAGE_TYPE_HELLO, "Hello"}, - {OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc"}, - {OSPF6_MESSAGE_TYPE_LSREQ, "LSReq"}, - {OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate"}, - {OSPF6_MESSAGE_TYPE_LSACK, "LSAck"}, - {0}}; + +const char *ospf6_message_type(int type) +{ + switch (type) { + case OSPF6_MESSAGE_TYPE_HELLO: + return "Hello"; + case OSPF6_MESSAGE_TYPE_DBDESC: + return "DbDesc"; + case OSPF6_MESSAGE_TYPE_LSREQ: + return "LSReq"; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + return "LSUpdate"; + case OSPF6_MESSAGE_TYPE_LSACK: + return "LSAck"; + case OSPF6_MESSAGE_TYPE_UNKNOWN: + default: + return "unknown"; + } +} /* Minimum (besides the standard OSPF packet header) lengths for OSPF packets of particular types, offset is the "type" field. */ @@ -101,7 +117,7 @@ static void ospf6_header_print(struct ospf6_header *oh) void ospf6_hello_print(struct ospf6_header *oh, int action) { struct ospf6_hello *hello; - char options[16]; + char options[32]; char *p; ospf6_header_print(oh); @@ -136,7 +152,7 @@ void ospf6_hello_print(struct ospf6_header *oh, int action) void ospf6_dbdesc_print(struct ospf6_header *oh, int action) { struct ospf6_dbdesc *dbdesc; - char options[16]; + char options[32]; char *p; ospf6_header_print(oh); @@ -439,6 +455,20 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, return; } + if (((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) == + OSPF6_OPT_AT) && + (oi->at_data.flags == 0)) || + ((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) != + OSPF6_OPT_AT) && + (oi->at_data.flags != 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_warn( + "VRF %s: IF %s AT-bit mismatch in hello packet", + oi->interface->vrf->name, oi->interface->name); + oi->at_data.rx_drop++; + return; + } + /* Find neighbor, create if not exist */ on = ospf6_neighbor_lookup(oh->router_id, oi); if (on == NULL) { @@ -1006,6 +1036,20 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst, dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh + sizeof(struct ospf6_header)); + if (((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) == + OSPF6_OPT_AT) && + (oi->at_data.flags == 0)) || + ((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) != + OSPF6_OPT_AT) && + (oi->at_data.flags != 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_warn( + "VRF %s: IF %s AT-bit mismatch in dbdesc packet", + oi->interface->vrf->name, oi->interface->name); + oi->at_data.rx_drop++; + return; + } + /* Interface MTU check */ if (!oi->mtu_ignore && ntohs(dbdesc->ifmtu) != oi->ifmtu) { zlog_warn("VRF %s: I/F %s MTU mismatch (my %d rcvd %d)", @@ -1412,14 +1456,15 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, bytesonwire); return MSG_NG; } + /* Now it is safe to access header fields. */ if (bytesonwire != ntohs(oh->length)) { zlog_warn("%s: %s packet length error (%u real, %u declared)", - __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL), - bytesonwire, ntohs(oh->length)); + __func__, ospf6_message_type(oh->type), bytesonwire, + ntohs(oh->length)); return MSG_NG; } + /* version check */ if (oh->version != OSPFV3_VERSION) { zlog_warn("%s: invalid (%u) protocol version", __func__, @@ -1431,8 +1476,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, && bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) { zlog_warn("%s: undersized (%u B) %s packet", __func__, - bytesonwire, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + bytesonwire, ospf6_message_type(oh->type)); return MSG_NG; } /* type-specific deeper validation */ @@ -1446,7 +1490,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, % 4) return MSG_OK; zlog_warn("%s: alignment error in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_DBDESC: /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes @@ -1467,7 +1511,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, % OSPF6_LSREQ_LSDESC_FIX_SIZE) return MSG_OK; zlog_warn("%s: alignment error in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_LSUPDATE: /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes @@ -1497,7 +1541,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, } if (test != MSG_OK) zlog_warn("%s: anomaly in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return test; } @@ -1727,6 +1771,9 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; + enum ospf6_auth_err ret = OSPF6_AUTH_PROCESS_NORMAL; + uint32_t at_len = 0; + uint32_t lls_len = 0; /* initialize */ memset(&src, 0, sizeof(src)); @@ -1772,6 +1819,24 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) return OSPF6_READ_CONTINUE; oh = (struct ospf6_header *)recvbuf; + ret = ospf6_auth_validate_pkt(oi, (uint32_t *)&len, oh, &at_len, + &lls_len); + if (ret == OSPF6_AUTH_VALIDATE_SUCCESS) { + ret = ospf6_auth_check_digest(oh, oi, &src, lls_len); + if (ret == OSPF6_AUTH_VALIDATE_FAILURE) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err( + "RECV[%s]: OSPF packet auth digest miss-match on %s", + oi->interface->name, + ospf6_message_type(oh->type)); + oi->at_data.rx_drop++; + return OSPF6_READ_CONTINUE; + } + } else if (ret == OSPF6_AUTH_VALIDATE_FAILURE) { + oi->at_data.rx_drop++; + return OSPF6_READ_CONTINUE; + } + if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK) return OSPF6_READ_CONTINUE; @@ -1782,8 +1847,7 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) /* Log */ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) { - zlog_debug("%s received on %s", - lookup_msg(ospf6_message_type_str, oh->type, NULL), + zlog_debug("%s received on %s", ospf6_message_type(oh->type), oi->interface->name); zlog_debug(" src: %pI6", &src); zlog_debug(" dst: %pI6", &dst); @@ -1807,6 +1871,10 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) default: assert(0); } + + if ((at_len != 0) && IS_OSPF6_DEBUG_AUTH_RX) + ospf6_auth_hdr_dump_recv(oh, (len + at_len + lls_len), + lls_len); } switch (oh->type) { @@ -1837,7 +1905,7 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) return OSPF6_READ_CONTINUE; } -int ospf6_receive(struct thread *thread) +void ospf6_receive(struct thread *thread) { int sockfd; struct ospf6 *ospf6; @@ -1854,13 +1922,32 @@ int ospf6_receive(struct thread *thread) count++; switch (ospf6_read_helper(sockfd, ospf6)) { case OSPF6_READ_ERROR: - return 0; + return; case OSPF6_READ_CONTINUE: break; } } +} - return 0; +static void ospf6_fill_hdr_checksum(struct ospf6_interface *oi, + struct ospf6_packet *op) +{ + struct ipv6_ph ph = {}; + struct ospf6_header *oh; + void *offset = NULL; + + if (oi->at_data.flags != 0) + return; + + memcpy(&ph.src, oi->linklocal_addr, sizeof(struct in6_addr)); + memcpy(&ph.dst, &op->dst, sizeof(struct in6_addr)); + ph.ulpl = htonl(op->length); + ph.next_hdr = IPPROTO_OSPFIGP; + + /* Suppress static analysis warnings about accessing icmp6 oob */ + oh = (struct ospf6_header *)STREAM_DATA(op->s); + offset = oh; + oh->checksum = in_cksum_with_ph6(&ph, offset, op->length); } static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, @@ -1873,6 +1960,7 @@ static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, oh->version = (uint8_t)OSPFV3_VERSION; oh->type = type; oh->length = 0; + oh->router_id = oi->area->ospf6->router_id; oh->area_id = oi->area->area_id; oh->checksum = 0; @@ -1904,9 +1992,48 @@ static void ospf6_fill_lsupdate_header(struct stream *s, uint32_t lsa_num) lsu->lsa_number = htonl(lsa_num); } -static uint32_t ospf6_packet_max(struct ospf6_interface *oi) +static void ospf6_auth_trailer_copy_keychain_key(struct ospf6_interface *oi) +{ + char *keychain_name = NULL; + struct keychain *keychain = NULL; + struct key *key = NULL; + + keychain_name = oi->at_data.keychain; + keychain = keychain_lookup(keychain_name); + if (keychain) { + key = key_lookup_for_send(keychain); + if (key && key->string && + key->hash_algo != KEYCHAIN_ALGO_NULL) { + /* storing the values so that further + * lookup can be avoided. after + * processing the digest need to reset + * these values + */ + oi->at_data.hash_algo = key->hash_algo; + oi->at_data.auth_key = XSTRDUP( + MTYPE_OSPF6_AUTH_MANUAL_KEY, key->string); + oi->at_data.key_id = key->index; + SET_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID); + } + } +} + +static uint16_t ospf6_packet_max(struct ospf6_interface *oi) { + uint16_t at_len = 0; + assert(oi->ifmtu > sizeof(struct ip6_hdr)); + + if (oi->at_data.flags != 0) { + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) + ospf6_auth_trailer_copy_keychain_key(oi); + + at_len += OSPF6_AUTH_HDR_MIN_SIZE; + at_len += keychain_get_hash_len(oi->at_data.hash_algo); + return oi->ifmtu - (sizeof(struct ip6_hdr)) - at_len; + } + return oi->ifmtu - (sizeof(struct ip6_hdr)); } @@ -1915,11 +2042,15 @@ static uint16_t ospf6_make_hello(struct ospf6_interface *oi, struct stream *s) struct listnode *node, *nnode; struct ospf6_neighbor *on; uint16_t length = OSPF6_HELLO_MIN_SIZE; + uint8_t options1 = oi->area->options[1]; + + if (oi->at_data.flags != 0) + options1 |= OSPF6_OPT_AT; stream_putl(s, oi->interface->ifindex); stream_putc(s, oi->priority); stream_putc(s, oi->area->options[0]); - stream_putc(s, oi->area->options[1]); + stream_putc(s, options1); stream_putc(s, oi->area->options[2]); stream_putw(s, oi->hello_interval); stream_putw(s, oi->dead_interval); @@ -1946,7 +2077,7 @@ static uint16_t ospf6_make_hello(struct ospf6_interface *oi, struct stream *s) return length; } -static int ospf6_write(struct thread *thread) +static void ospf6_write(struct thread *thread) { struct ospf6 *ospf6 = THREAD_ARG(thread); struct ospf6_interface *oi; @@ -1959,10 +2090,11 @@ static int ospf6_write(struct thread *thread) int len; int64_t latency = 0; struct timeval timestamp; + uint16_t at_len = 0; if (ospf6->fd < 0) { zlog_warn("ospf6_write failed to send, fd %d", ospf6->fd); - return -1; + return; } node = listhead(ospf6->oi_write_q); @@ -1983,17 +2115,32 @@ static int ospf6_write(struct thread *thread) oh = (struct ospf6_header *)STREAM_DATA(op->s); + if (oi->at_data.flags != 0) { + at_len = ospf6_auth_len_get(oi); + if (at_len) { + iovector[0].iov_len = + ntohs(oh->length) + at_len; + ospf6_auth_digest_send(oi->linklocal_addr, oi, + oh, at_len, + iovector[0].iov_len); + } else { + iovector[0].iov_len = ntohs(oh->length); + } + } else { + iovector[0].iov_len = ntohs(oh->length); + } + len = ospf6_sendmsg(oi->linklocal_addr, &op->dst, oi->interface->ifindex, iovector, ospf6->fd); - if (len != op->length) + + if (len != (op->length + (int)at_len)) flog_err(EC_LIB_DEVELOPMENT, "Could not send entire message"); if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) { zlog_debug("%s send on %s", - lookup_msg(ospf6_message_type_str, oh->type, - NULL), + ospf6_message_type(oh->type), oi->interface->name); zlog_debug(" src: %pI6", oi->linklocal_addr); zlog_debug(" dst: %pI6", &op->dst); @@ -2052,6 +2199,15 @@ static int ospf6_write(struct thread *thread) assert(0); break; } + + if ((oi->at_data.flags != 0) && + (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) && + (IS_OSPF6_DEBUG_AUTH_TX)) + ospf6_auth_hdr_dump_send(oh, iovector[0].iov_len); + + /* initialize at_len to 0 for next packet */ + at_len = 0; + /* Now delete packet from queue. */ ospf6_packet_delete(oi); @@ -2077,11 +2233,9 @@ static int ospf6_write(struct thread *thread) if (!list_isempty(ospf6->oi_write_q)) thread_add_write(master, ospf6_write, ospf6, ospf6->fd, &ospf6->t_write); - - return 0; } -int ospf6_hello_send(struct thread *thread) +void ospf6_hello_send(struct thread *thread) { struct ospf6_interface *oi; struct ospf6_packet *op; @@ -2094,7 +2248,7 @@ int ospf6_hello_send(struct thread *thread) if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO, SEND_HDR)) zlog_debug("Unable to send Hello on down interface %s", oi->interface->name); - return 0; + return; } op = ospf6_packet_new(oi->ifmtu); @@ -2106,7 +2260,7 @@ int ospf6_hello_send(struct thread *thread) if (length == OSPF6_HEADER_SIZE) { /* Hello overshooting MTU */ ospf6_packet_free(op); - return 0; + return; } /* Fill OSPF header. */ @@ -2117,6 +2271,8 @@ int ospf6_hello_send(struct thread *thread) op->dst = allspfrouters6; + ospf6_fill_hdr_checksum(oi, op); + /* Add packet to the top of the interface output queue, so that they * can't get delayed by things like long queues of LS Update packets */ @@ -2127,14 +2283,16 @@ int ospf6_hello_send(struct thread *thread) &oi->thread_send_hello); OSPF6_MESSAGE_WRITE_ON(oi); - - return 0; } static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) { uint16_t length = OSPF6_DB_DESC_MIN_SIZE; struct ospf6_lsa *lsa, *lsanext; + uint8_t options1 = on->ospf6_if->area->options[1]; + + if (on->ospf6_if->at_data.flags != 0) + options1 |= OSPF6_OPT_AT; /* if this is initial one, initialize sequence number for DbDesc */ if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) @@ -2145,7 +2303,7 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) /* reserved */ stream_putc(s, 0); /* reserved 1 */ stream_putc(s, on->ospf6_if->area->options[0]); - stream_putc(s, on->ospf6_if->area->options[1]); + stream_putc(s, options1); stream_putc(s, on->ospf6_if->area->options[2]); stream_putw(s, on->ospf6_if->ifmtu); stream_putc(s, 0); /* reserved 2 */ @@ -2175,7 +2333,7 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) return length; } -int ospf6_dbdesc_send(struct thread *thread) +void ospf6_dbdesc_send(struct thread *thread) { struct ospf6_neighbor *on; uint16_t length = OSPF6_HEADER_SIZE; @@ -2189,7 +2347,7 @@ int ospf6_dbdesc_send(struct thread *thread) zlog_debug( "Quit to send DbDesc to neighbor %s state %s", on->name, ospf6_neighbor_state_str[on->state]); - return 0; + return; } /* set next thread if master */ @@ -2212,14 +2370,14 @@ int ospf6_dbdesc_send(struct thread *thread) else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); + ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); - - return 0; } -int ospf6_dbdesc_send_newone(struct thread *thread) +void ospf6_dbdesc_send_newone(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa, *lsanext; @@ -2265,7 +2423,6 @@ int ospf6_dbdesc_send_newone(struct thread *thread) &on->thread_exchange_done); thread_execute(master, ospf6_dbdesc_send, on, 0); - return 0; } static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s) @@ -2319,6 +2476,7 @@ static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on, (*op)->length = length + OSPF6_HEADER_SIZE; (*op)->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, *op); ospf6_packet_add(on->ospf6_if, *op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); /* new packet */ @@ -2341,7 +2499,7 @@ static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on, return length; } -int ospf6_lsreq_send(struct thread *thread) +void ospf6_lsreq_send(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_packet *op; @@ -2357,13 +2515,13 @@ int ospf6_lsreq_send(struct thread *thread) zlog_debug("Quit to send LSReq to neighbor %s state %s", on->name, ospf6_neighbor_state_str[on->state]); - return 0; + return; } /* schedule loading_done if request list is empty */ if (on->request_list->count == 0) { thread_add_event(master, loading_done, on, 0, NULL); - return 0; + return; } op = ospf6_packet_new(on->ospf6_if->ifmtu); @@ -2374,7 +2532,7 @@ int ospf6_lsreq_send(struct thread *thread) if (length == OSPF6_HEADER_SIZE) { /* Hello overshooting MTU */ ospf6_packet_free(op); - return 0; + return; } /* Fill OSPF header. */ @@ -2388,6 +2546,7 @@ int ospf6_lsreq_send(struct thread *thread) else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2398,8 +2557,6 @@ int ospf6_lsreq_send(struct thread *thread) on->ospf6_if->rxmt_interval, &on->thread_send_lsreq); } - - return 0; } static void ospf6_send_lsupdate(struct ospf6_neighbor *on, @@ -2425,6 +2582,7 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, op->dst = alldrouters6; } if (oi) { + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); /* If ospf instance is being deleted, send the packet * immediately @@ -2452,9 +2610,8 @@ static uint16_t ospf6_make_lsupdate_list(struct ospf6_neighbor *on, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) { - if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header) - + OSPF6_HEADER_SIZE) - > ospf6_packet_max(on->ospf6_if)) { + if ((length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE) > + ospf6_packet_max(on->ospf6_if)) { ospf6_fill_header(on->ospf6_if, (*op)->s, length + OSPF6_HEADER_SIZE); (*op)->length = length + OSPF6_HEADER_SIZE; @@ -2490,9 +2647,8 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header) - + OSPF6_HEADER_SIZE) - > ospf6_packet_max(on->ospf6_if)) { + if ((length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE) > + ospf6_packet_max(on->ospf6_if)) { ospf6_fill_header(on->ospf6_if, (*op)->s, length + OSPF6_HEADER_SIZE); (*op)->length = length + OSPF6_HEADER_SIZE; @@ -2502,6 +2658,7 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, else (*op)->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, *op); ospf6_packet_add(on->ospf6_if, *op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2521,7 +2678,7 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, return length; } -int ospf6_lsupdate_send_neighbor(struct thread *thread) +void ospf6_lsupdate_send_neighbor(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_packet *op; @@ -2539,7 +2696,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) SEND_HDR)) zlog_debug("Quit to send (neighbor state %s)", ospf6_neighbor_state_str[on->state]); - return 0; + return; } /* first do lsupdate_list */ @@ -2573,6 +2730,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) op->dst = allspfrouters6; else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); } else @@ -2586,7 +2744,6 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) on->ospf6_if->rxmt_interval, &on->thread_send_lsupdate); } - return 0; } int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on, @@ -2629,9 +2786,8 @@ static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) { - if (length + (unsigned int)OSPF6_LSA_SIZE(lsa->header) - + OSPF6_HEADER_SIZE - > ospf6_packet_max(oi)) { + if (length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE > + ospf6_packet_max(oi)) { ospf6_fill_header(oi, (*op)->s, length + OSPF6_HEADER_SIZE); (*op)->length = length + OSPF6_HEADER_SIZE; @@ -2658,7 +2814,7 @@ static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi, return length; } -int ospf6_lsupdate_send_interface(struct thread *thread) +void ospf6_lsupdate_send_interface(struct thread *thread) { struct ospf6_interface *oi; struct ospf6_packet *op; @@ -2675,12 +2831,12 @@ int ospf6_lsupdate_send_interface(struct thread *thread) "Quit to send LSUpdate to interface %s state %s", oi->interface->name, ospf6_interface_state_str[oi->state]); - return 0; + return; } /* if we have nothing to send, return */ if (oi->lsupdate_list->count == 0) - return 0; + return; op = ospf6_packet_new(oi->ifmtu); ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi, op->s); @@ -2698,11 +2854,9 @@ int ospf6_lsupdate_send_interface(struct thread *thread) thread_add_event(master, ospf6_lsupdate_send_interface, oi, 0, &oi->thread_send_lsupdate); } - - return 0; } -int ospf6_lsack_send_neighbor(struct thread *thread) +void ospf6_lsack_send_neighbor(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_packet *op; @@ -2716,12 +2870,12 @@ int ospf6_lsack_send_neighbor(struct thread *thread) zlog_debug("Quit to send LSAck to neighbor %s state %s", on->name, ospf6_neighbor_state_str[on->state]); - return 0; + return; } /* if we have nothing to send, return */ if (on->lsack_list->count == 0) - return 0; + return; op = ospf6_packet_new(on->ospf6_if->ifmtu); ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, on->ospf6_if, op->s); @@ -2730,7 +2884,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread) if (length == OSPF6_HEADER_SIZE) { ospf6_packet_free(op); - return 0; + return; } /* Fill OSPF header. */ @@ -2739,14 +2893,13 @@ int ospf6_lsack_send_neighbor(struct thread *thread) /* Set packet length, dst and queue to FIFO. */ op->length = length; op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); if (on->lsack_list->count > 0) thread_add_event(master, ospf6_lsack_send_neighbor, on, 0, &on->thread_send_lsack); - - return 0; } static uint16_t ospf6_make_lsack_interface(struct ospf6_interface *oi, @@ -2780,7 +2933,7 @@ static uint16_t ospf6_make_lsack_interface(struct ospf6_interface *oi, return length; } -int ospf6_lsack_send_interface(struct thread *thread) +void ospf6_lsack_send_interface(struct thread *thread) { struct ospf6_interface *oi; struct ospf6_packet *op; @@ -2795,12 +2948,12 @@ int ospf6_lsack_send_interface(struct thread *thread) "Quit to send LSAck to interface %s state %s", oi->interface->name, ospf6_interface_state_str[oi->state]); - return 0; + return; } /* if we have nothing to send, return */ if (oi->lsack_list->count == 0) - return 0; + return; op = ospf6_packet_new(oi->ifmtu); ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, oi, op->s); @@ -2809,7 +2962,7 @@ int ospf6_lsack_send_interface(struct thread *thread) if (length == OSPF6_HEADER_SIZE) { ospf6_packet_free(op); - return 0; + return; } /* Fill OSPF header. */ ospf6_fill_header(oi, op->s, length); @@ -2823,14 +2976,13 @@ int ospf6_lsack_send_interface(struct thread *thread) else op->dst = alldrouters6; + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); OSPF6_MESSAGE_WRITE_ON(oi); if (oi->lsack_list->count > 0) thread_add_event(master, ospf6_lsack_send_interface, oi, 0, &oi->thread_send_lsack); - - return 0; } /* Commands */ diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index 0cd10ef82..daab98640 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -25,6 +25,7 @@ /* Debug option */ extern unsigned char conf_debug_ospf6_message[]; + #define OSPF6_ACTION_SEND 0x01 #define OSPF6_ACTION_RECV 0x02 #define OSPF6_DEBUG_MESSAGE_SEND 0x01 @@ -62,6 +63,7 @@ extern unsigned char conf_debug_ospf6_message[]; #define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4 /* Database update */ #define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */ #define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */ +#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */ struct ospf6_packet { struct ospf6_packet *next; @@ -146,8 +148,16 @@ struct ospf6_lsupdate { /* Followed by LSAs */ }; +/* LLS is not supported, but used to derive + * offset of Auth_trailer + */ +struct ospf6_lls_hdr { + uint16_t checksum; + uint16_t length; +}; + /* Link State Acknowledgement */ -#define OSPF6_LS_ACK_MIN_SIZE 0U +#define OSPF6_LS_ACK_MIN_SIZE 0U /* It is just a sequence of LSA Headers */ /* Function definition */ @@ -163,18 +173,18 @@ extern void ospf6_fifo_free(struct ospf6_fifo *fifo); extern int ospf6_iobuf_size(unsigned int size); extern void ospf6_message_terminate(void); -extern int ospf6_receive(struct thread *thread); +extern void ospf6_receive(struct thread *thread); -extern int ospf6_hello_send(struct thread *thread); -extern int ospf6_dbdesc_send(struct thread *thread); -extern int ospf6_dbdesc_send_newone(struct thread *thread); -extern int ospf6_lsreq_send(struct thread *thread); -extern int ospf6_lsupdate_send_interface(struct thread *thread); -extern int ospf6_lsupdate_send_neighbor(struct thread *thread); -extern int ospf6_lsack_send_interface(struct thread *thread); -extern int ospf6_lsack_send_neighbor(struct thread *thread); +extern void ospf6_hello_send(struct thread *thread); +extern void ospf6_dbdesc_send(struct thread *thread); +extern void ospf6_dbdesc_send_newone(struct thread *thread); +extern void ospf6_lsreq_send(struct thread *thread); +extern void ospf6_lsupdate_send_interface(struct thread *thread); +extern void ospf6_lsupdate_send_neighbor(struct thread *thread); +extern void ospf6_lsack_send_interface(struct thread *thread); +extern void ospf6_lsack_send_neighbor(struct thread *thread); extern int config_write_ospf6_debug_message(struct vty *); extern void install_element_ospf6_debug_message(void); - +extern const char *ospf6_message_type(int type); #endif /* OSPF6_MESSAGE_H */ diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index afa504d13..8dca0913d 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -112,6 +112,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, { struct ospf6_neighbor *on; char buf[16]; + int type; on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor)); inet_ntop(AF_INET, &router_id, buf, sizeof(buf)); @@ -131,6 +132,13 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, on->lsupdate_list = ospf6_lsdb_create(on); on->lsack_list = ospf6_lsdb_create(on); + for (type = 0; type < OSPF6_MESSAGE_TYPE_MAX; type++) { + on->seqnum_l[type] = 0; + on->seqnum_h[type] = 0; + } + + on->auth_present = false; + listnode_add_sort(oi->neighbor_list, on); ospf6_bfd_info_nbr_create(oi, on); @@ -264,7 +272,7 @@ static int need_adjacency(struct ospf6_neighbor *on) return 0; } -int hello_received(struct thread *thread) +void hello_received(struct thread *thread) { struct ospf6_neighbor *on; @@ -282,11 +290,9 @@ int hello_received(struct thread *thread) if (on->state <= OSPF6_NEIGHBOR_DOWN) ospf6_neighbor_state_change(OSPF6_NEIGHBOR_INIT, on, OSPF6_NEIGHBOR_EVENT_HELLO_RCVD); - - return 0; } -int twoway_received(struct thread *thread) +void twoway_received(struct thread *thread) { struct ospf6_neighbor *on; @@ -294,7 +300,7 @@ int twoway_received(struct thread *thread) assert(on); if (on->state > OSPF6_NEIGHBOR_INIT) - return 0; + return; if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) zlog_debug("Neighbor Event %s: *2Way-Received*", on->name); @@ -304,7 +310,7 @@ int twoway_received(struct thread *thread) if (!need_adjacency(on)) { ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on, OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); - return 0; + return; } ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on, @@ -316,11 +322,9 @@ int twoway_received(struct thread *thread) THREAD_OFF(on->thread_send_dbdesc); thread_add_event(master, ospf6_dbdesc_send, on, 0, &on->thread_send_dbdesc); - - return 0; } -int negotiation_done(struct thread *thread) +void negotiation_done(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa, *lsanext; @@ -329,7 +333,7 @@ int negotiation_done(struct thread *thread) assert(on); if (on->state != OSPF6_NEIGHBOR_EXSTART) - return 0; + return; if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) zlog_debug("Neighbor Event %s: *NegotiationDone*", on->name); @@ -372,21 +376,17 @@ int negotiation_done(struct thread *thread) UNSET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT); ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXCHANGE, on, OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE); - - return 0; } -static int ospf6_neighbor_last_dbdesc_release(struct thread *thread) +static void ospf6_neighbor_last_dbdesc_release(struct thread *thread) { struct ospf6_neighbor *on = THREAD_ARG(thread); assert(on); memset(&on->dbdesc_last, 0, sizeof(struct ospf6_dbdesc)); - - return 0; } -int exchange_done(struct thread *thread) +void exchange_done(struct thread *thread) { struct ospf6_neighbor *on; @@ -394,7 +394,7 @@ int exchange_done(struct thread *thread) assert(on); if (on->state != OSPF6_NEIGHBOR_EXCHANGE) - return 0; + return; if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) zlog_debug("Neighbor Event %s: *ExchangeDone*", on->name); @@ -420,8 +420,6 @@ int exchange_done(struct thread *thread) thread_add_event(master, ospf6_lsreq_send, on, 0, &on->thread_send_lsreq); } - - return 0; } /* Check loading state. */ @@ -445,7 +443,7 @@ void ospf6_check_nbr_loading(struct ospf6_neighbor *on) } } -int loading_done(struct thread *thread) +void loading_done(struct thread *thread) { struct ospf6_neighbor *on; @@ -453,7 +451,7 @@ int loading_done(struct thread *thread) assert(on); if (on->state != OSPF6_NEIGHBOR_LOADING) - return 0; + return; if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) zlog_debug("Neighbor Event %s: *LoadingDone*", on->name); @@ -462,11 +460,9 @@ int loading_done(struct thread *thread) ospf6_neighbor_state_change(OSPF6_NEIGHBOR_FULL, on, OSPF6_NEIGHBOR_EVENT_LOADING_DONE); - - return 0; } -int adj_ok(struct thread *thread) +void adj_ok(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa, *lsanext; @@ -499,11 +495,9 @@ int adj_ok(struct thread *thread) ospf6_lsdb_remove(lsa, on->retrans_list); } } - - return 0; } -int seqnumber_mismatch(struct thread *thread) +void seqnumber_mismatch(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa, *lsanext; @@ -512,7 +506,7 @@ int seqnumber_mismatch(struct thread *thread) assert(on); if (on->state < OSPF6_NEIGHBOR_EXCHANGE) - return 0; + return; if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) zlog_debug("Neighbor Event %s: *SeqNumberMismatch*", on->name); @@ -536,11 +530,9 @@ int seqnumber_mismatch(struct thread *thread) on->thread_send_dbdesc = NULL; thread_add_event(master, ospf6_dbdesc_send, on, 0, &on->thread_send_dbdesc); - - return 0; } -int bad_lsreq(struct thread *thread) +void bad_lsreq(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa, *lsanext; @@ -549,7 +541,7 @@ int bad_lsreq(struct thread *thread) assert(on); if (on->state < OSPF6_NEIGHBOR_EXCHANGE) - return 0; + return; if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) zlog_debug("Neighbor Event %s: *BadLSReq*", on->name); @@ -574,10 +566,9 @@ int bad_lsreq(struct thread *thread) thread_add_event(master, ospf6_dbdesc_send, on, 0, &on->thread_send_dbdesc); - return 0; } -int oneway_received(struct thread *thread) +void oneway_received(struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa, *lsanext; @@ -586,7 +577,7 @@ int oneway_received(struct thread *thread) assert(on); if (on->state < OSPF6_NEIGHBOR_TWOWAY) - return 0; + return; if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) zlog_debug("Neighbor Event %s: *1Way-Received*", on->name); @@ -608,11 +599,9 @@ int oneway_received(struct thread *thread) THREAD_OFF(on->thread_send_lsack); THREAD_OFF(on->thread_exchange_done); THREAD_OFF(on->thread_adj_ok); - - return 0; } -int inactivity_timer(struct thread *thread) +void inactivity_timer(struct thread *thread) { struct ospf6_neighbor *on; @@ -648,8 +637,6 @@ int inactivity_timer(struct thread *thread) on->ospf6_if->dead_interval, &on->inactivity_timer); } - - return 0; } @@ -935,8 +922,44 @@ static void ospf6_neighbor_show_detail(struct vty *vty, bfd_sess_show(vty, json_neighbor, on->bfd_session); - json_object_object_add(json, on->name, json_neighbor); + if (on->auth_present == true) { + json_object_string_add(json_neighbor, "authStatus", + "enabled"); + json_object_int_add( + json_neighbor, "recvdHelloHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]); + json_object_int_add( + json_neighbor, "recvdHelloLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]); + json_object_int_add( + json_neighbor, "recvdDBDescHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]); + json_object_int_add( + json_neighbor, "recvdDBDescLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]); + json_object_int_add( + json_neighbor, "recvdLSReqHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]); + json_object_int_add( + json_neighbor, "recvdLSReqLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]); + json_object_int_add( + json_neighbor, "recvdLSUpdHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]); + json_object_int_add( + json_neighbor, "recvdLSUpdLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]); + json_object_int_add( + json_neighbor, "recvdLSAckHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]); + json_object_int_add( + json_neighbor, "recvdLSAckLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]); + } else + json_object_string_add(json_neighbor, "authStatus", + "disabled"); + json_object_object_add(json, on->name, json_neighbor); } else { vty_out(vty, " Neighbor %s\n", on->name); @@ -1022,6 +1045,27 @@ static void ospf6_neighbor_show_detail(struct vty *vty, vty_out(vty, " %s\n", lsa->name); bfd_sess_show(vty, NULL, on->bfd_session); + + if (on->auth_present == true) { + vty_out(vty, " Authentication header present\n"); + vty_out(vty, + "\t\t\t hello DBDesc LSReq LSUpd LSAck\n"); + vty_out(vty, + " Higher sequence no 0x%-10X 0x%-10X 0x%-10X 0x%-10X 0x%-10X\n", + on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO], + on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]); + vty_out(vty, + " Lower sequence no 0x%-10X 0x%-10X 0x%-10X 0x%-10X 0x%-10X\n", + on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO], + on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]); + } else + vty_out(vty, " Authentication header not present\n"); } } diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index de59a1ccf..ea4d42415 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -144,6 +144,14 @@ struct ospf6_neighbor { /* ospf6 graceful restart HELPER info */ struct ospf6_helper_info gr_helper_info; + + /* seqnum_h/l is used to compare sequence + * number in received packet Auth header + */ + uint32_t seqnum_h[OSPF6_MESSAGE_TYPE_MAX]; + uint32_t seqnum_l[OSPF6_MESSAGE_TYPE_MAX]; + bool auth_present; + bool lls_present; }; /* Neighbor state */ @@ -197,16 +205,16 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, void ospf6_neighbor_delete(struct ospf6_neighbor *on); /* Neighbor event */ -extern int hello_received(struct thread *thread); -extern int twoway_received(struct thread *thread); -extern int negotiation_done(struct thread *thread); -extern int exchange_done(struct thread *thread); -extern int loading_done(struct thread *thread); -extern int adj_ok(struct thread *thread); -extern int seqnumber_mismatch(struct thread *thread); -extern int bad_lsreq(struct thread *thread); -extern int oneway_received(struct thread *thread); -extern int inactivity_timer(struct thread *thread); +extern void hello_received(struct thread *thread); +extern void twoway_received(struct thread *thread); +extern void negotiation_done(struct thread *thread); +extern void exchange_done(struct thread *thread); +extern void loading_done(struct thread *thread); +extern void adj_ok(struct thread *thread); +extern void seqnumber_mismatch(struct thread *thread); +extern void bad_lsreq(struct thread *thread); +extern void oneway_received(struct thread *thread); +extern void inactivity_timer(struct thread *thread); extern void ospf6_check_nbr_loading(struct ospf6_neighbor *on); extern void ospf6_neighbor_init(void); diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 5961cfe66..7501f49fe 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -33,6 +33,7 @@ #include "ospf6_top.h" #include "ospf6_network.h" #include "ospf6d.h" +#include "ospf6_message.h" struct in6_addr allspfrouters6; struct in6_addr alldrouters6; @@ -60,20 +61,6 @@ static void ospf6_set_transport_class(int ospf6_sock) #endif } -static void ospf6_set_checksum(int ospf6_sock) -{ - int offset = 12; -#ifndef DISABLE_IPV6_CHECKSUM - if (setsockopt(ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, - sizeof(offset)) - < 0) - zlog_warn("Network: set IPV6_CHECKSUM failed: %s", - safe_strerror(errno)); -#else - zlog_warn("Network: Don't set IPV6_CHECKSUM"); -#endif /* DISABLE_IPV6_CHECKSUM */ -} - void ospf6_serv_close(int *ospf6_sock) { if (*ospf6_sock != -1) { @@ -113,7 +100,6 @@ int ospf6_serv_sock(struct ospf6 *ospf6) ospf6_reset_mcastloop(ospf6_sock); ospf6_set_pktinfo(ospf6_sock); ospf6_set_transport_class(ospf6_sock); - ospf6_set_checksum(ospf6_sock); ospf6->fd = ospf6_sock; /* setup global in6_addr, allspf6 and alldr6 for later use */ diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c index 042907d0f..1220c3278 100644 --- a/ospf6d/ospf6_nssa.c +++ b/ospf6d/ospf6_nssa.c @@ -970,7 +970,7 @@ int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route, } /* This function performs ABR related processing */ -static int ospf6_abr_task_timer(struct thread *thread) +static void ospf6_abr_task_timer(struct thread *thread) { struct ospf6 *ospf6 = THREAD_ARG(thread); @@ -982,8 +982,6 @@ static int ospf6_abr_task_timer(struct thread *thread) ospf6_abr_task(ospf6); /* if nssa-abr, then scan Type-7 LSDB */ ospf6_abr_nssa_task(ospf6); - - return 0; } void ospf6_schedule_abr_task(struct ospf6 *ospf6) diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c index e60d2c7e0..4d0c4ee59 100644 --- a/ospf6d/ospf6_proto.c +++ b/ospf6d/ospf6_proto.c @@ -82,12 +82,16 @@ void ospf6_capability_printbuf(char capability, char *buf, int size) void ospf6_options_printbuf(uint8_t *options, char *buf, int size) { - const char *dc, *r, *n, *mc, *e, *v6; + const char *dc, *r, *n, *mc, *e, *v6, *af, *at, *l; dc = (OSPF6_OPT_ISSET(options, OSPF6_OPT_DC) ? "DC" : "--"); r = (OSPF6_OPT_ISSET(options, OSPF6_OPT_R) ? "R" : "-"); n = (OSPF6_OPT_ISSET(options, OSPF6_OPT_N) ? "N" : "-"); mc = (OSPF6_OPT_ISSET(options, OSPF6_OPT_MC) ? "MC" : "--"); e = (OSPF6_OPT_ISSET(options, OSPF6_OPT_E) ? "E" : "-"); v6 = (OSPF6_OPT_ISSET(options, OSPF6_OPT_V6) ? "V6" : "--"); - snprintf(buf, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6); + af = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_AF) ? "AF" : "--"); + at = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_AT) ? "AT" : "--"); + l = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_L) ? "L" : "-"); + snprintf(buf, size, "%s|%s|%s|-|-|%s|%s|%s|%s|%s|%s", at, l, af, dc, r, + n, mc, e, v6); } diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h index b98dc38b7..ea476b3a8 100644 --- a/ospf6d/ospf6_proto.h +++ b/ospf6d/ospf6_proto.h @@ -40,13 +40,20 @@ /* OSPF options */ /* present in HELLO, DD, LSA */ -#define OSPF6_OPT_SET(x,opt) ((x)[2] |= (opt)) -#define OSPF6_OPT_ISSET(x,opt) ((x)[2] & (opt)) -#define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt)) +#define OSPF6_OPT_SET(x, opt) ((x)[2] |= (opt)) +#define OSPF6_OPT_ISSET(x, opt) ((x)[2] & (opt)) +#define OSPF6_OPT_CLEAR(x, opt) ((x)[2] &= ~(opt)) +#define OSPF6_OPT_SET_EXT(x, opt) ((x)[1] |= (opt)) +#define OSPF6_OPT_ISSET_EXT(x, opt) ((x)[1] & (opt)) +#define OSPF6_OPT_CLEAR_EXT(x, opt) ((x)[1] &= ~(opt)) #define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0) +#define OSPF6_OPT_AT (1 << 2) /* Authentication trailer Capability */ +#define OSPF6_OPT_L (1 << 1) /* Link local signalling Capability */ +#define OSPF6_OPT_AF (1 << 0) /* Address family Capability */ +/* 2 bits reserved for OSPFv2 migrated options */ #define OSPF6_OPT_DC (1 << 5) /* Demand Circuit handling Capability */ -#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ +#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ #define OSPF6_OPT_N (1 << 3) /* Handling Type-7 LSA Capability */ #define OSPF6_OPT_MC (1 << 2) /* Multicasting Capability */ #define OSPF6_OPT_E (1 << 1) /* AS External Capability */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index f5d60d80f..3c74ca55c 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -1168,7 +1168,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route, json_object *json_routes, bool use_json) { char destination[PREFIX2STR_BUFFER], nexthop[64]; - char area_id[16], id[16], adv_router[16], capa[16], options[16]; + char area_id[16], id[16], adv_router[16], capa[16], options[32]; char pfx_options[16]; struct timeval now, res; char duration[64]; @@ -1653,7 +1653,7 @@ static void ospf6_linkstate_show_header(struct vty *vty) static void ospf6_linkstate_show(struct vty *vty, struct ospf6_route *route) { uint32_t router, id; - char routername[16], idname[16], rbits[16], options[16]; + char routername[16], idname[16], rbits[16], options[32]; router = ospf6_linkstate_prefix_adv_router(&route->prefix); inet_ntop(AF_INET, &router, routername, sizeof(routername)); @@ -1779,7 +1779,7 @@ void ospf6_brouter_show_header(struct vty *vty) void ospf6_brouter_show(struct vty *vty, struct ospf6_route *route) { uint32_t adv_router; - char adv[16], rbits[16], options[16], area[16]; + char adv[16], rbits[16], options[32], area[16]; adv_router = ospf6_linkstate_prefix_adv_router(&route->prefix); inet_ntop(AF_INET, &adv_router, adv, sizeof(adv)); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index f9c47cbce..2e8e9f2cd 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -605,7 +605,7 @@ static void ospf6_spf_log_database(struct ospf6_area *oa) zlog_debug("%s", buffer); } -static int ospf6_spf_calculation_thread(struct thread *t) +static void ospf6_spf_calculation_thread(struct thread *t) { struct ospf6_area *oa; struct ospf6 *ospf6; @@ -681,7 +681,6 @@ static int ospf6_spf_calculation_thread(struct thread *t) ospf6->last_spf_reason = ospf6->spf_reason; ospf6_reset_spf_reason(ospf6); - return 0; } /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we @@ -1245,7 +1244,7 @@ int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa, return 0; } -static int ospf6_ase_calculate_timer(struct thread *t) +static void ospf6_ase_calculate_timer(struct thread *t) { struct ospf6 *ospf6; struct ospf6_lsa *lsa; @@ -1283,8 +1282,6 @@ static int ospf6_ase_calculate_timer(struct thread *t) ospf6_zebra_gr_disable(ospf6); ospf6->gr_info.finishing_restart = false; } - - return 0; } void ospf6_ase_calculate_timer_add(struct ospf6 *ospf6) diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 6c707e355..2a6d7cd09 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -54,6 +54,7 @@ #include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top"); @@ -445,6 +446,17 @@ static struct ospf6 *ospf6_create(const char *name) /* Make ospf protocol socket. */ ospf6_serv_sock(o); + /* If sequence number is stored in persistent storage, read it. + */ + if (ospf6_auth_nvm_file_exist() == OSPF6_AUTH_FILE_EXIST) { + ospf6_auth_seqno_nvm_read(o); + o->seqnum_h = o->seqnum_h + 1; + ospf6_auth_seqno_nvm_update(o); + } else { + o->seqnum_l = o->seqnum_h = 0; + ospf6_auth_seqno_nvm_update(o); + } + return o; } @@ -574,7 +586,7 @@ void ospf6_master_init(struct thread_master *master) om6->master = master; } -static int ospf6_maxage_remover(struct thread *thread) +static void ospf6_maxage_remover(struct thread *thread) { struct ospf6 *o = (struct ospf6 *)THREAD_ARG(thread); struct ospf6_area *oa; @@ -591,7 +603,7 @@ static int ospf6_maxage_remover(struct thread *thread) continue; ospf6_maxage_remove(o); - return 0; + return; } } } @@ -615,8 +627,6 @@ static int ospf6_maxage_remover(struct thread *thread) if (reschedule) { ospf6_maxage_remove(o); } - - return 0; } void ospf6_maxage_remove(struct ospf6 *o) @@ -1386,6 +1396,10 @@ static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json, json_object_int_add(json, "numberOfAreaInRouter", listcount(o->area_list)); + json_object_int_add(json, "AuthTrailerHigherSeqNo", + o->seqnum_h); + json_object_int_add(json, "AuthTrailerLowerSeqNo", o->seqnum_l); + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) @@ -1466,6 +1480,10 @@ static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json, vty_out(vty, " Number of areas in this router is %u\n", listcount(o->area_list)); + vty_out(vty, " Authentication Sequence number info\n"); + vty_out(vty, " Higher sequence no %u, Lower sequence no %u\n", + o->seqnum_h, o->seqnum_l); + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) @@ -2130,7 +2148,7 @@ DEFPY (show_ipv6_ospf6_external_aggregator, VRF_CMD_HELP_STR "All VRFs\n" "Show external summary addresses\n" - "detailed informtion\n" + "detailed information\n" JSON_STR) { bool uj = use_json(argc, argv); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index b9f7235b4..f06a3254a 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -228,6 +228,8 @@ struct ospf6 { /* Action for aggregation of external LSAs */ int aggr_action; + uint32_t seqnum_l; /* lower order Sequence Number */ + uint32_t seqnum_h; /* higher order Sequence Number */ #define OSPF6_EXTL_AGGR_DEFAULT_DELAY 5 /* For ASBR summary delay timer */ uint16_t aggr_delay_interval; diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 82d280811..4b37c5bc2 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -166,19 +166,20 @@ static int ospf6_zebra_import_check_update(ZAPI_CALLBACK_ARGS) { struct ospf6 *ospf6; struct zapi_route nhr; + struct prefix matched; ospf6 = ospf6_lookup_by_vrf_id(vrf_id); if (ospf6 == NULL || !IS_OSPF6_ASBR(ospf6)) return 0; - if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { zlog_err("%s[%u]: Failure to decode route", __func__, ospf6->vrf_id); return -1; } - if (nhr.prefix.family != AF_INET6 || nhr.prefix.prefixlen != 0 - || nhr.type == ZEBRA_ROUTE_OSPF6) + if (matched.family != AF_INET6 || matched.prefixlen != 0 || + nhr.type == ZEBRA_ROUTE_OSPF6) return 0; ospf6->nssa_default_import_check.status = !!nhr.nexthop_num; @@ -354,7 +355,7 @@ DEFUN(show_zebra, vty_json(vty, json); } else { - vty_out(vty, "Zebra Infomation\n"); + vty_out(vty, "Zebra Information\n"); vty_out(vty, " fail: %d\n", zclient->fail); vty_out(vty, " redistribute default: %d\n", vrf_bitmap_check(zclient->default_information[AFI_IP6], diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index cc5a0f787..a16f4f73e 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -48,6 +48,7 @@ #include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" +#include "ospf6_auth_trailer.h" DEFINE_MGROUP(OSPF6D, "ospf6d"); @@ -98,6 +99,7 @@ static int config_write_ospf6_debug(struct vty *vty) config_write_ospf6_debug_flood(vty); config_write_ospf6_debug_nssa(vty); config_write_ospf6_debug_gr_helper(vty); + config_write_ospf6_debug_auth(vty); return 0; } @@ -1458,4 +1460,7 @@ void ospf6_init(struct thread_master *master) VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd); + install_element_ospf6_debug_auth(); + ospf6_interface_auth_trailer_cmd_init(); + install_element_ospf6_clear_intf_auth(); } diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index 34aabc205..cf863ff52 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -24,6 +24,7 @@ vtysh_scan += \ ospf6d/ospf6_top.c \ ospf6d/ospf6_zebra.c \ ospf6d/ospf6d.c \ + ospf6d/ospf6_auth_trailer.c \ # end vtysh_daemons += ospf6d if SNMP @@ -56,6 +57,7 @@ ospf6d_libospf6_a_SOURCES = \ ospf6d/ospf6_top.c \ ospf6d/ospf6_zebra.c \ ospf6d/ospf6d.c \ + ospf6d/ospf6_auth_trailer.c \ # end noinst_HEADERS += \ @@ -80,6 +82,7 @@ noinst_HEADERS += \ ospf6d/ospf6_top.h \ ospf6d/ospf6_zebra.h \ ospf6d/ospf6d.h \ + ospf6d/ospf6_auth_trailer.h \ # end ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la $(LIBCAP) diff --git a/ospfclient/ospfclient.c b/ospfclient/ospfclient.c index 3ca1e132b..3cfee7d57 100644 --- a/ospfclient/ospfclient.c +++ b/ospfclient/ospfclient.c @@ -82,7 +82,7 @@ struct my_opaque_lsa { * --------------------------------------------------------- */ -static int lsa_delete(struct thread *t) +static void lsa_delete(struct thread *t) { struct ospf_apiclient *oclient; struct in_addr area_id; @@ -93,7 +93,7 @@ static int lsa_delete(struct thread *t) rc = inet_aton(args[6], &area_id); if (rc <= 0) { printf("Address Specified: %s is invalid\n", args[6]); - return rc; + return; } printf("Deleting LSA... "); @@ -102,10 +102,9 @@ static int lsa_delete(struct thread *t) atoi(args[3]), /* opaque type */ atoi(args[4])); /* opaque ID */ printf("done, return code is = %d\n", rc); - return rc; } -static int lsa_inject(struct thread *t) +static void lsa_inject(struct thread *t) { struct ospf_apiclient *cl; struct in_addr ifaddr; @@ -124,13 +123,13 @@ static int lsa_inject(struct thread *t) rc = inet_aton(args[5], &ifaddr); if (rc <= 0) { printf("Ifaddr specified %s is invalid\n", args[5]); - return rc; + return; } rc = inet_aton(args[6], &area_id); if (rc <= 0) { printf("Area ID specified %s is invalid\n", args[6]); - return rc; + return; } lsa_type = atoi(args[2]); opaque_type = atoi(args[3]); @@ -146,14 +145,12 @@ static int lsa_inject(struct thread *t) printf("done, return code is %d\n", rc); counter++; - - return 0; } /* This thread handles asynchronous messages coming in from the OSPF API server */ -static int lsa_read(struct thread *thread) +static void lsa_read(struct thread *thread) { struct ospf_apiclient *oclient; int fd; @@ -173,8 +170,6 @@ static int lsa_read(struct thread *thread) /* Reschedule read thread */ thread_add_read(master, lsa_read, oclient, fd, NULL); - - return 0; } /* --------------------------------------------------------- diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 8e59bd9eb..7aa3a27c6 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -1829,7 +1829,7 @@ void ospf_abr_task(struct ospf *ospf) zlog_debug("ospf_abr_task(): Stop"); } -static int ospf_abr_task_timer(struct thread *thread) +static void ospf_abr_task_timer(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); @@ -1843,8 +1843,6 @@ static int ospf_abr_task_timer(struct thread *thread) ospf_abr_task(ospf); ospf_abr_nssa_task(ospf); /* if nssa-abr, then scan Type-7 LSDB */ - - return 0; } void ospf_schedule_abr_task(struct ospf *ospf) diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index a33ca9577..a624f4ce1 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -278,7 +278,7 @@ struct ospf_apiserver *ospf_apiserver_new(int fd_sync, int fd_async) return new; } -void ospf_apiserver_event(enum event event, int fd, +void ospf_apiserver_event(enum ospf_apiserver_event event, int fd, struct ospf_apiserver *apiserv) { switch (event) { @@ -362,13 +362,12 @@ void ospf_apiserver_free(struct ospf_apiserver *apiserv) XFREE(MTYPE_OSPF_APISERVER, apiserv); } -int ospf_apiserver_read(struct thread *thread) +void ospf_apiserver_read(struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; int fd; - int rc = -1; - enum event event; + enum ospf_apiserver_event event; apiserv = THREAD_ARG(thread); fd = THREAD_FD(thread); @@ -396,7 +395,7 @@ int ospf_apiserver_read(struct thread *thread) else { zlog_warn("ospf_apiserver_read: Unknown fd(%d)", fd); ospf_apiserver_free(apiserv); - goto out; + return; } /* Read message from fd. */ @@ -408,25 +407,22 @@ int ospf_apiserver_read(struct thread *thread) /* Perform cleanup. */ ospf_apiserver_free(apiserv); - goto out; + return; } if (IS_DEBUG_OSPF_EVENT) msg_print(msg); /* Dispatch to corresponding message handler. */ - rc = ospf_apiserver_handle_msg(apiserv, msg); + ospf_apiserver_handle_msg(apiserv, msg); /* Prepare for next message, add read thread. */ ospf_apiserver_event(event, fd, apiserv); msg_free(msg); - -out: - return rc; } -int ospf_apiserver_sync_write(struct thread *thread) +void ospf_apiserver_sync_write(struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; @@ -455,7 +451,7 @@ int ospf_apiserver_sync_write(struct thread *thread) if (!msg) { zlog_warn( "API: ospf_apiserver_sync_write: No message in Sync-FIFO?"); - return 0; + return; } if (IS_DEBUG_OSPF_EVENT) @@ -485,12 +481,10 @@ out: /* Perform cleanup and disconnect with peer */ ospf_apiserver_free(apiserv); } - - return rc; } -int ospf_apiserver_async_write(struct thread *thread) +void ospf_apiserver_async_write(struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; @@ -519,7 +513,7 @@ int ospf_apiserver_async_write(struct thread *thread) if (!msg) { zlog_warn( "API: ospf_apiserver_async_write: No message in Async-FIFO?"); - return 0; + return; } if (IS_DEBUG_OSPF_EVENT) @@ -549,8 +543,6 @@ out: /* Perform cleanup and disconnect with peer */ ospf_apiserver_free(apiserv); } - - return rc; } @@ -593,7 +585,7 @@ int ospf_apiserver_serv_sock_family(unsigned short port, int family) /* Accept connection request from external applications. For each accepted connection allocate own connection instance. */ -int ospf_apiserver_accept(struct thread *thread) +void ospf_apiserver_accept(struct thread *thread) { int accept_sock; int new_sync_sock; @@ -617,7 +609,7 @@ int ospf_apiserver_accept(struct thread *thread) if (new_sync_sock < 0) { zlog_warn("ospf_apiserver_accept: accept: %s", safe_strerror(errno)); - return -1; + return; } /* Get port address and port number of peer to make reverse connection. @@ -632,7 +624,7 @@ int ospf_apiserver_accept(struct thread *thread) zlog_warn("ospf_apiserver_accept: getpeername: %s", safe_strerror(errno)); close(new_sync_sock); - return -1; + return; } if (IS_DEBUG_OSPF_EVENT) @@ -652,7 +644,7 @@ int ospf_apiserver_accept(struct thread *thread) &peer_async.sin_addr, ntohs(peer_async.sin_port)); close(new_sync_sock); - return -1; + return; } new_async_sock = socket(AF_INET, SOCK_STREAM, 0); @@ -660,7 +652,7 @@ int ospf_apiserver_accept(struct thread *thread) zlog_warn("ospf_apiserver_accept: socket: %s", safe_strerror(errno)); close(new_sync_sock); - return -1; + return; } ret = connect(new_async_sock, (struct sockaddr *)&peer_async, @@ -671,7 +663,7 @@ int ospf_apiserver_accept(struct thread *thread) safe_strerror(errno)); close(new_sync_sock); close(new_async_sock); - return -1; + return; } #ifdef USE_ASYNC_READ @@ -683,7 +675,7 @@ int ospf_apiserver_accept(struct thread *thread) safe_strerror(errno)); close(new_sync_sock); close(new_async_sock); - return -1; + return; } #endif /* USE_ASYNC_READ */ @@ -705,8 +697,6 @@ int ospf_apiserver_accept(struct thread *thread) if (IS_DEBUG_OSPF_EVENT) zlog_debug("API: New apiserv(%p), total#(%d)", (void *)apiserv, apiserver_list->count); - - return 0; } @@ -720,7 +710,7 @@ static int ospf_apiserver_send_msg(struct ospf_apiserver *apiserv, { struct msg_fifo *fifo; struct msg *msg2; - enum event event; + enum ospf_apiserver_event event; int fd; switch (msg->hdr.msgtype) { diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h index 544a32a28..3d5773708 100644 --- a/ospfd/ospf_apiserver.h +++ b/ospfd/ospf_apiserver.h @@ -68,7 +68,7 @@ struct ospf_apiserver { struct thread *t_async_write; }; -enum event { +enum ospf_apiserver_event { OSPF_APISERVER_ACCEPT, OSPF_APISERVER_SYNC_READ, #ifdef USE_ASYNC_READ @@ -88,13 +88,13 @@ extern int ospf_apiserver_init(void); extern void ospf_apiserver_term(void); extern struct ospf_apiserver *ospf_apiserver_new(int fd_sync, int fd_async); extern void ospf_apiserver_free(struct ospf_apiserver *apiserv); -extern void ospf_apiserver_event(enum event event, int fd, +extern void ospf_apiserver_event(enum ospf_apiserver_event event, int fd, struct ospf_apiserver *apiserv); extern int ospf_apiserver_serv_sock_family(unsigned short port, int family); -extern int ospf_apiserver_accept(struct thread *thread); -extern int ospf_apiserver_read(struct thread *thread); -extern int ospf_apiserver_sync_write(struct thread *thread); -extern int ospf_apiserver_async_write(struct thread *thread); +extern void ospf_apiserver_accept(struct thread *thread); +extern void ospf_apiserver_read(struct thread *thread); +extern void ospf_apiserver_sync_write(struct thread *thread); +extern void ospf_apiserver_async_write(struct thread *thread); extern int ospf_apiserver_send_reply(struct ospf_apiserver *apiserv, uint32_t seqnr, uint8_t rc); diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 8cb85b462..70581b908 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -207,7 +207,7 @@ struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf, struct as_external_lsa *al; struct in_addr mask, id; - /* Fisrt search the lsdb with address specifc LSID + /* First search the lsdb with address specific LSID * where all the host bits are set, if there a matched * LSA, return. * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255 @@ -223,8 +223,15 @@ struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf, id.s_addr = p->prefix.s_addr | (~mask.s_addr); lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA, id, ospf->router_id); - if (lsa) + if (lsa) { + if (p->prefixlen == IPV4_MAX_BITLEN) { + al = (struct as_external_lsa *)lsa->data; + + if (mask.s_addr != al->mask.s_addr) + return NULL; + } return lsa; + } lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA, p->prefix, ospf->router_id); @@ -272,7 +279,7 @@ void ospf_asbr_status_update(struct ospf *ospf, uint8_t status) /* If there's redistribution configured, we need to refresh external * LSAs in order to install Type-7 and flood to all NSSA Areas */ -static int ospf_asbr_nssa_redist_update_timer(struct thread *thread) +static void ospf_asbr_nssa_redist_update_timer(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); int type; @@ -298,8 +305,6 @@ static int ospf_asbr_nssa_redist_update_timer(struct thread *thread) } ospf_external_lsa_refresh_default(ospf); - - return 0; } void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf) @@ -623,7 +628,7 @@ struct ospf_lsa *ospf_originate_summary_lsa(struct ospf *ospf, ospf_link_ei_to_aggr(aggr, ei); lsa = ospf_external_info_find_lsa(ospf, &aggr->p); - /* Dont originate external LSA, + /* Don't originate external LSA, * If it is configured not to advertise. */ if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) { @@ -780,12 +785,12 @@ static void ospf_handle_aggregated_exnl_rt(struct ospf *ospf, /* Handling the case where the external route prefix * and aggregate prefix is same - * If same dont flush the originated external LSA. + * If same don't flush the originated external LSA. */ if (prefix_same((struct prefix *)&aggr->p, (struct prefix *)&ei->p)) { if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR)) zlog_debug( - "%s: External Route prefix same as Aggregator(%pI4/%d), so dont flush.", + "%s: External Route prefix same as Aggregator(%pI4/%d), so don't flush.", __func__, &ei->p.prefix, ei->p.prefixlen); return; } @@ -1057,7 +1062,7 @@ static void ospf_handle_external_aggr_update(struct ospf *ospf) } } -static int ospf_asbr_external_aggr_process(struct thread *thread) +static void ospf_asbr_external_aggr_process(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); int operation = 0; @@ -1079,8 +1084,6 @@ static int ospf_asbr_external_aggr_process(struct thread *thread) default: break; } - - return OSPF_SUCCESS; } static void ospf_external_aggr_timer(struct ospf *ospf, struct ospf_external_aggr_rt *aggr, diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index e9fb891d7..23c7a1e70 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -564,7 +564,7 @@ static int ospf_ase_compare_tables(struct ospf *ospf, return 0; } -static int ospf_ase_calculate_timer(struct thread *t) +static void ospf_ase_calculate_timer(struct thread *t) { struct ospf *ospf; struct ospf_lsa *lsa; @@ -631,8 +631,6 @@ static int ospf_ase_calculate_timer(struct thread *t) ospf_zebra_gr_disable(ospf); ospf->gr_info.finishing_restart = false; } - - return 0; } void ospf_ase_calculate_schedule(struct ospf *ospf) diff --git a/ospfd/ospf_gr.c b/ospfd/ospf_gr.c index 6bfe48145..2521f2fce 100644 --- a/ospfd/ospf_gr.c +++ b/ospfd/ospf_gr.c @@ -510,14 +510,12 @@ void ospf_gr_check_adjs(struct ospf *ospf) } /* Handling of grace period expiry. */ -static int ospf_gr_grace_period_expired(struct thread *thread) +static void ospf_gr_grace_period_expired(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); ospf->gr_info.t_grace_period = NULL; ospf_gr_restart_exit(ospf, "grace period has expired"); - - return 0; } /* @@ -732,7 +730,7 @@ DEFPY(graceful_restart_prepare, graceful_restart_prepare_cmd, "Graceful Restart commands\n" "Prepare upcoming graceful restart\n" IP_STR - "Prepare to restart the OSPF process") + "Prepare to restart the OSPF process\n") { struct ospf *ospf; struct listnode *node; diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c index ae002fdc9..92236cf44 100644 --- a/ospfd/ospf_gr_helper.c +++ b/ospfd/ospf_gr_helper.c @@ -346,14 +346,13 @@ static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa, * Returns: * Nothing */ -static int ospf_handle_grace_timer_expiry(struct thread *thread) +static void ospf_handle_grace_timer_expiry(struct thread *thread) { struct ospf_neighbor *nbr = THREAD_ARG(thread); nbr->gr_helper_info.t_grace_timer = NULL; ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT); - return OSPF_GR_SUCCESS; } /* @@ -847,8 +846,8 @@ void ospf_gr_helper_support_set(struct ospf *ospf, bool support) lookup.advRtrAddr.s_addr = nbr->router_id.s_addr; /* check if helper support enabled for the - * corresponding routerid.If enabled, dont - * dont exit from helper role. + * corresponding routerid.If enabled, don't + * exit from helper role. */ if (hash_lookup(ospf->enable_rtr_list, &lookup)) continue; diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 299e753cc..2626cccc3 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -845,6 +845,8 @@ int ospf_if_down(struct ospf_interface *oi) /* Shutdown packet reception and sending */ ospf_if_stream_unset(oi); + if (!ospf->new_table) + return 1; for (rn = route_top(ospf->new_table); rn; rn = route_next(rn)) { or = rn->info; diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 1850d946b..97da61034 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -248,7 +248,7 @@ int ospf_dr_election(struct ospf_interface *oi) } -int ospf_hello_timer(struct thread *thread) +void ospf_hello_timer(struct thread *thread) { struct ospf_interface *oi; @@ -263,11 +263,9 @@ int ospf_hello_timer(struct thread *thread) /* Hello timer set. */ OSPF_HELLO_TIMER_ON(oi); - - return 0; } -static int ospf_wait_timer(struct thread *thread) +static void ospf_wait_timer(struct thread *thread) { struct ospf_interface *oi; @@ -278,8 +276,6 @@ static int ospf_wait_timer(struct thread *thread) zlog_debug("ISM[%s]: Timer (Wait timer expire)", IF_NAME(oi)); OSPF_ISM_EVENT_SCHEDULE(oi, ISM_WaitTimer); - - return 0; } /* Hook function called after ospf ISM event is occurred. And vty's @@ -575,7 +571,7 @@ static void ism_change_state(struct ospf_interface *oi, int state) } /* Execute ISM event process. */ -int ospf_ism_event(struct thread *thread) +void ospf_ism_event(struct thread *thread) { int event; int next_state; @@ -601,6 +597,4 @@ int ospf_ism_event(struct thread *thread) /* Make sure timer is set. */ ism_timer_set(oi); - - return 0; } diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h index 5d0f95aed..35fbd15d0 100644 --- a/ospfd/ospf_ism.h +++ b/ospfd/ospf_ism.h @@ -90,9 +90,9 @@ thread_execute(master, ospf_ism_event, (I), (E)) /* Prototypes. */ -extern int ospf_ism_event(struct thread *); +extern void ospf_ism_event(struct thread *thread); extern void ism_change_status(struct ospf_interface *, int); -extern int ospf_hello_timer(struct thread *thread); +extern void ospf_hello_timer(struct thread *thread); extern int ospf_dr_election(struct ospf_interface *oi); DECLARE_HOOK(ospf_ism_change, diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index df691bf4d..f6c1b4361 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -353,7 +353,7 @@ static int ospf_ldp_sync_ism_change(struct ospf_interface *oi, int state, /* * LDP-SYNC holddown timer routines */ -static int ospf_ldp_sync_holddown_timer(struct thread *thread) +static void ospf_ldp_sync_holddown_timer(struct thread *thread) { struct interface *ifp; struct ospf_if_params *params; @@ -375,7 +375,6 @@ static int ospf_ldp_sync_holddown_timer(struct thread *thread) ospf_if_recalculate_output_cost(ifp); } - return 0; } void ospf_ldp_sync_holddown_timer_add(struct interface *ifp) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index c169996e0..48751dfba 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -53,6 +53,29 @@ #include "ospfd/ospf_abr.h" #include "ospfd/ospf_errors.h" +static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf, + struct prefix_ipv4 *p, + uint8_t type, + uint32_t metric, + struct in_addr old_id); +static struct ospf_lsa * +ospf_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric, + struct ospf_area *area, struct in_addr id); +static struct ospf_lsa *ospf_summary_lsa_refresh(struct ospf *ospf, + struct ospf_lsa *lsa); +static struct ospf_lsa * +ospf_asbr_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric, + struct ospf_area *area, + struct in_addr id); +static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf, + struct ospf_lsa *lsa); +static struct ospf_lsa *ospf_handle_exnl_lsa_lsId_chg(struct ospf *ospf, + struct external_info *ei, + struct in_addr id); +static struct ospf_lsa * +ospf_exnl_lsa_prepare_and_flood(struct ospf *ospf, struct external_info *ei, + struct in_addr id); + uint32_t get_metric(uint8_t *metric) { uint32_t m; @@ -711,7 +734,7 @@ void ospf_router_lsa_body_set(struct stream **s, struct ospf_area *area) stream_putw_at(*s, putp, cnt); } -static int ospf_stub_router_timer(struct thread *t) +static void ospf_stub_router_timer(struct thread *t) { struct ospf_area *area = THREAD_ARG(t); @@ -723,13 +746,11 @@ static int ospf_stub_router_timer(struct thread *t) * clobber an administratively set stub-router state though. */ if (CHECK_FLAG(area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) - return 0; + return; UNSET_FLAG(area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); ospf_router_lsa_update_area(area); - - return 0; } static void ospf_stub_router_check(struct ospf_area *area) @@ -1221,31 +1242,11 @@ static struct ospf_lsa *ospf_summary_lsa_new(struct ospf_area *area, } /* Originate Summary-LSA. */ -struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p, - uint32_t metric, - struct ospf_area *area) +static struct ospf_lsa * +ospf_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric, + struct ospf_area *area, struct in_addr id) { struct ospf_lsa *new; - struct in_addr id; - - if (area->ospf->gr_info.restart_in_progress) { - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "LSA[Type%d]: Graceful Restart in progress, don't originate", - OSPF_SUMMARY_LSA); - return NULL; - } - - id = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p); - - if (id.s_addr == 0xffffffff) { - /* Maybe Link State ID not available. */ - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "LSA[Type%d]: Link ID not available, can't originate", - OSPF_SUMMARY_LSA); - return NULL; - } /* Create new summary-LSA instance. */ if (!(new = ospf_summary_lsa_new(area, (struct prefix *)p, metric, id))) @@ -1270,6 +1271,97 @@ struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p, return new; } +static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf, + struct prefix_ipv4 *p, + uint8_t type, + uint32_t metric, + struct in_addr old_id) +{ + struct ospf_lsa *lsa = NULL; + struct ospf_lsa *new = NULL; + struct summary_lsa *sl = NULL; + struct ospf_area *old_area = NULL; + struct prefix_ipv4 old_prefix; + uint32_t old_metric; + struct in_addr mask; + uint32_t metric_val; + char *metric_buf; + + lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, p->prefix, + ospf->router_id); + + if (!lsa) { + flog_warn(EC_OSPF_LSA_NULL, "(%s): LSA not found", __func__); + return NULL; + } + + sl = (struct summary_lsa *)lsa->data; + + old_area = lsa->area; + old_metric = GET_METRIC(sl->metric); + old_prefix.prefix = sl->header.id; + old_prefix.prefixlen = ip_masklen(sl->mask); + old_prefix.family = AF_INET; + + + /* change the mask */ + masklen2ip(p->prefixlen, &mask); + sl->mask.s_addr = mask.s_addr; + + /* Copy the metric*/ + metric_val = htonl(metric); + metric_buf = (char *)&metric_val; + memcpy(sl->metric, metric_buf, sizeof(metric_val)); + + if (type == OSPF_SUMMARY_LSA) { + /*Refresh the LSA with new LSA*/ + ospf_summary_lsa_refresh(ospf, lsa); + + new = ospf_summary_lsa_prepare_and_flood( + &old_prefix, old_metric, old_area, old_id); + } else { + /*Refresh the LSA with new LSA*/ + ospf_summary_asbr_lsa_refresh(ospf, lsa); + + new = ospf_asbr_summary_lsa_prepare_and_flood( + &old_prefix, old_metric, old_area, old_id); + } + + return new; +} + +/* Originate Summary-LSA. */ +struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p, + uint32_t metric, + struct ospf_area *area) +{ + struct in_addr id; + enum lsid_status status; + struct ospf_lsa *new = NULL; + + status = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p, + &id); + + if (status == LSID_CHANGE) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug("Link ID has to be changed."); + + new = ospf_handle_summarylsa_lsId_chg( + area->ospf, p, OSPF_SUMMARY_LSA, metric, id); + return new; + } else if (status == LSID_NOT_AVAILABLE) { + /* Link State ID not available. */ + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type5]: Link ID not available, can't originate"); + + return NULL; + } + + new = ospf_summary_lsa_prepare_and_flood(p, metric, area, id); + return new; +} + static struct ospf_lsa *ospf_summary_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa) { @@ -1370,32 +1462,12 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_new(struct ospf_area *area, } /* Originate summary-ASBR-LSA. */ -struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p, - uint32_t metric, - struct ospf_area *area) +static struct ospf_lsa * +ospf_asbr_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric, + struct ospf_area *area, + struct in_addr id) { struct ospf_lsa *new; - struct in_addr id; - - if (area->ospf->gr_info.restart_in_progress) { - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "LSA[Type%d]: Graceful Restart in progress, don't originate", - OSPF_ASBR_SUMMARY_LSA); - return NULL; - } - - id = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_ASBR_SUMMARY_LSA, - p); - - if (id.s_addr == 0xffffffff) { - /* Maybe Link State ID not available. */ - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "LSA[Type%d]: Link ID not available, can't originate", - OSPF_ASBR_SUMMARY_LSA); - return NULL; - } /* Create new summary-LSA instance. */ new = ospf_summary_asbr_lsa_new(area, (struct prefix *)p, metric, id); @@ -1421,6 +1493,37 @@ struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p, return new; } +struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p, + uint32_t metric, + struct ospf_area *area) +{ + struct ospf_lsa *new; + struct in_addr id; + enum lsid_status status; + + status = ospf_lsa_unique_id(area->ospf, area->lsdb, + OSPF_ASBR_SUMMARY_LSA, p, &id); + + if (status == LSID_CHANGE) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug("Link ID has to be changed."); + + new = ospf_handle_summarylsa_lsId_chg( + area->ospf, p, OSPF_ASBR_SUMMARY_LSA, metric, id); + return new; + } else if (status == LSID_NOT_AVAILABLE) { + /* Link State ID not available. */ + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type5]: Link ID not available, can't originate"); + + return NULL; + } + + new = ospf_asbr_summary_lsa_prepare_and_flood(p, metric, area, id); + return new; +} + static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa) { @@ -1612,42 +1715,15 @@ static void ospf_external_lsa_body_set(struct stream *s, } /* Create new external-LSA. */ -static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf, - struct external_info *ei, - struct in_addr *old_id) +static struct ospf_lsa * +ospf_exnl_lsa_prepare_and_flood(struct ospf *ospf, struct external_info *ei, + struct in_addr id) { struct stream *s; struct lsa_header *lsah; struct ospf_lsa *new; - struct in_addr id; int length; - if (ei == NULL) { - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "LSA[Type5]: External info is NULL, can't originate"); - return NULL; - } - - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug("LSA[Type5]: Originate AS-external-LSA instance"); - - /* If old Link State ID is specified, refresh LSA with same ID. */ - if (old_id) - id = *old_id; - /* Get Link State with unique ID. */ - else { - id = ospf_lsa_unique_id(ospf, ospf->lsdb, OSPF_AS_EXTERNAL_LSA, - &ei->p); - if (id.s_addr == 0xffffffff) { - /* Maybe Link State ID not available. */ - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "LSA[Type5]: Link ID not available, can't originate"); - return NULL; - } - } - /* Create new stream for LSA. */ s = stream_new(OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *)STREAM_DATA(s); @@ -1677,6 +1753,99 @@ static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf, return new; } +static struct ospf_lsa *ospf_handle_exnl_lsa_lsId_chg(struct ospf *ospf, + struct external_info *ei, + struct in_addr id) +{ + struct ospf_lsa *lsa; + struct as_external_lsa *al; + struct in_addr mask; + struct ospf_lsa *new; + struct external_info ei_summary; + struct external_info *ei_old; + + lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA, + ei->p.prefix, ospf->router_id); + + if (!lsa) { + flog_warn(EC_OSPF_LSA_NULL, "(%s): LSA not found", __func__); + return NULL; + } + + ei_old = ospf_external_info_check(ospf, lsa); + + al = (struct as_external_lsa *)lsa->data; + + if (!ei_old) { + /* eii_old pointer of LSA is NULL, this + * must be external aggregate route. + */ + ei_summary.p.family = AF_INET; + ei_summary.p.prefix = al->header.id; + ei_summary.p.prefixlen = ip_masklen(al->mask); + ei_summary.tag = (unsigned long)ntohl(al->e[0].route_tag); + ei_old = &ei_summary; + } + + /* change the mask */ + masklen2ip(ei->p.prefixlen, &mask); + al->mask.s_addr = mask.s_addr; + + /*Refresh the LSA with new LSA*/ + ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 0); + + /*Originate the old LSA with changed LSID*/ + new = ospf_exnl_lsa_prepare_and_flood(ospf, ei_old, id); + + return new; +} + +static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf, + struct external_info *ei, + struct in_addr *old_id) +{ + struct ospf_lsa *new; + struct in_addr id; + enum lsid_status status; + + if (ei == NULL) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type5]: External info is NULL, can't originate"); + return NULL; + } + + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug("LSA[Type5]: Originate AS-external-LSA instance"); + + /* If old Link State ID is specified, refresh LSA with same ID. */ + if (old_id) + id = *old_id; + /* Get Link State with unique ID. */ + else { + status = ospf_lsa_unique_id(ospf, ospf->lsdb, + OSPF_AS_EXTERNAL_LSA, &ei->p, &id); + + if (status == LSID_CHANGE) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug("Link ID has to be changed."); + + new = ospf_handle_exnl_lsa_lsId_chg(ospf, ei, id); + return new; + } else if (status == LSID_NOT_AVAILABLE) { + /* Link State ID not available. */ + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type5]: Link ID not available, can't originate"); + return NULL; + } + } + + new = ospf_exnl_lsa_prepare_and_flood(ospf, ei, id); + + return new; +} + /* As Type-7 */ static void ospf_install_flood_nssa(struct ospf *ospf, struct ospf_lsa *lsa, struct external_info *ei) @@ -2184,7 +2353,7 @@ void ospf_external_lsa_rid_change(struct ospf *ospf) continue; if (!ospf_external_lsa_originate(ospf, - NULL)) + ei)) flog_warn( EC_OSPF_LSA_INSTALL_FAILURE, "LSA: AS-external-LSA was not originated."); @@ -2854,7 +3023,7 @@ int ospf_check_nbr_status(struct ospf *ospf) } -static int ospf_maxage_lsa_remover(struct thread *thread) +static void ospf_maxage_lsa_remover(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); struct ospf_lsa *lsa, *old; @@ -2891,7 +3060,7 @@ static int ospf_maxage_lsa_remover(struct thread *thread) ospf_maxage_lsa_remover, 0); route_unlock_node( rn); /* route_top/route_next */ - return 0; + return; } /* Remove LSA from the LSDB */ @@ -2947,8 +3116,6 @@ static int ospf_maxage_lsa_remover(struct thread *thread) if (reschedule) OSPF_TIMER_ON(ospf->t_maxage, ospf_maxage_lsa_remover, ospf->maxage_delay); - - return 0; } /* This function checks whether an LSA with initial sequence number should be @@ -2983,7 +3150,7 @@ void ospf_lsa_maxage_delete(struct ospf *ospf, struct ospf_lsa *lsa) struct prefix lsa_prefix; memset(&lsa_prefix, 0, sizeof(struct prefix)); - lsa_prefix.family = 0; + lsa_prefix.family = AF_UNSPEC; lsa_prefix.prefixlen = sizeof(lsa_prefix.u.ptr) * CHAR_BIT; lsa_prefix.u.ptr = (uintptr_t)lsa; @@ -3024,7 +3191,7 @@ void ospf_lsa_maxage(struct ospf *ospf, struct ospf_lsa *lsa) } memset(&lsa_prefix, 0, sizeof(struct prefix)); - lsa_prefix.family = 0; + lsa_prefix.family = AF_UNSPEC; lsa_prefix.prefixlen = sizeof(lsa_prefix.u.ptr) * CHAR_BIT; lsa_prefix.u.ptr = (uintptr_t)lsa; @@ -3104,7 +3271,7 @@ static int ospf_lsa_maxage_walker_remover(struct ospf *ospf, } /* Periodical check of MaxAge LSA. */ -int ospf_lsa_maxage_walker(struct thread *thread) +void ospf_lsa_maxage_walker(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); struct route_node *rn; @@ -3141,7 +3308,6 @@ int ospf_lsa_maxage_walker(struct thread *thread) OSPF_TIMER_ON(ospf->t_maxage_walker, ospf_lsa_maxage_walker, OSPF_LSA_MAXAGE_CHECK_INTERVAL); - return 0; } struct ospf_lsa *ospf_lsa_lookup_by_prefix(struct ospf_lsdb *lsdb, uint8_t type, @@ -3509,49 +3675,87 @@ int ospf_lsa_is_self_originated(struct ospf *ospf, struct ospf_lsa *lsa) } /* Get unique Link State ID. */ -struct in_addr ospf_lsa_unique_id(struct ospf *ospf, struct ospf_lsdb *lsdb, - uint8_t type, struct prefix_ipv4 *p) +enum lsid_status ospf_lsa_unique_id(struct ospf *ospf, struct ospf_lsdb *lsdb, + uint8_t type, struct prefix_ipv4 *p, + struct in_addr *id) { struct ospf_lsa *lsa; - struct in_addr mask, id; + struct in_addr mask; - id = p->prefix; + *id = p->prefix; /* Check existence of LSA instance. */ - lsa = ospf_lsdb_lookup_by_id(lsdb, type, id, ospf->router_id); + lsa = ospf_lsdb_lookup_by_id(lsdb, type, *id, ospf->router_id); if (lsa) { struct as_external_lsa *al = (struct as_external_lsa *)lsa->data; + /* Ref rfc2328,Appendex E.1 + * If router already originated the external lsa with lsid + * as the current prefix, and the masklens are same then + * terminate the LSID algorithem. + */ if (ip_masklen(al->mask) == p->prefixlen) { if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) zlog_debug( - "ospf_lsa_unique_id(): Can't get Link State ID for %pFX", - p); + "%s: Can't get Link State ID for %pFX", + __func__, p); /* id.s_addr = 0; */ - id.s_addr = 0xffffffff; - return id; - } - /* Masklen differs, then apply wildcard mask to Link State ID. - */ - else { + id->s_addr = 0xffffffff; + return LSID_NOT_AVAILABLE; + } else if (ip_masklen(al->mask) < p->prefixlen) { + /* Ref rfc2328,Appendex E.2 + * the current prefix masklen is greater than the + * existing LSA, then generate the Link state ID, + * by setting all host bits in prefix addressa and + * originate. + * + * Eg: 1st Route : 10.0.0.0/16 - LSID:10.0.0.0 + * 2nd Route : 10.0.0.0/24 - LSID:10.0.0.255 + */ masklen2ip(p->prefixlen, &mask); - id.s_addr = p->prefix.s_addr | (~mask.s_addr); - lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, id, + id->s_addr = p->prefix.s_addr | (~mask.s_addr); + lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, *id, ospf->router_id); if (lsa) { if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) zlog_debug( - "ospf_lsa_unique_id(): Can't get Link State ID for %pFX", - p); - /* id.s_addr = 0; */ - id.s_addr = 0xffffffff; - return id; + "%s: Can't get Link State ID for %pFX", + __func__, p); + id->s_addr = 0xffffffff; + return LSID_NOT_AVAILABLE; + } + } else { + /* Ref rfc2328,Appendex E.3 + * the current prefix masklen is lesser than the + * existing LSA,then the originated LSA has to be + * refreshed by modifying masklen, cost and tag. + * Originate the old route info with new LSID by + * setting the host bits in prefix address. + * + * Eg: 1st Route : 10.0.0.0/24 - LSID:10.0.0.0 + * 2nd Route : 10.0.0.0/16 - ? + * Since 2nd route mask len is less than firstone + * LSID has to be changed. + * 1st route LSID:10.0.0.255 + * 2nd route LSID:10.0.0.0 + */ + id->s_addr = lsa->data->id.s_addr | (~al->mask.s_addr); + lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, *id, + ospf->router_id); + if (lsa && (ip_masklen(al->mask) != IPV4_MAX_BITLEN)) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "%s: Can't get Link State ID for %pFX", + __func__, p); + id->s_addr = 0xffffffff; + return LSID_NOT_AVAILABLE; } + return LSID_CHANGE; } } - return id; + return LSID_AVAILABLE; } @@ -3564,7 +3768,7 @@ struct lsa_action { struct ospf_lsa *lsa; }; -static int ospf_lsa_action(struct thread *t) +static void ospf_lsa_action(struct thread *t) { struct lsa_action *data; @@ -3585,7 +3789,6 @@ static int ospf_lsa_action(struct thread *t) ospf_lsa_unlock(&data->lsa); /* Message */ XFREE(MTYPE_OSPF_MESSAGE, data); - return 0; } void ospf_schedule_lsa_flood_area(struct ospf_area *area, struct ospf_lsa *lsa) @@ -3756,7 +3959,7 @@ void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa) } } -int ospf_lsa_refresh_walker(struct thread *t) +void ospf_lsa_refresh_walker(struct thread *t) { struct list *refresh_list; struct listnode *node, *nnode; @@ -3835,8 +4038,6 @@ int ospf_lsa_refresh_walker(struct thread *t) if (IS_DEBUG_OSPF(lsa, LSA_REFRESH)) zlog_debug("LSA[Refresh]: ospf_lsa_refresh_walker(): end"); - - return 0; } /* Flush the LSAs for the specific area */ diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index a97957371..4b3be1538 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -208,6 +208,8 @@ struct as_external_lsa { } e[1]; }; +enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE }; + #include "ospfd/ospf_opaque.h" /* Macros. */ @@ -306,7 +308,7 @@ extern struct ospf_lsa *ospf_lsa_lookup_by_prefix(struct ospf_lsdb *, uint8_t, extern void ospf_lsa_maxage(struct ospf *, struct ospf_lsa *); extern uint32_t get_metric(uint8_t *); -extern int ospf_lsa_maxage_walker(struct thread *); +extern void ospf_lsa_maxage_walker(struct thread *thread); extern struct ospf_lsa *ospf_lsa_refresh(struct ospf *, struct ospf_lsa *); extern void ospf_external_lsa_refresh_default(struct ospf *); @@ -317,14 +319,16 @@ extern struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *, struct ospf_lsa *, struct external_info *, int, bool aggr); -extern struct in_addr ospf_lsa_unique_id(struct ospf *, struct ospf_lsdb *, - uint8_t, struct prefix_ipv4 *); +extern enum lsid_status ospf_lsa_unique_id(struct ospf *ospf, + struct ospf_lsdb *lsdb, + uint8_t type, struct prefix_ipv4 *p, + struct in_addr *addr); extern void ospf_schedule_lsa_flood_area(struct ospf_area *, struct ospf_lsa *); extern void ospf_schedule_lsa_flush_area(struct ospf_area *, struct ospf_lsa *); extern void ospf_refresher_register_lsa(struct ospf *, struct ospf_lsa *); extern void ospf_refresher_unregister_lsa(struct ospf *, struct ospf_lsa *); -extern int ospf_lsa_refresh_walker(struct thread *); +extern void ospf_lsa_refresh_walker(struct thread *thread); extern void ospf_lsa_maxage_delete(struct ospf *, struct ospf_lsa *); diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index 86eb14131..b0881c098 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -70,7 +70,7 @@ void ospf_lsdb_cleanup(struct ospf_lsdb *lsdb) void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa) { if (lp && lsa && lsa->data) { - lp->family = 0; + lp->family = AF_UNSPEC; lp->prefixlen = 64; lp->id = lsa->data->id; lp->adv_router = lsa->data->adv_router; @@ -199,7 +199,7 @@ struct ospf_lsa *ospf_lsdb_lookup_by_id(struct ospf_lsdb *lsdb, uint8_t type, table = lsdb->type[type].db; memset(&lp, 0, sizeof(struct prefix_ls)); - lp.family = 0; + lp.family = AF_UNSPEC; lp.prefixlen = 64; lp.id = id; lp.adv_router = adv_router; @@ -226,7 +226,7 @@ struct ospf_lsa *ospf_lsdb_lookup_by_id_next(struct ospf_lsdb *lsdb, table = lsdb->type[type].db; memset(&lp, 0, sizeof(struct prefix_ls)); - lp.family = 0; + lp.family = AF_UNSPEC; lp.prefixlen = 64; lp.id = id; lp.adv_router = adv_router; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index e3cf1cfc8..c538d1a09 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -59,7 +59,7 @@ DEFINE_HOOK(ospf_nsm_change, static void nsm_clear_adj(struct ospf_neighbor *); /* OSPF NSM Timer functions. */ -static int ospf_inactivity_timer(struct thread *thread) +static void ospf_inactivity_timer(struct thread *thread) { struct ospf_neighbor *nbr; @@ -84,11 +84,9 @@ static int ospf_inactivity_timer(struct thread *thread) OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer, nbr->v_inactivity); } - - return 0; } -static int ospf_db_desc_timer(struct thread *thread) +static void ospf_db_desc_timer(struct thread *thread) { struct ospf_neighbor *nbr; @@ -106,8 +104,6 @@ static int ospf_db_desc_timer(struct thread *thread) /* DD Retransmit timer set. */ OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); - - return 0; } /* Hook function called after ospf NSM event is occurred. @@ -776,7 +772,7 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) } /* Execute NSM event process. */ -int ospf_nsm_event(struct thread *thread) +void ospf_nsm_event(struct thread *thread) { int event; int next_state; @@ -846,8 +842,6 @@ int ospf_nsm_event(struct thread *thread) */ if (nbr->state == NSM_Deleted) ospf_nbr_delete(nbr); - - return 0; } /* Check loading state. */ diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h index 798325f79..0b40b1f42 100644 --- a/ospfd/ospf_nsm.h +++ b/ospfd/ospf_nsm.h @@ -70,7 +70,7 @@ thread_execute(master, ospf_nsm_event, (N), (E)) /* Prototypes. */ -extern int ospf_nsm_event(struct thread *); +extern void ospf_nsm_event(struct thread *); extern void ospf_check_nbr_loading(struct ospf_neighbor *); extern int ospf_db_summary_isempty(struct ospf_neighbor *); extern int ospf_db_summary_count(struct ospf_neighbor *); diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 4670316db..b781c9edc 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -1286,9 +1286,9 @@ out: * Followings are Opaque-LSA origination/refresh management functions. *------------------------------------------------------------------------*/ -static int ospf_opaque_type9_lsa_originate(struct thread *t); -static int ospf_opaque_type10_lsa_originate(struct thread *t); -static int ospf_opaque_type11_lsa_originate(struct thread *t); +static void ospf_opaque_type9_lsa_originate(struct thread *t); +static void ospf_opaque_type10_lsa_originate(struct thread *t); +static void ospf_opaque_type11_lsa_originate(struct thread *t); static void ospf_opaque_lsa_reoriginate_resume(struct list *listtop, void *arg); void ospf_opaque_lsa_originate_schedule(struct ospf_interface *oi, int *delay0) @@ -1460,10 +1460,9 @@ void ospf_opaque_lsa_originate_schedule(struct ospf_interface *oi, int *delay0) *delay0 = delay; } -static int ospf_opaque_type9_lsa_originate(struct thread *t) +static void ospf_opaque_type9_lsa_originate(struct thread *t) { struct ospf_interface *oi; - int rc; oi = THREAD_ARG(t); oi->t_opaque_lsa_self = NULL; @@ -1472,15 +1471,12 @@ static int ospf_opaque_type9_lsa_originate(struct thread *t) zlog_debug("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s", IF_NAME(oi)); - rc = opaque_lsa_originate_callback(ospf_opaque_type9_funclist, oi); - - return rc; + opaque_lsa_originate_callback(ospf_opaque_type9_funclist, oi); } -static int ospf_opaque_type10_lsa_originate(struct thread *t) +static void ospf_opaque_type10_lsa_originate(struct thread *t) { struct ospf_area *area; - int rc; area = THREAD_ARG(t); area->t_opaque_lsa_self = NULL; @@ -1490,15 +1486,12 @@ static int ospf_opaque_type10_lsa_originate(struct thread *t) "Timer[Type10-LSA]: Originate Opaque-LSAs for Area %pI4", &area->area_id); - rc = opaque_lsa_originate_callback(ospf_opaque_type10_funclist, area); - - return rc; + opaque_lsa_originate_callback(ospf_opaque_type10_funclist, area); } -static int ospf_opaque_type11_lsa_originate(struct thread *t) +static void ospf_opaque_type11_lsa_originate(struct thread *t) { struct ospf *top; - int rc; top = THREAD_ARG(t); top->t_opaque_lsa_self = NULL; @@ -1507,9 +1500,7 @@ static int ospf_opaque_type11_lsa_originate(struct thread *t) zlog_debug( "Timer[Type11-LSA]: Originate AS-External Opaque-LSAs"); - rc = opaque_lsa_originate_callback(ospf_opaque_type11_funclist, top); - - return rc; + opaque_lsa_originate_callback(ospf_opaque_type11_funclist, top); } static void ospf_opaque_lsa_reoriginate_resume(struct list *listtop, void *arg) @@ -1665,10 +1656,10 @@ struct ospf_lsa *ospf_opaque_lsa_refresh(struct ospf_lsa *lsa) static struct ospf_lsa *pseudo_lsa(struct ospf_interface *oi, struct ospf_area *area, uint8_t lsa_type, uint8_t opaque_type); -static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t); -static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t); -static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t); -static int ospf_opaque_lsa_refresh_timer(struct thread *t); +static void ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t); +static void ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t); +static void ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t); +static void ospf_opaque_lsa_refresh_timer(struct thread *t); void ospf_opaque_lsa_reoriginate_schedule(void *lsa_type_dependent, uint8_t lsa_type, uint8_t opaque_type) @@ -1679,7 +1670,7 @@ void ospf_opaque_lsa_reoriginate_schedule(void *lsa_type_dependent, struct ospf_lsa *lsa; struct opaque_info_per_type *oipt; - int (*func)(struct thread * t) = NULL; + void (*func)(struct thread * t) = NULL; int delay; switch (lsa_type) { @@ -1846,13 +1837,12 @@ static struct ospf_lsa *pseudo_lsa(struct ospf_interface *oi, return &lsa; } -static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t) +static void ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct ospf *top; struct ospf_interface *oi; - int rc = -1; oipt = THREAD_ARG(t); @@ -1861,7 +1851,7 @@ static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t) flog_warn( EC_OSPF_LSA, "ospf_opaque_type9_lsa_reoriginate_timer: No associated function?"); - goto out; + return; } oi = (struct ospf_interface *)oipt->owner; @@ -1869,7 +1859,7 @@ static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t) flog_warn( EC_OSPF_LSA, "ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?"); - goto out; + return; } if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE) @@ -1881,8 +1871,7 @@ static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t) oipt->opaque_type); oipt->status = PROC_SUSPEND; - rc = 0; - goto out; + return; } if (IS_DEBUG_OSPF_EVENT) @@ -1890,12 +1879,10 @@ static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t) "Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)", oipt->opaque_type, IF_NAME(oi)); - rc = (*functab->lsa_originator)(oi); -out: - return rc; + (*functab->lsa_originator)(oi); } -static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t) +static void ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; @@ -1903,7 +1890,7 @@ static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t) struct ospf *top; struct ospf_area *area; struct ospf_interface *oi; - int n, rc = -1; + int n; oipt = THREAD_ARG(t); @@ -1912,7 +1899,7 @@ static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t) flog_warn( EC_OSPF_LSA, "ospf_opaque_type10_lsa_reoriginate_timer: No associated function?"); - goto out; + return; } area = (struct ospf_area *)oipt->owner; @@ -1920,7 +1907,7 @@ static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t) flog_warn( EC_OSPF_LSA, "ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?"); - goto out; + return; } /* There must be at least one "opaque-capable, full-state" neighbor. */ @@ -1937,8 +1924,7 @@ static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t) oipt->opaque_type); oipt->status = PROC_SUSPEND; - rc = 0; - goto out; + return; } if (IS_DEBUG_OSPF_EVENT) @@ -1946,17 +1932,14 @@ static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t) "Timer[Type10-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for Area %pI4", oipt->opaque_type, &area->area_id); - rc = (*functab->lsa_originator)(area); -out: - return rc; + (*functab->lsa_originator)(area); } -static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t) +static void ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct ospf *top; - int rc = -1; oipt = THREAD_ARG(t); @@ -1965,14 +1948,14 @@ static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t) flog_warn( EC_OSPF_LSA, "ospf_opaque_type11_lsa_reoriginate_timer: No associated function?"); - goto out; + return; } if ((top = (struct ospf *)oipt->owner) == NULL) { flog_warn( EC_OSPF_LSA, "ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?"); - goto out; + return; } if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE)) { @@ -1982,8 +1965,7 @@ static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t) oipt->opaque_type); oipt->status = PROC_SUSPEND; - rc = 0; - goto out; + return; } if (IS_DEBUG_OSPF_EVENT) @@ -1991,9 +1973,7 @@ static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t) "Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).", oipt->opaque_type); - rc = (*functab->lsa_originator)(top); -out: - return rc; + (*functab->lsa_originator)(top); } void ospf_opaque_lsa_refresh_schedule(struct ospf_lsa *lsa0) @@ -2064,7 +2044,7 @@ out: return; } -static int ospf_opaque_lsa_refresh_timer(struct thread *t) +static void ospf_opaque_lsa_refresh_timer(struct thread *t) { struct opaque_info_per_id *oipi; struct ospf_opaque_functab *functab; @@ -2079,8 +2059,6 @@ static int ospf_opaque_lsa_refresh_timer(struct thread *t) if ((functab = oipi->opqctl_type->functab) != NULL) if (functab->lsa_refresher != NULL) (*functab->lsa_refresher)(lsa); - - return 0; } void ospf_opaque_lsa_flush_schedule(struct ospf_lsa *lsa0) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index e17e53109..c2bd7a079 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -449,7 +449,7 @@ static int ospf_make_md5_digest(struct ospf_interface *oi, } -static int ospf_ls_req_timer(struct thread *thread) +static void ospf_ls_req_timer(struct thread *thread) { struct ospf_neighbor *nbr; @@ -462,8 +462,6 @@ static int ospf_ls_req_timer(struct thread *thread) /* Set Link State Request retransmission timer. */ OSPF_NSM_TIMER_ON(nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req); - - return 0; } void ospf_ls_req_event(struct ospf_neighbor *nbr) @@ -474,7 +472,7 @@ void ospf_ls_req_event(struct ospf_neighbor *nbr) /* Cyclic timer function. Fist registered in ospf_nbr_new () in ospf_neighbor.c */ -int ospf_ls_upd_timer(struct thread *thread) +void ospf_ls_upd_timer(struct thread *thread) { struct ospf_neighbor *nbr; @@ -530,11 +528,9 @@ int ospf_ls_upd_timer(struct thread *thread) /* Set LS Update retransmission timer. */ OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); - - return 0; } -int ospf_ls_ack_timer(struct thread *thread) +void ospf_ls_ack_timer(struct thread *thread) { struct ospf_interface *oi; @@ -547,8 +543,6 @@ int ospf_ls_ack_timer(struct thread *thread) /* Set LS Ack timer. */ OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); - - return 0; } #ifdef WANT_OSPF_WRITE_FRAGMENT @@ -625,7 +619,7 @@ static void ospf_write_frags(int fd, struct ospf_packet *op, struct ip *iph, } #endif /* WANT_OSPF_WRITE_FRAGMENT */ -static int ospf_write(struct thread *thread) +static void ospf_write(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); struct ospf_interface *oi; @@ -657,7 +651,7 @@ static int ospf_write(struct thread *thread) zlog_debug( "ospf_write failed to send, fd %d, instance %u", ospf->fd, ospf->oi_running); - return -1; + return; } node = listhead(ospf->oi_write_q); @@ -876,8 +870,6 @@ static int ospf_write(struct thread *thread) if (!list_isempty(ospf->oi_write_q)) thread_add_write(master, ospf_write, ospf, ospf->fd, &ospf->t_write); - - return 0; } /* OSPF Hello message read -- RFC2328 Section 10.5. */ @@ -3215,7 +3207,7 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf) } /* Starting point of packet process function. */ -int ospf_read(struct thread *thread) +void ospf_read(struct thread *thread) { struct ospf *ospf; int32_t count = 0; @@ -3232,13 +3224,11 @@ int ospf_read(struct thread *thread) ret = ospf_read_helper(ospf); switch (ret) { case OSPF_READ_ERROR: - return -1; + return; case OSPF_READ_CONTINUE: break; } } - - return 0; } /* Make OSPF header. */ @@ -3747,7 +3737,7 @@ static void ospf_poll_send(struct ospf_nbr_nbma *nbr_nbma) ospf_hello_send_sub(oi, nbr_nbma->addr.s_addr); } -int ospf_poll_timer(struct thread *thread) +void ospf_poll_timer(struct thread *thread) { struct ospf_nbr_nbma *nbr_nbma; @@ -3763,12 +3753,10 @@ int ospf_poll_timer(struct thread *thread) if (nbr_nbma->v_poll > 0) OSPF_POLL_TIMER_ON(nbr_nbma->t_poll, ospf_poll_timer, nbr_nbma->v_poll); - - return 0; } -int ospf_hello_reply_timer(struct thread *thread) +void ospf_hello_reply_timer(struct thread *thread) { struct ospf_neighbor *nbr; @@ -3780,8 +3768,6 @@ int ospf_hello_reply_timer(struct thread *thread) IF_NAME(nbr->oi), &nbr->router_id); ospf_hello_send_sub(nbr->oi, nbr->address.u.prefix4.s_addr); - - return 0; } /* Send OSPF Hello. */ @@ -4124,7 +4110,7 @@ static void ospf_ls_upd_queue_send(struct ospf_interface *oi, } } -static int ospf_ls_upd_send_queue_event(struct thread *thread) +static void ospf_ls_upd_send_queue_event(struct thread *thread) { struct ospf_interface *oi = THREAD_ARG(thread); struct route_node *rn; @@ -4167,8 +4153,6 @@ static int ospf_ls_upd_send_queue_event(struct thread *thread) if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_ls_upd_send_queue stop"); - - return 0; } void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag, @@ -4272,7 +4256,7 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, OSPF_ISM_WRITE_ON(oi->ospf); } -static int ospf_ls_ack_send_event(struct thread *thread) +static void ospf_ls_ack_send_event(struct thread *thread) { struct ospf_interface *oi = THREAD_ARG(thread); @@ -4281,8 +4265,6 @@ static int ospf_ls_ack_send_event(struct thread *thread) while (listcount(oi->ls_ack_direct.ls_ack)) ospf_ls_ack_send_list(oi, oi->ls_ack_direct.ls_ack, oi->ls_ack_direct.dst); - - return 0; } void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h index 72b87edaf..cefc9c21b 100644 --- a/ospfd/ospf_packet.h +++ b/ospfd/ospf_packet.h @@ -139,7 +139,7 @@ extern struct ospf_packet *ospf_fifo_head(struct ospf_fifo *); extern void ospf_fifo_flush(struct ospf_fifo *); extern void ospf_fifo_free(struct ospf_fifo *); -extern int ospf_read(struct thread *); +extern void ospf_read(struct thread *thread); extern void ospf_hello_send(struct ospf_interface *); extern void ospf_db_desc_send(struct ospf_neighbor *); extern void ospf_db_desc_resend(struct ospf_neighbor *); @@ -152,10 +152,10 @@ extern void ospf_ls_ack_send_delayed(struct ospf_interface *); extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event(struct ospf_neighbor *); -extern int ospf_ls_upd_timer(struct thread *); -extern int ospf_ls_ack_timer(struct thread *); -extern int ospf_poll_timer(struct thread *); -extern int ospf_hello_reply_timer(struct thread *); +extern void ospf_ls_upd_timer(struct thread *thread); +extern void ospf_ls_ack_timer(struct thread *thread); +extern void ospf_poll_timer(struct thread *thread); +extern void ospf_hello_reply_timer(struct thread *thread); extern const struct message ospf_packet_type_str[]; extern const size_t ospf_packet_type_str_max; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 7ec3db789..bf3755686 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -1779,7 +1779,7 @@ static int ospf_snmp_vl_add(struct ospf_vl_data *vl_data) struct route_node *rn; memset(&lp, 0, sizeof(struct prefix_ls)); - lp.family = 0; + lp.family = AF_UNSPEC; lp.prefixlen = 64; lp.id = vl_data->vl_area_id; lp.adv_router = vl_data->vl_peer; @@ -1798,7 +1798,7 @@ static int ospf_snmp_vl_delete(struct ospf_vl_data *vl_data) struct route_node *rn; memset(&lp, 0, sizeof(struct prefix_ls)); - lp.family = 0; + lp.family = AF_UNSPEC; lp.prefixlen = 64; lp.id = vl_data->vl_area_id; lp.adv_router = vl_data->vl_peer; @@ -1820,7 +1820,7 @@ static struct ospf_vl_data *ospf_snmp_vl_lookup(struct in_addr *area_id, struct ospf_vl_data *vl_data; memset(&lp, 0, sizeof(struct prefix_ls)); - lp.family = 0; + lp.family = AF_UNSPEC; lp.prefixlen = 64; lp.id = *area_id; lp.adv_router = *neighbor; @@ -1843,7 +1843,7 @@ static struct ospf_vl_data *ospf_snmp_vl_lookup_next(struct in_addr *area_id, struct ospf_vl_data *vl_data; memset(&lp, 0, sizeof(struct prefix_ls)); - lp.family = 0; + lp.family = AF_UNSPEC; lp.prefixlen = 64; lp.id = *area_id; lp.adv_router = *neighbor; diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 8b4d55984..f76340021 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1809,7 +1809,7 @@ void ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table, } /* Worker for SPF calculation scheduler. */ -static int ospf_spf_calculate_schedule_worker(struct thread *thread) +static void ospf_spf_calculate_schedule_worker(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); struct route_table *new_table, *new_rtrs; @@ -1929,8 +1929,6 @@ static int ospf_spf_calculate_schedule_worker(struct thread *thread) } ospf_clear_spf_reason_flags(); - - return 0; } /* diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 181cc37f4..e4059d05c 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -470,7 +470,7 @@ int ospf_sr_local_block_release_label(mpls_label_t label) * * @return 1 on success */ -static int sr_start_label_manager(struct thread *start) +static void sr_start_label_manager(struct thread *start) { struct ospf *ospf; @@ -478,8 +478,6 @@ static int sr_start_label_manager(struct thread *start) /* re-attempt to start SR & Label Manager connection */ ospf_sr_start(ospf); - - return 1; } /* Segment Routing starter function */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 97b581dae..da90435c5 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -652,20 +652,22 @@ DEFUN (ospf_area_range, DEFUN (ospf_area_range_cost, ospf_area_range_cost_cmd, - "area range A.B.C.D/M cost (0-16777215)", + "area range A.B.C.D/M {cost (0-16777215)|substitute A.B.C.D/M}", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "User specified metric for this range\n" - "Advertised metric for this range\n") + "Advertised metric for this range\n" + "Announce area range as another prefix\n" + "Network prefix to be announced instead of range\n") { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_ipv4_prefixlen = 3; - int idx_cost = 5; - struct prefix_ipv4 p; + int idx = 4; + struct prefix_ipv4 p, s; struct in_addr area_id; int format; uint32_t cost; @@ -677,8 +679,16 @@ DEFUN (ospf_area_range_cost, ospf_area_display_format_set(ospf, ospf_area_get(ospf, area_id), format); - cost = strtoul(argv[idx_cost]->arg, NULL, 10); - ospf_area_range_cost_set(ospf, area_id, &p, cost); + if (argv_find(argv, argc, "cost", &idx)) { + cost = strtoul(argv[idx + 1]->arg, NULL, 10); + ospf_area_range_cost_set(ospf, area_id, &p, cost); + } + + idx = 4; + if (argv_find(argv, argc, "substitute", &idx)) { + str2prefix_ipv4(argv[idx + 1]->arg, &s); + ospf_area_range_substitute_set(ospf, area_id, &p, &s); + } return CMD_SUCCESS; } @@ -742,36 +752,6 @@ DEFUN (no_ospf_area_range, return CMD_SUCCESS; } -DEFUN (ospf_area_range_substitute, - ospf_area_range_substitute_cmd, - "area range A.B.C.D/M substitute A.B.C.D/M", - "OSPF area parameters\n" - "OSPF area ID in IP address format\n" - "OSPF area ID as a decimal value\n" - "Summarize routes matching address/mask (border routers only)\n" - "Area range prefix\n" - "Announce area range as another prefix\n" - "Network prefix to be announced instead of range\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - int idx_ipv4_number = 1; - int idx_ipv4_prefixlen = 3; - int idx_ipv4_prefixlen_2 = 5; - struct prefix_ipv4 p, s; - struct in_addr area_id; - int format; - - VTY_GET_OSPF_AREA_ID(area_id, format, argv[idx_ipv4_number]->arg); - str2prefix_ipv4(argv[idx_ipv4_prefixlen]->arg, &p); - str2prefix_ipv4(argv[idx_ipv4_prefixlen_2]->arg, &s); - - ospf_area_range_substitute_set(ospf, area_id, &p, &s); - ospf_area_display_format_set(ospf, ospf_area_get(ospf, area_id), - format); - - return CMD_SUCCESS; -} - DEFUN (no_ospf_area_range_substitute, no_ospf_area_range_substitute_cmd, "no area range A.B.C.D/M substitute A.B.C.D/M", @@ -6578,7 +6558,7 @@ static void show_lsa_prefix_set(struct vty *vty, struct prefix_ls *lp, struct in_addr *id, struct in_addr *adv_router) { memset(lp, 0, sizeof(struct prefix_ls)); - lp->family = 0; + lp->family = AF_UNSPEC; if (id == NULL) lp->prefixlen = 0; else if (adv_router == NULL) { @@ -9725,7 +9705,7 @@ DEFUN (ospf_max_metric_router_lsa_startup, unsigned int seconds; if (argc < 4) { - vty_out(vty, "%% Must supply stub-router period"); + vty_out(vty, "%% Must supply stub-router period\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -9781,7 +9761,7 @@ DEFUN (ospf_max_metric_router_lsa_shutdown, unsigned int seconds; if (argc < 4) { - vty_out(vty, "%% Must supply stub-router shutdown period"); + vty_out(vty, "%% Must supply stub-router shutdown period\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -10430,7 +10410,7 @@ DEFPY (show_ip_ospf_gr_helper, "All VRFs\n" "OSPF Graceful Restart\n" "Helper details in the router\n" - "Detailed informtion\n" + "Detailed information\n" JSON_STR) { char *vrf_name = NULL; @@ -11575,7 +11555,7 @@ DEFUN (show_ip_ospf_external_aggregator, VRF_CMD_HELP_STR "All VRFs\n" "Show external summary addresses\n" - "Detailed informtion\n" + "Detailed information\n" JSON_STR) { char *vrf_name = NULL; @@ -12847,7 +12827,6 @@ void ospf_vty_init(void) install_element(OSPF_NODE, &ospf_area_range_cost_cmd); install_element(OSPF_NODE, &ospf_area_range_not_advertise_cmd); install_element(OSPF_NODE, &no_ospf_area_range_cmd); - install_element(OSPF_NODE, &ospf_area_range_substitute_cmd); install_element(OSPF_NODE, &no_ospf_area_range_substitute_cmd); /* "area virtual-link" commands. */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 7834b7d93..389d3647d 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -524,7 +524,7 @@ bool ospf_external_default_routemap_apply_walk(struct ospf *ospf, * Function to originate or flush default after applying * route-map on all ei. */ -static int ospf_external_lsa_default_routemap_timer(struct thread *thread) +static void ospf_external_lsa_default_routemap_timer(struct thread *thread) { struct list *ext_list; struct ospf *ospf = THREAD_ARG(thread); @@ -545,7 +545,7 @@ static int ospf_external_lsa_default_routemap_timer(struct thread *thread) /* Nothing to be done here. */ if (IS_DEBUG_OSPF_DEFAULT_INFO) zlog_debug("Default originate info not present"); - return 0; + return; } /* For all the ei apply route-map */ @@ -570,8 +570,6 @@ static int ospf_external_lsa_default_routemap_timer(struct thread *thread) ospf_external_lsa_refresh(ospf, lsa, default_ei, true, false); else if (!ret && lsa) ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &default_ei->p, 0); - - return 1; } @@ -1380,7 +1378,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) /* Handling the case where the * external route prefix * and aggegate prefix is same - * If same dont flush the + * If same don't flush the * originated * external LSA. */ @@ -1522,7 +1520,7 @@ int ospf_distribute_list_out_unset(struct ospf *ospf, int type, } /* distribute-list update timer. */ -static int ospf_distribute_list_update_timer(struct thread *thread) +static void ospf_distribute_list_update_timer(struct thread *thread) { struct route_node *rn; struct external_info *ei; @@ -1532,7 +1530,7 @@ static int ospf_distribute_list_update_timer(struct thread *thread) struct ospf *ospf = THREAD_ARG(thread); if (ospf == NULL) - return 0; + return; ospf->t_distribute_update = NULL; @@ -1639,8 +1637,6 @@ static int ospf_distribute_list_update_timer(struct thread *thread) } if (default_refresh) ospf_external_lsa_refresh_default(ospf); - - return 0; } /* Update distribute-list and set timer to apply access-list. */ diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index e5f3eec60..221f6e7e4 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -584,13 +584,11 @@ static void ospf_deferred_shutdown_finish(struct ospf *ospf) } /* Timer thread for G-R */ -static int ospf_deferred_shutdown_timer(struct thread *t) +static void ospf_deferred_shutdown_timer(struct thread *t) { struct ospf *ospf = THREAD_ARG(t); ospf_deferred_shutdown_finish(ospf); - - return 0; } /* Check whether deferred-shutdown must be scheduled, otherwise call @@ -1089,7 +1087,7 @@ struct ospf_interface *add_ospf_interface(struct connected *co, ospf_ldp_sync_if_init(oi); /* - * if router_id is not configured, dont bring up + * if router_id is not configured, don't bring up * interfaces. * ospf_router_id_update() will call ospf_if_update * whenever r-id is configured instead. diff --git a/pathd/path_errors.c b/pathd/path_errors.c index 112a3d5ee..68372c29b 100644 --- a/pathd/path_errors.c +++ b/pathd/path_errors.c @@ -81,7 +81,7 @@ static struct log_ref ferr_path_warn[] = { { .code = EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE, .title = "Unsupported PCEP feature", - .description = "Receved an unsupported PCEP message", + .description = "Received an unsupported PCEP message", .suggestion = "The PCC and PCE are probably not compatible. Open an Issue with all relevant log files" }, { diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c index 4c16b8394..99b1c349a 100644 --- a/pathd/path_pcep_config.c +++ b/pathd/path_pcep_config.c @@ -301,7 +301,7 @@ int path_pcep_config_initiate_path(struct path *path) return ERROR_19_9; } zlog_warn( - "(%s)PCE tried to REMOVE found canidate!, let's remove", + "(%s)PCE tried to REMOVE found candidate!, let's remove", __func__); candidate->policy->srp_id = path->srp_id; SET_FLAG(candidate->policy->flags, F_POLICY_DELETED); diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c index 162c53590..b9f2ba3c6 100644 --- a/pathd/path_pcep_controller.c +++ b/pathd/path_pcep_controller.c @@ -92,10 +92,10 @@ struct get_pcep_session_args { /* Internal Functions Called From Main Thread */ static int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res); -static int pcep_refine_path_event_cb(struct thread *thread); +static void pcep_refine_path_event_cb(struct thread *thread); /* Internal Functions Called From Controller Thread */ -static int pcep_thread_finish_event_handler(struct thread *thread); +static void pcep_thread_finish_event_handler(struct thread *thread); /* Controller Thread Timer Handler */ static int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id, @@ -108,7 +108,7 @@ static int schedule_thread_timer_with_cb( enum pcep_ctrl_timer_type timer_type, enum pcep_ctrl_timeout_type timeout_type, uint32_t delay, void *payload, struct thread **thread, pcep_ctrl_thread_callback timer_cb); -static int pcep_thread_timer_handler(struct thread *thread); +static void pcep_thread_timer_handler(struct thread *thread); /* Controller Thread Socket read/write Handler */ static int schedule_thread_socket(struct ctrl_state *ctrl_state, int pcc_id, @@ -124,7 +124,7 @@ static int send_to_thread_with_cb(struct ctrl_state *ctrl_state, int pcc_id, enum pcep_ctrl_event_type type, uint32_t sub_type, void *payload, pcep_ctrl_thread_callback event_cb); -static int pcep_thread_event_handler(struct thread *thread); +static void pcep_thread_event_handler(struct thread *thread); static int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state, struct pcc_opts *opts); static int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state, @@ -149,7 +149,7 @@ pcep_thread_path_refined_event(struct ctrl_state *ctrl_state, /* Main Thread Event Handler */ static int send_to_main(struct ctrl_state *ctrl_state, int pcc_id, enum pcep_main_event_type type, void *payload); -static int pcep_main_event_handler(struct thread *thread); +static void pcep_main_event_handler(struct thread *thread); /* Helper functions */ static void set_ctrl_state(struct frr_pthread *fpt, @@ -340,7 +340,7 @@ int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res) return 0; } -int pcep_refine_path_event_cb(struct thread *thread) +void pcep_refine_path_event_cb(struct thread *thread) { struct pcep_refine_path_event_data *data = THREAD_ARG(thread); assert(data != NULL); @@ -351,7 +351,7 @@ int pcep_refine_path_event_cb(struct thread *thread) path_pcep_refine_path(path); - return send_to_thread(ctrl_state, pcc_id, EV_PATH_REFINED, 0, data); + send_to_thread(ctrl_state, pcc_id, EV_PATH_REFINED, 0, data); } @@ -507,7 +507,7 @@ void pcep_thread_path_refined_event(struct ctrl_state *ctrl_state, /* ------------ Internal Functions Called From Controller Thread ------------ */ -int pcep_thread_finish_event_handler(struct thread *thread) +void pcep_thread_finish_event_handler(struct thread *thread) { int i; struct frr_pthread *fpt = THREAD_ARG(thread); @@ -527,7 +527,6 @@ int pcep_thread_finish_event_handler(struct thread *thread) fpt->data = NULL; atomic_store_explicit(&fpt->running, false, memory_order_relaxed); - return 0; } /* ------------ Controller Thread Timer Handler ------------ */ @@ -566,7 +565,7 @@ int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id, thread, pcep_thread_timer_handler); } -int pcep_thread_timer_handler(struct thread *thread) +void pcep_thread_timer_handler(struct thread *thread) { /* data unpacking */ struct pcep_ctrl_timer_data *data = THREAD_ARG(thread); @@ -579,26 +578,25 @@ int pcep_thread_timer_handler(struct thread *thread) void *param = data->payload; XFREE(MTYPE_PCEP, data); - int ret = 0; struct pcc_state *pcc_state = NULL; switch (timer_type) { case TM_RECONNECT_PCC: pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); if (!pcc_state) - return ret; + return; pcep_pcc_reconnect(ctrl_state, pcc_state); break; case TM_TIMEOUT: pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); if (!pcc_state) - return ret; + return; pcep_pcc_timeout_handler(ctrl_state, pcc_state, timeout_type, param); break; case TM_CALCULATE_BEST_PCE: /* Previous best disconnect so new best should be synced */ - ret = pcep_pcc_timer_update_best_pce(ctrl_state, pcc_id); + pcep_pcc_timer_update_best_pce(ctrl_state, pcc_id); break; case TM_SESSION_TIMEOUT_PCC: pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); @@ -610,11 +608,9 @@ int pcep_thread_timer_handler(struct thread *thread) "Unknown controller timer triggered: %u", timer_type); break; } - - return ret; } -int pcep_thread_pcep_event(struct thread *thread) +void pcep_thread_pcep_event(struct thread *thread) { struct pcep_ctrl_event_data *data = THREAD_ARG(thread); assert(data != NULL); @@ -634,8 +630,6 @@ int pcep_thread_pcep_event(struct thread *thread) } } destroy_pcep_event(event); - - return 0; } /* ------------ Controller Thread Socket Functions ------------ */ @@ -725,7 +719,7 @@ int send_to_thread_with_cb(struct ctrl_state *ctrl_state, int pcc_id, return 0; } -int pcep_thread_event_handler(struct thread *thread) +void pcep_thread_event_handler(struct thread *thread) { /* data unpacking */ struct pcep_ctrl_event_data *data = THREAD_ARG(thread); @@ -738,8 +732,6 @@ int pcep_thread_event_handler(struct thread *thread) void *payload = data->payload; XFREE(MTYPE_PCEP, data); - int ret = 0; - /* Possible sub-type values */ enum pcep_pathd_event_type path_event_type = PCEP_PATH_UNDEFINED; @@ -757,29 +749,26 @@ int pcep_thread_event_handler(struct thread *thread) case EV_UPDATE_PCC_OPTS: assert(payload != NULL); pcc_opts = (struct pcc_opts *)payload; - ret = pcep_thread_event_update_pcc_options(ctrl_state, - pcc_opts); + pcep_thread_event_update_pcc_options(ctrl_state, pcc_opts); break; case EV_UPDATE_PCE_OPTS: assert(payload != NULL); pce_opts = (struct pce_opts *)payload; - ret = pcep_thread_event_update_pce_options(ctrl_state, pcc_id, - pce_opts); + pcep_thread_event_update_pce_options(ctrl_state, pcc_id, + pce_opts); break; case EV_REMOVE_PCC: pce_opts = (struct pce_opts *)payload; - ret = pcep_thread_event_remove_pcc(ctrl_state, pce_opts); - if (ret == 0) { - ret = pcep_pcc_multi_pce_remove_pcc(ctrl_state, - ctrl_state->pcc); - } + if (pcep_thread_event_remove_pcc(ctrl_state, pce_opts) == 0) + pcep_pcc_multi_pce_remove_pcc(ctrl_state, + ctrl_state->pcc); break; case EV_PATHD_EVENT: assert(payload != NULL); path_event_type = (enum pcep_pathd_event_type)sub_type; path = (struct path *)payload; - ret = pcep_thread_event_pathd_event(ctrl_state, path_event_type, - path); + pcep_thread_event_pathd_event(ctrl_state, path_event_type, + path); break; case EV_SYNC_PATH: assert(payload != NULL); @@ -789,14 +778,14 @@ int pcep_thread_event_handler(struct thread *thread) pcep_thread_event_sync_path(ctrl_state, pcc_id, path); break; case EV_SYNC_DONE: - ret = pcep_thread_event_sync_done(ctrl_state, pcc_id); + pcep_thread_event_sync_done(ctrl_state, pcc_id); break; case EV_RESET_PCC_SESSION: pcc_state = pcep_pcc_get_pcc_by_name(ctrl_state->pcc, (const char *)payload); if (pcc_state) { pcep_pcc_disable(ctrl_state, pcc_state); - ret = pcep_pcc_enable(ctrl_state, pcc_state); + pcep_pcc_enable(ctrl_state, pcc_state); } else { flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR, "Cannot reset state for PCE: %s", @@ -840,8 +829,6 @@ int pcep_thread_event_handler(struct thread *thread) type); break; } - - return ret; } int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state, @@ -994,7 +981,7 @@ int send_to_main(struct ctrl_state *ctrl_state, int pcc_id, return 0; } -int pcep_main_event_handler(struct thread *thread) +void pcep_main_event_handler(struct thread *thread) { /* data unpacking */ struct pcep_main_event_data *data = THREAD_ARG(thread); @@ -1005,7 +992,7 @@ int pcep_main_event_handler(struct thread *thread) void *payload = data->payload; XFREE(MTYPE_PCEP, data); - return handler(type, pcc_id, payload); + handler(type, pcc_id, payload); } diff --git a/pathd/path_pcep_controller.h b/pathd/path_pcep_controller.h index f55cc0db7..de113feee 100644 --- a/pathd/path_pcep_controller.h +++ b/pathd/path_pcep_controller.h @@ -90,7 +90,7 @@ struct pcep_ctrl_socket_data { void *payload; }; -typedef int (*pcep_ctrl_thread_callback)(struct thread *); +typedef void (*pcep_ctrl_thread_callback)(struct thread *); /* PCC connection information, populated in a thread-safe * manner with pcep_ctrl_get_pcc_info() */ @@ -174,7 +174,7 @@ int pcep_thread_socket_write(void *fpt, void **thread, int fd, void *payload, int pcep_thread_send_ctrl_event(void *fpt, void *payload, pcep_ctrl_thread_callback cb); -int pcep_thread_pcep_event(struct thread *thread); +void pcep_thread_pcep_event(struct thread *thread); int pcep_thread_pcc_count(struct ctrl_state *ctrl_state); /* Called by the PCC to refine a path in the main thread */ int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id, diff --git a/pathd/path_pcep_lib.c b/pathd/path_pcep_lib.c index 9fc8c091f..8e3565d72 100644 --- a/pathd/path_pcep_lib.c +++ b/pathd/path_pcep_lib.c @@ -45,8 +45,8 @@ static int pcep_lib_pceplib_socket_read_cb(void *fpt, void **thread, int fd, void *payload); static int pcep_lib_pceplib_socket_write_cb(void *fpt, void **thread, int fd, void *payload); -static int pcep_lib_socket_read_ready(struct thread *thread); -static int pcep_lib_socket_write_ready(struct thread *thread); +static void pcep_lib_socket_read_ready(struct thread *thread); +static void pcep_lib_socket_write_ready(struct thread *thread); /* pceplib pcep_event callbacks */ static void pcep_lib_pceplib_event_cb(void *fpt, pcep_event *event); @@ -241,26 +241,22 @@ int pcep_lib_pceplib_socket_read_cb(void *fpt, void **thread, int fd, /* Callbacks called by path_pcep_controller when a socket is ready to read/write */ -int pcep_lib_socket_write_ready(struct thread *thread) +void pcep_lib_socket_write_ready(struct thread *thread) { struct pcep_ctrl_socket_data *data = THREAD_ARG(thread); assert(data != NULL); - int retval = pceplib_external_socket_write(data->fd, data->payload); + pceplib_external_socket_write(data->fd, data->payload); XFREE(MTYPE_PCEP, data); - - return retval; } -int pcep_lib_socket_read_ready(struct thread *thread) +void pcep_lib_socket_read_ready(struct thread *thread) { struct pcep_ctrl_socket_data *data = THREAD_ARG(thread); assert(data != NULL); - int retval = pceplib_external_socket_read(data->fd, data->payload); + pceplib_external_socket_read(data->fd, data->payload); XFREE(MTYPE_PCEP, data); - - return retval; } /* Callback passed to pceplib when a pcep_event is ready */ diff --git a/pathd/path_ted.c b/pathd/path_ted.c index ff9bc82f3..3440b9339 100644 --- a/pathd/path_ted.c +++ b/pathd/path_ted.c @@ -39,8 +39,8 @@ static void path_ted_unregister_vty(void); static uint32_t path_ted_start_importing_igp(const char *daemon_str); static uint32_t path_ted_stop_importing_igp(void); static enum zclient_send_status path_ted_link_state_sync(void); -static int path_ted_timer_handler_sync(struct thread *thread); -static int path_ted_timer_handler_refresh(struct thread *thread); +static void path_ted_timer_handler_sync(struct thread *thread); +static void path_ted_timer_handler_refresh(struct thread *thread); static int path_ted_cli_debug_config_write(struct vty *vty); static int path_ted_cli_debug_set_all(uint32_t flags, bool set); @@ -602,14 +602,14 @@ enum zclient_send_status path_ted_link_state_sync(void) * * @return status */ -int path_ted_timer_handler_sync(struct thread *thread) +void path_ted_timer_handler_sync(struct thread *thread) { /* data unpacking */ struct ted_state *data = THREAD_ARG(thread); assert(data != NULL); /* Retry the sync */ - return path_ted_link_state_sync(); + path_ted_link_state_sync(); } /** @@ -639,10 +639,10 @@ int path_ted_segment_list_refresh(void) * * @return status */ -int path_ted_timer_handler_refresh(struct thread *thread) +void path_ted_timer_handler_refresh(struct thread *thread) { if (!path_ted_is_initialized()) - return MPLS_LABEL_NONE; + return; PATH_TED_DEBUG("%s: PATHD-TED: Refresh sid from current TED", __func__); /* data unpacking */ @@ -651,7 +651,6 @@ int path_ted_timer_handler_refresh(struct thread *thread) assert(data != NULL); srte_policy_update_ted_sid(); - return 0; } /** diff --git a/pathd/pathd.c b/pathd/pathd.c index 7f6d34f75..be2cfe8b0 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -45,9 +45,9 @@ DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate), (candidate)); static void trigger_pathd_candidate_created(struct srte_candidate *candidate); -static int trigger_pathd_candidate_created_timer(struct thread *thread); +static void trigger_pathd_candidate_created_timer(struct thread *thread); static void trigger_pathd_candidate_updated(struct srte_candidate *candidate); -static int trigger_pathd_candidate_updated_timer(struct thread *thread); +static void trigger_pathd_candidate_updated_timer(struct thread *thread); static void trigger_pathd_candidate_removed(struct srte_candidate *candidate); static const char * srte_candidate_metric_name(enum srte_candidate_metric_type type); @@ -1240,11 +1240,11 @@ void trigger_pathd_candidate_created(struct srte_candidate *candidate) (void *)candidate, HOOK_DELAY, &candidate->hook_timer); } -int trigger_pathd_candidate_created_timer(struct thread *thread) +void trigger_pathd_candidate_created_timer(struct thread *thread) { struct srte_candidate *candidate = THREAD_ARG(thread); candidate->hook_timer = NULL; - return hook_call(pathd_candidate_created, candidate); + hook_call(pathd_candidate_created, candidate); } void trigger_pathd_candidate_updated(struct srte_candidate *candidate) @@ -1260,11 +1260,11 @@ void trigger_pathd_candidate_updated(struct srte_candidate *candidate) (void *)candidate, HOOK_DELAY, &candidate->hook_timer); } -int trigger_pathd_candidate_updated_timer(struct thread *thread) +void trigger_pathd_candidate_updated_timer(struct thread *thread) { struct srte_candidate *candidate = THREAD_ARG(thread); candidate->hook_timer = NULL; - return hook_call(pathd_candidate_updated, candidate); + hook_call(pathd_candidate_updated, candidate); } void trigger_pathd_candidate_removed(struct srte_candidate *candidate) @@ -1345,7 +1345,7 @@ int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry, zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)", __func__, ted_sid); } else { - zlog_debug("%s: PATHD-TED: SL: Sucess query C : ted-sid (%d)", + zlog_debug("%s: PATHD-TED: SL: Success query C : ted-sid (%d)", __func__, ted_sid); } if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, @@ -1375,7 +1375,7 @@ int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry, zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)", __func__, ted_sid); } else { - zlog_debug("%s: PATHD-TED: SL: Sucess query E : ted-sid (%d)", + zlog_debug("%s: PATHD-TED: SL: Success query E : ted-sid (%d)", __func__, ted_sid); } if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, @@ -1404,7 +1404,7 @@ int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry, zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__, ted_sid); } else { - zlog_debug("%s:SL: Sucess query F : ted-sid (%d)", __func__, + zlog_debug("%s:SL: Success query F : ted-sid (%d)", __func__, ted_sid); } if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 03e6bacf1..7710f3277 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -792,6 +792,12 @@ void pbr_map_check_nh_group_change(const char *nh_group) if (found_name) { bool original = pbrm->valid; + /* Set data we were waiting on */ + if (pbrms->nhgrp_name) + pbr_nht_set_seq_nhg_data( + pbrms, + nhgc_find(pbrms->nhgrp_name)); + pbr_map_check_valid_internal(pbrm); if (pbrm->valid && (original != pbrm->valid)) diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index aaadad482..fb0bd7258 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -522,6 +522,49 @@ char *pbr_nht_nexthop_make_name(char *name, size_t l, return buffer; } +/* Set data derived from nhg in pbrms */ +void pbr_nht_set_seq_nhg_data(struct pbr_map_sequence *pbrms, + const struct nexthop_group_cmd *nhgc) +{ + const struct nexthop_group *nhg; + + if (!nhgc) + return; + + nhg = &nhgc->nhg; + if (!nhg->nexthop) + return; + + switch (nhg->nexthop->type) { + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + pbrms->family = AF_INET6; + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + pbrms->family = AF_INET; + default: + break; + } +} + +/* Configure a routemap sequence to use a given nexthop group */ +void pbr_nht_set_seq_nhg(struct pbr_map_sequence *pbrms, const char *name) +{ + struct nexthop_group_cmd *nhgc; + + if (!name) + return; + + pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name); + + nhgc = nhgc_find(name); + if (!nhgc) + return; + + pbr_nht_set_seq_nhg_data(pbrms, nhgc); +} + void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms, const struct nexthop *nhop) { diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h index 8d9edc633..ecc92cc05 100644 --- a/pbrd/pbr_nht.h +++ b/pbrd/pbr_nht.h @@ -109,6 +109,11 @@ extern struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name); extern void pbr_nht_change_group(const char *name); extern void pbr_nht_delete_group(const char *name); +extern void pbr_nht_set_seq_nhg_data(struct pbr_map_sequence *pbrms, + const struct nexthop_group_cmd *nhgc); +extern void pbr_nht_set_seq_nhg(struct pbr_map_sequence *pbrms, + const char *name); + extern void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms, const struct nexthop *nhop); extern void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms); diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index c9ec532bb..b5946bd40 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -358,7 +358,7 @@ DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd, struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); #ifndef GNU_LINUX - vty_out(vty, "pbr marks are not supported on this platform"); + vty_out(vty, "pbr marks are not supported on this platform\n"); return CMD_WARNING_CONFIG_FAILED; #endif @@ -506,7 +506,8 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, /* This is new/replacement config */ pbrms_clear_set_config(pbrms); - pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name); + pbr_nht_set_seq_nhg(pbrms, name); + pbr_map_check(pbrms, true); return CMD_SUCCESS; diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index b480d4072..f99258872 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -399,17 +399,19 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi) static int pbr_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) { struct zapi_route nhr; + struct prefix matched; uint32_t i; - if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { zlog_err("Failure to decode Nexthop update message"); return 0; } if (DEBUG_MODE_CHECK(&pbr_dbg_zebra, DEBUG_MODE_ALL)) { - DEBUGD(&pbr_dbg_zebra, "%s: Received Nexthop update: %pFX", - __func__, &nhr.prefix); + DEBUGD(&pbr_dbg_zebra, + "%s: Received Nexthop update: %pFX against %pFX", + __func__, &matched, &nhr.prefix); DEBUGD(&pbr_dbg_zebra, "%s: (Nexthops(%u)", __func__, nhr.nexthop_num); @@ -423,6 +425,7 @@ static int pbr_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) } } + nhr.prefix = matched; pbr_nht_nexthop_update(&nhr); return 1; } diff --git a/pceplib/pcep_timers.c b/pceplib/pcep_timers.c index bbf9b7798..b0f3e70b5 100644 --- a/pceplib/pcep_timers.c +++ b/pceplib/pcep_timers.c @@ -413,7 +413,7 @@ bool reset_timer(int timer_id) /* Keeping this log for now, since in older versions of FRR the * timer cancellation was blocking. This allows us to see how * long the it takes.*/ - pcep_log(LOG_DEBUG, "%s: Reseting timer [%d] with callback", + pcep_log(LOG_DEBUG, "%s: Resetting timer [%d] with callback", __func__, timer_to_reset->timer_id); timers_context_->timer_cancel_func( &timer_to_reset->external_timer); diff --git a/pceplib/test/pcep_msg_messages_test.c b/pceplib/test/pcep_msg_messages_test.c index 3fec24a22..e3a74f92d 100644 --- a/pceplib/test/pcep_msg_messages_test.c +++ b/pceplib/test/pcep_msg_messages_test.c @@ -143,7 +143,7 @@ void test_pcep_msg_create_request() /* Test IPv6 */ rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL); - struct in6_addr src_addr_ipv6, dst_addr_ipv6; + struct in6_addr src_addr_ipv6 = {}, dst_addr_ipv6 = {}; struct pcep_object_endpoints_ipv6 *ipv6_obj = pcep_obj_create_endpoint_ipv6(&src_addr_ipv6, &dst_addr_ipv6); message = pcep_msg_create_request_ipv6(rp_obj, ipv6_obj, NULL); diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c new file mode 100644 index 000000000..e3130b156 --- /dev/null +++ b/pimd/pim6_cmd.c @@ -0,0 +1,494 @@ +/* + * PIM for IPv6 FRR + * Copyright (C) 2022 Vmware, Inc. + * Mobashshera Rasool + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "lib/json.h" +#include "command.h" +#include "if.h" +#include "prefix.h" +#include "zclient.h" +#include "plist.h" +#include "hash.h" +#include "nexthop.h" +#include "vrf.h" +#include "ferr.h" + +#include "pimd.h" +#include "pim6_cmd.h" +#include "pim_vty.h" +#include "lib/northbound_cli.h" +#include "pim_errors.h" +#include "pim_nb.h" +#include "pim_cmd_common.h" + +#ifndef VTYSH_EXTRACT_PL +#include "pimd/pim6_cmd_clippy.c" +#endif + +DEFPY (ipv6_pim_joinprune_time, + ipv6_pim_joinprune_time_cmd, + "ipv6 pim join-prune-interval (1-65535)$jpi", + IPV6_STR + PIM_STR + "Join Prune Send Interval\n" + "Seconds\n") +{ + return pim_process_join_prune_cmd(vty, jpi_str); +} + +DEFPY (no_ipv6_pim_joinprune_time, + no_ipv6_pim_joinprune_time_cmd, + "no ipv6 pim join-prune-interval [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR) +{ + return pim_process_no_join_prune_cmd(vty); +} + +DEFPY (ipv6_pim_spt_switchover_infinity, + ipv6_pim_spt_switchover_infinity_cmd, + "ipv6 pim spt-switchover infinity-and-beyond", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n") +{ + return pim_process_spt_switchover_infinity_cmd(vty); +} + +DEFPY (ipv6_pim_spt_switchover_infinity_plist, + ipv6_pim_spt_switchover_infinity_plist_cmd, + "ipv6 pim spt-switchover infinity-and-beyond prefix-list WORD$plist", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n") +{ + return pim_process_spt_switchover_prefixlist_cmd(vty, plist); +} + +DEFPY (no_ipv6_pim_spt_switchover_infinity, + no_ipv6_pim_spt_switchover_infinity_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n") +{ + return pim_process_no_spt_switchover_cmd(vty); +} + +DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, + no_ipv6_pim_spt_switchover_infinity_plist_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond prefix-list WORD", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n") +{ + return pim_process_no_spt_switchover_cmd(vty); +} + +DEFPY (ipv6_pim_packets, + ipv6_pim_packets_cmd, + "ipv6 pim packets (1-255)", + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n") +{ + return pim_process_pim_packet_cmd(vty, packets_str); +} + +DEFPY (no_ipv6_pim_packets, + no_ipv6_pim_packets_cmd, + "no ipv6 pim packets [(1-255)]", + NO_STR + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR) +{ + return pim_process_no_pim_packet_cmd(vty); +} + +DEFPY (ipv6_pim_keep_alive, + ipv6_pim_keep_alive_cmd, + "ipv6 pim keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n") +{ + return pim_process_keepalivetimer_cmd(vty, kat_str); +} + +DEFPY (no_ipv6_pim_keep_alive, + no_ipv6_pim_keep_alive_cmd, + "no ipv6 pim keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR) +{ + return pim_process_no_keepalivetimer_cmd(vty); +} + +DEFPY (ipv6_pim_rp_keep_alive, + ipv6_pim_rp_keep_alive_cmd, + "ipv6 pim rp keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Rendevous Point\n" + "Keep alive Timer\n" + "Seconds\n") +{ + return pim_process_rp_kat_cmd(vty, kat_str); +} + +DEFPY (no_ipv6_pim_rp_keep_alive, + no_ipv6_pim_rp_keep_alive_cmd, + "no ipv6 pim rp keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Rendevous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR) +{ + return pim_process_no_rp_kat_cmd(vty); +} + +DEFPY (ipv6_pim_register_suppress, + ipv6_pim_register_suppress_cmd, + "ipv6 pim register-suppress-time (1-65535)$rst", + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n") +{ + return pim_process_register_suppress_cmd(vty, rst_str); +} + +DEFPY (no_ipv6_pim_register_suppress, + no_ipv6_pim_register_suppress_cmd, + "no ipv6 pim register-suppress-time [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR) +{ + return pim_process_no_register_suppress_cmd(vty); +} + +DEFPY (interface_ipv6_pim, + interface_ipv6_pim_cmd, + "ipv6 pim", + IPV6_STR + PIM_STR) +{ + return pim_process_ip_pim_cmd(vty); +} + +DEFPY (interface_no_ipv6_pim, + interface_no_ipv6_pim_cmd, + "no ipv6 pim", + NO_STR + IPV6_STR + PIM_STR) +{ + return pim_process_no_ip_pim_cmd(vty); +} + +DEFPY (interface_ipv6_pim_drprio, + interface_ipv6_pim_drprio_cmd, + "ipv6 pim drpriority (1-4294967295)", + IPV6_STR + PIM_STR + "Set the Designated Router Election Priority\n" + "Value of the new DR Priority\n") +{ + return pim_process_ip_pim_drprio_cmd(vty, drpriority_str); +} + +DEFPY (interface_no_ipv6_pim_drprio, + interface_no_ipv6_pim_drprio_cmd, + "no ip pim drpriority [(1-4294967295)]", + NO_STR + IPV6_STR + PIM_STR + "Revert the Designated Router Priority to default\n" + "Old Value of the Priority\n") +{ + return pim_process_no_ip_pim_drprio_cmd(vty); +} + +DEFPY (interface_ipv6_pim_hello, + interface_ipv6_pim_hello_cmd, + "ipv6 pim hello (1-65535) [(1-65535)]$hold", + IPV6_STR + PIM_STR + IFACE_PIM_HELLO_STR + IFACE_PIM_HELLO_TIME_STR + IFACE_PIM_HELLO_HOLD_STR) +{ + return pim_process_ip_pim_hello_cmd(vty, hello_str, hold_str); +} + +DEFPY (interface_no_ipv6_pim_hello, + interface_no_ipv6_pim_hello_cmd, + "no ipv6 pim hello [(1-65535) [(1-65535)]]", + NO_STR + IPV6_STR + PIM_STR + IFACE_PIM_HELLO_STR + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR) +{ + return pim_process_no_ip_pim_hello_cmd(vty); +} + +DEFPY (interface_ipv6_pim_activeactive, + interface_ipv6_pim_activeactive_cmd, + "[no] ipv6 pim active-active", + NO_STR + IPV6_STR + PIM_STR + "Mark interface as Active-Active for MLAG operations\n") +{ + return pim_process_ip_pim_activeactive_cmd(vty, no); +} + +DEFPY_HIDDEN (interface_ipv6_pim_ssm, + interface_ipv6_pim_ssm_cmd, + "ipv6 pim ssm", + IPV6_STR + PIM_STR + IFACE_PIM_STR) +{ + int ret; + + ret = pim_process_ip_pim_cmd(vty); + + if (ret != NB_OK) + return ret; + + vty_out(vty, + "Enabled PIM SM on interface; configure PIM SSM range if needed\n"); + + return NB_OK; +} + +DEFPY_HIDDEN (interface_no_ipv6_pim_ssm, + interface_no_ipv6_pim_ssm_cmd, + "no ipv6 pim ssm", + NO_STR + IPV6_STR + PIM_STR + IFACE_PIM_STR) +{ + return pim_process_no_ip_pim_cmd(vty); +} + +DEFPY_HIDDEN (interface_ipv6_pim_sm, + interface_ipv6_pim_sm_cmd, + "ipv6 pim sm", + IPV6_STR + PIM_STR + IFACE_PIM_SM_STR) +{ + return pim_process_ip_pim_cmd(vty); +} + +DEFPY_HIDDEN (interface_no_ipv6_pim_sm, + interface_no_ipv6_pim_sm_cmd, + "no ipv6 pim sm", + NO_STR + IPV6_STR + PIM_STR + IFACE_PIM_SM_STR) +{ + return pim_process_no_ip_pim_cmd(vty); +} + +/* boundaries */ +DEFPY (interface_ipv6_pim_boundary_oil, + interface_ipv6_pim_boundary_oil_cmd, + "ipv6 multicast boundary oil WORD", + IPV6_STR + "Generic multicast configuration options\n" + "Define multicast boundary\n" + "Filter OIL by group using prefix list\n" + "Prefix list to filter OIL with\n") +{ + return pim_process_ip_pim_boundary_oil_cmd(vty, oil); +} + +DEFPY (interface_no_ipv6_pim_boundary_oil, + interface_no_ipv6_pim_boundary_oil_cmd, + "no ipv6 multicast boundary oil [WORD]", + NO_STR + IPV6_STR + "Generic multicast configuration options\n" + "Define multicast boundary\n" + "Filter OIL by group using prefix list\n" + "Prefix list to filter OIL with\n") +{ + return pim_process_no_ip_pim_boundary_oil_cmd(vty); +} + +DEFPY (interface_ipv6_mroute, + interface_ipv6_mroute_cmd, + "ipv6 mroute INTERFACE X:X::X:X$group [X:X::X:X]$source", + IPV6_STR + "Add multicast route\n" + "Outgoing interface name\n" + "Group address\n" + "Source address\n") +{ + return pim_process_ip_mroute_cmd(vty, interface, group_str, source_str); +} + +DEFPY (interface_no_ipv6_mroute, + interface_no_ipv6_mroute_cmd, + "no ipv6 mroute INTERFACE X:X::X:X$group [X:X::X:X]$source", + NO_STR + IPV6_STR + "Add multicast route\n" + "Outgoing interface name\n" + "Group Address\n" + "Source Address\n") +{ + return pim_process_no_ip_mroute_cmd(vty, interface, group_str, + source_str); +} + +DEFPY (ipv6_pim_rp, + ipv6_pim_rp_cmd, + "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n") +{ + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + + return pim_process_rp_cmd(vty, rp_str, group_str); +} + +DEFPY (no_ipv6_pim_rp, + no_ipv6_pim_rp_cmd, + "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n") +{ + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + + return pim_process_no_rp_cmd(vty, rp_str, group_str); +} + +DEFPY (ipv6_pim_rp_prefix_list, + ipv6_pim_rp_prefix_list_cmd, + "ipv6 pim rp X:X::X:X$rp prefix-list WORD$plist", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n") +{ + return pim_process_rp_plist_cmd(vty, rp_str, plist); +} + +DEFPY (no_ipv6_pim_rp_prefix_list, + no_ipv6_pim_rp_prefix_list_cmd, + "no ipv6 pim rp X:X::X:X$rp prefix-list WORD$plist", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n") +{ + return pim_process_no_rp_plist_cmd(vty, rp_str, plist); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_element(CONFIG_NODE, &ipv6_pim_joinprune_time_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_joinprune_time_cmd); + install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_cmd); + install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_plist_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_spt_switchover_infinity_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_spt_switchover_infinity_plist_cmd); + install_element(CONFIG_NODE, &ipv6_pim_packets_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_packets_cmd); + install_element(CONFIG_NODE, &ipv6_pim_keep_alive_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_keep_alive_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_keep_alive_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_keep_alive_cmd); + install_element(CONFIG_NODE, &ipv6_pim_register_suppress_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_register_suppress_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_drprio_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_drprio_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_hello_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_hello_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_activeactive_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_ssm_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_ssm_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_sm_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_sm_cmd); + install_element(INTERFACE_NODE, + &interface_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, + &interface_no_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); +} diff --git a/pimd/pim6_cmd.h b/pimd/pim6_cmd.h new file mode 100644 index 000000000..ac5eb3f9b --- /dev/null +++ b/pimd/pim6_cmd.h @@ -0,0 +1,49 @@ +/* + * PIM for IPv6 FRR + * Copyright (C) 2022 Vmware, Inc. + * Mobashshera Rasool + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef PIM6_CMD_H +#define PIM6_CMD_H + +#define PIM_STR "PIM information\n" +#define MLD_STR "MLD information\n" +#define MLD_GROUP_STR "MLD groups information\n" +#define MLD_SOURCE_STR "MLD sources information\n" +#define IFACE_MLD_STR "Enable MLD operation\n" +#define IFACE_MLD_QUERY_INTERVAL_STR "MLD host query interval\n" +#define IFACE_MLD_QUERY_MAX_RESPONSE_TIME_STR \ + "MLD max query response value (seconds)\n" +#define IFACE_MLD_QUERY_MAX_RESPONSE_TIME_DSEC_STR \ + "MLD max query response value (deciseconds)\n" +#define IFACE_MLD_LAST_MEMBER_QUERY_INTERVAL_STR \ + "MLD last member query interval\n" +#define IFACE_MLD_LAST_MEMBER_QUERY_COUNT_STR "MLD last member query count\n" +#define IFACE_PIM_STR "Enable PIM SSM operation\n" +#define IFACE_PIM_SM_STR "Enable PIM SM operation\n" +#define IFACE_PIM_HELLO_STR "Hello Interval\n" +#define IFACE_PIM_HELLO_TIME_STR "Time in seconds for Hello Interval\n" +#define IFACE_PIM_HELLO_HOLD_STR "Time in seconds for Hold Interval\n" +#define MROUTE_STR "IP multicast routing table\n" +#define DEBUG_MLD_STR "MLD protocol activity\n" +#define DEBUG_MLD_EVENTS_STR "MLD protocol events\n" +#define DEBUG_MLD_PACKETS_STR "MLD protocol packets\n" +#define DEBUG_MLD_TRACE_STR "MLD internal daemon activity\n" + +void pim_cmd_init(void); + +#endif /* PIM6_CMD_H */ diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c index 3d8ebd0d8..8c7fca174 100644 --- a/pimd/pim6_main.c +++ b/pimd/pim6_main.c @@ -36,6 +36,8 @@ #include "pim_errors.h" #include "pim_iface.h" #include "pim_zebra.h" +#include "pim_nb.h" +#include "pim6_cmd.h" zebra_capabilities_t _caps_p[] = { ZCAP_SYS_ADMIN, @@ -109,6 +111,9 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_route_map_info, &frr_vrf_info, &frr_routing_info, + &frr_pim_info, + &frr_pim_rp_info, + &frr_gmp_info, }; /* clang-format off */ @@ -172,27 +177,24 @@ int main(int argc, char **argv, char **envp) prefix_list_delete_hook(pim_prefix_list_update); pim_route_map_init(); - pim_init(); #endif - + /* pim_init(); */ + pim_cmd_init(); /* * Initialize zclient "update" and "lookup" sockets */ pim_iface_init(); - /* TODO PIM6: next line is temporary since pim_cmd_init is disabled */ - if_cmd_init(NULL); - -#if 0 pim_zebra_init(); +#if 0 pim_bfd_init(); pim_mlag_init(); +#endif hook_register(routing_conf_event, routing_control_plane_protocols_name_validate); routing_control_plane_protocols_register_vrf_dependency(); -#endif frr_config_fork(); frr_run(router->master); diff --git a/pimd/pim6_stubs.c b/pimd/pim6_stubs.c new file mode 100644 index 000000000..e689c7aca --- /dev/null +++ b/pimd/pim6_stubs.c @@ -0,0 +1,123 @@ +/* + * PIMv6 temporary stubs + * Copyright (C) 2022 David Lamparter for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "pimd.h" +#include "pim_nht.h" +#include "pim_zlookup.h" +#include "pim_pim.h" +#include "pim_register.h" +#include "pim_cmd.h" + +/* + * NH lookup / NHT + */ +void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr) +{ +} + +void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr) +{ +} + +int zclient_lookup_nexthop(struct pim_instance *pim, + struct pim_zlookup_nexthop nexthop_tab[], + const int tab_size, pim_addr addr, + int max_lookup) +{ + return -1; +} + +void zclient_lookup_new(void) +{ +} + +void zclient_lookup_free(void) +{ +} + +/* + * packet handling + */ +int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, + int pim_msg_size, const char *ifname) +{ + return 0; +} + +int pim_hello_send(struct interface *ifp, uint16_t holdtime) +{ + return -1; +} + +void pim_hello_restart_now(struct interface *ifp) +{ +} + +void pim_hello_restart_triggered(struct interface *ifp) +{ +} + +int pim_sock_add(struct interface *ifp) +{ + return -1; +} + +void pim_sock_delete(struct interface *ifp, const char *delete_message) +{ +} + +/* + * PIM register + */ +void pim_register_join(struct pim_upstream *up) +{ +} + +void pim_null_register_send(struct pim_upstream *up) +{ +} + +void pim_reg_del_on_couldreg_fail(struct interface *ifp) +{ +} + +bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp) +{ + return false; +} + +void pim_bsm_proc_free(struct pim_instance *pim) +{ +} + +void pim_bsm_proc_init(struct pim_instance *pim) +{ +} + +struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope, + struct prefix *grp) +{ + return NULL; +} + +void pim_bsm_write_config(struct vty *vty, struct interface *ifp) +{ +} diff --git a/pimd/pim_addr.c b/pimd/pim_addr.c index 8d89b5714..6ba0947c2 100644 --- a/pimd/pim_addr.c +++ b/pimd/pim_addr.c @@ -39,18 +39,11 @@ static ssize_t printfrr_pimaddr(struct fbuf *buf, struct printfrr_eargs *ea, if (!addr) return bputs(buf, "(null)"); - if (use_star) { - pim_addr zero = {}; - - if (memcmp(addr, &zero, sizeof(zero)) == 0) - return bputch(buf, '*'); - } + if (use_star && pim_addr_is_any(*addr)) + return bputch(buf, '*'); #if PIM_IPV == 4 return bprintfrr(buf, "%pI4", addr); -#elif !defined(PIM_V6_TEMP_BREAK) - CPP_NOTICE("note IPv6 typing for pim_addr is temporarily disabled."); - return bprintfrr(buf, "%pI4", addr); #else return bprintfrr(buf, "%pI6", addr); #endif diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index a1a8b55a5..e422a2e2d 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -21,19 +21,86 @@ #define _PIMD_PIM_ADDR_H #include "jhash.h" +#include "prefix.h" -/* temporarily disable IPv6 types to keep code compiling. - * Defining PIM_V6_TEMP_BREAK will show a lot of compile errors - they are - * very useful to see TODOs. - */ -#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) +/* clang-format off */ + +#if PIM_IPV == 4 typedef struct in_addr pim_addr; -#define PIM_ADDRSTRLEN INET_ADDRSTRLEN + +#define PIM_ADDRSTRLEN INET_ADDRSTRLEN +#define PIM_AF AF_INET +#define PIM_AFI AFI_IP +#define PIM_MAX_BITLEN IPV4_MAX_BITLEN +#define PIM_AF_NAME "ip" + +union pimprefixptr { + prefixtype(pimprefixptr, struct prefix, p) + prefixtype(pimprefixptr, struct prefix_ipv4, p4) +} TRANSPARENT_UNION; + +union pimprefixconstptr { + prefixtype(pimprefixconstptr, const struct prefix, p) + prefixtype(pimprefixconstptr, const struct prefix_ipv4, p4) +} TRANSPARENT_UNION; + #else typedef struct in6_addr pim_addr; -#define PIM_ADDRSTRLEN INET6_ADDRSTRLEN + +#define PIM_ADDRSTRLEN INET6_ADDRSTRLEN +#define PIM_AF AF_INET6 +#define PIM_AFI AFI_IP6 +#define PIM_MAX_BITLEN IPV6_MAX_BITLEN +#define PIM_AF_NAME "ipv6" + +union pimprefixptr { + prefixtype(pimprefixptr, struct prefix, p) + prefixtype(pimprefixptr, struct prefix_ipv6, p6) +} TRANSPARENT_UNION; + +union pimprefixconstptr { + prefixtype(pimprefixconstptr, const struct prefix, p) + prefixtype(pimprefixconstptr, const struct prefix_ipv6, p6) +} TRANSPARENT_UNION; #endif +/* for assignment/initialization (C99 compound literal) + * named PIMADDR_ANY (not PIM_ADDR_ANY) to match INADDR_ANY + */ +#define PIMADDR_ANY (pim_addr){ } + +/* clang-format on */ + +static inline bool pim_addr_is_any(pim_addr addr) +{ + pim_addr zero = {}; + + return memcmp(&addr, &zero, sizeof(zero)) == 0; +} + +static inline int pim_addr_cmp(pim_addr a, pim_addr b) +{ + return memcmp(&a, &b, sizeof(a)); +} + +static inline void pim_addr_to_prefix(union pimprefixptr out, pim_addr in) +{ + out.p->family = PIM_AF; + out.p->prefixlen = PIM_MAX_BITLEN; + memcpy(out.p->u.val, &in, sizeof(in)); +} + +static inline pim_addr pim_addr_from_prefix(union pimprefixconstptr in) +{ + pim_addr ret; + + if (in.p->family != PIM_AF) + return PIMADDR_ANY; + + memcpy(&ret, in.p->u.val, sizeof(ret)); + return ret; +} + /* don't use this struct directly, use the pim_sgaddr typedef */ struct _pim_sgaddr { pim_addr grp; diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 79b46994a..e7fff4db6 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -61,18 +61,11 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, ch->interface->name); } - if (winner_changed) { - char was_str[INET_ADDRSTRLEN]; - char winner_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", ch->ifassert_winner, was_str, - sizeof(was_str)); - pim_inet4_dump("", winner, winner_str, - sizeof(winner_str)); + if (winner_changed) zlog_debug( - "%s: (S,G)=%s assert winner changed from %s to %s on interface %s", - __func__, ch->sg_str, was_str, winner_str, - ch->interface->name); - } + "%s: (S,G)=%s assert winner changed from %pPAs to %pPAs on interface %s", + __func__, ch->sg_str, &ch->ifassert_winner, + &winner, ch->interface->name); } /* PIM_DEBUG_PIM_EVENTS */ ch->ifassert_state = new_state; @@ -87,14 +80,10 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, } } -static void on_trace(const char *label, struct interface *ifp, - struct in_addr src) +static void on_trace(const char *label, struct interface *ifp, pim_addr src) { - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src, src_str, sizeof(src_str)); - zlog_debug("%s: from %s on %s", label, src_str, ifp->name); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: from %pPAs on %s", label, &src, ifp->name); } static int preferred_assert(const struct pim_ifchannel *ch, @@ -136,8 +125,8 @@ static void if_could_assert_do_a1(const char *caller, struct pim_ifchannel *ch) } } -static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, - struct in_addr group_addr, +static int dispatch_assert(struct interface *ifp, pim_addr source_addr, + pim_addr group_addr, struct pim_assert_metric recv_metric) { struct pim_ifchannel *ch; @@ -213,10 +202,11 @@ static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, } int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, - struct in_addr src_addr, uint8_t *buf, int buf_size) + pim_addr src_addr, uint8_t *buf, int buf_size) { pim_sgaddr sg; - struct prefix msg_source_addr; + pim_addr msg_source_addr; + bool wrong_af = false; struct pim_assert_metric msg_metric; int offset; uint8_t *curr; @@ -234,10 +224,9 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, memset(&sg, 0, sizeof(sg)); offset = pim_parse_addr_group(&sg, curr, curr_size); if (offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s", - __func__, src_str, ifp->name); + zlog_warn( + "%s: pim_parse_addr_group() failure: from %pPAs on %s", + __func__, &src_addr, ifp->name); return -1; } curr += offset; @@ -246,23 +235,21 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, /* Parse assert source addr */ - offset = pim_parse_addr_ucast(&msg_source_addr, curr, curr_size); - if (offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", - __func__, src_str, ifp->name); + offset = pim_parse_addr_ucast(&msg_source_addr, curr, curr_size, + &wrong_af); + if (offset < 1 || wrong_af) { + zlog_warn( + "%s: pim_parse_addr_ucast() failure: from %pPAs on %s", + __func__, &src_addr, ifp->name); return -2; } curr += offset; curr_size -= offset; if (curr_size < 8) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: preference/metric size is less than 8 bytes: size=%d from %s on interface %s", - __func__, curr_size, src_str, ifp->name); + "%s: preference/metric size is less than 8 bytes: size=%d from %pPAs on interface %s", + __func__, curr_size, &src_addr, ifp->name); return -3; } @@ -284,21 +271,13 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, msg_metric.route_metric = pim_read_uint32_host(curr); - if (PIM_DEBUG_PIM_TRACE) { - char neigh_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - char group_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, neigh_str, - sizeof(neigh_str)); - pim_inet4_dump("", msg_source_addr.u.prefix4, source_str, - sizeof(source_str)); - pim_inet4_dump("", sg.grp, group_str, sizeof(group_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u", - __func__, neigh_str, ifp->name, source_str, group_str, - msg_metric.metric_preference, msg_metric.route_metric, + "%s: from %pPAs on %s: (S,G)=(%pPAs,%pPAs) pref=%u metric=%u rpt_bit=%u", + __func__, &src_addr, ifp->name, &msg_source_addr, + &sg.grp, msg_metric.metric_preference, + msg_metric.route_metric, PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag)); - } msg_metric.ip_address = src_addr; @@ -306,8 +285,7 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, assert(pim_ifp); ++pim_ifp->pim_ifstat_assert_recv; - return dispatch_assert(ifp, msg_source_addr.u.prefix4, sg.grp, - msg_metric); + return dispatch_assert(ifp, msg_source_addr, sg.grp, msg_metric); } /* @@ -356,7 +334,7 @@ int pim_assert_metric_match(const struct pim_assert_metric *m1, } int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, - struct in_addr group_addr, struct in_addr source_addr, + pim_addr group_addr, pim_addr source_addr, uint32_t metric_preference, uint32_t route_metric, uint32_t rpt_bit_flag) { @@ -370,28 +348,21 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, /* Encode group */ remain = buf_pastend - pim_msg_curr; - pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, group_addr); + pim_msg_curr = pim_msg_addr_encode_group(pim_msg_curr, group_addr); if (!pim_msg_curr) { - char group_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", group_addr, group_str, - sizeof(group_str)); zlog_warn( - "%s: failure encoding group address %s: space left=%d", - __func__, group_str, remain); + "%s: failure encoding group address %pPA: space left=%d", + __func__, &group_addr, remain); return -1; } /* Encode source */ remain = buf_pastend - pim_msg_curr; - pim_msg_curr = - pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, source_addr); + pim_msg_curr = pim_msg_addr_encode_ucast(pim_msg_curr, source_addr); if (!pim_msg_curr) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", source_addr, source_str, - sizeof(source_str)); zlog_warn( - "%s: failure encoding source address %s: space left=%d", - __func__, source_str, remain); + "%s: failure encoding source address %pPA: space left=%d", + __func__, &source_addr, remain); return -2; } @@ -502,7 +473,7 @@ static int pim_assert_cancel(struct pim_ifchannel *ch) return pim_assert_do(ch, metric); } -static int on_assert_timer(struct thread *t) +static void on_assert_timer(struct thread *t) { struct pim_ifchannel *ch; struct interface *ifp; @@ -533,8 +504,6 @@ static int on_assert_timer(struct thread *t) ifp->name); } } - - return 0; } static void assert_timer_off(struct pim_ifchannel *ch) diff --git a/pimd/pim_assert.h b/pimd/pim_assert.h index a149fb176..22bab67c5 100644 --- a/pimd/pim_assert.h +++ b/pimd/pim_assert.h @@ -59,7 +59,7 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric); int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, - struct in_addr src_addr, uint8_t *buf, int buf_size); + pim_addr src_addr, uint8_t *buf, int buf_size); int pim_assert_metric_better(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); @@ -67,7 +67,7 @@ int pim_assert_metric_match(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, - struct in_addr group_addr, struct in_addr source_addr, + pim_addr group_addr, pim_addr source_addr, uint32_t metric_preference, uint32_t route_metric, uint32_t rpt_bit_flag); diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index 31f672bb8..c1f8220db 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -50,15 +50,15 @@ void pim_bfd_write_config(struct vty *vty, struct interface *ifp) if (pim_ifp->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT || pim_ifp->bfd_config.min_rx != BFD_DEF_MIN_RX || pim_ifp->bfd_config.min_tx != BFD_DEF_MIN_TX) - vty_out(vty, " ip pim bfd %d %d %d\n", + vty_out(vty, " " PIM_AF_NAME " pim bfd %d %d %d\n", pim_ifp->bfd_config.detection_multiplier, pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx); else #endif /* ! HAVE_BFDD */ - vty_out(vty, " ip pim bfd\n"); + vty_out(vty, " " PIM_AF_NAME " pim bfd\n"); if (pim_ifp->bfd_config.profile) - vty_out(vty, " ip pim bfd profile %s\n", + vty_out(vty, " " PIM_AF_NAME " pim bfd profile %s\n", pim_ifp->bfd_config.profile); } @@ -94,7 +94,11 @@ void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp, bfd_sess_set_timers( neigh->bfd_session, pim_ifp->bfd_config.detection_multiplier, pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx); +#if PIM_IPV == 4 bfd_sess_set_ipv4_addrs(neigh->bfd_session, NULL, &neigh->source_addr); +#else + bfd_sess_set_ipv6_addrs(neigh->bfd_session, NULL, &neigh->source_addr); +#endif bfd_sess_set_interface(neigh->bfd_session, neigh->interface->name); bfd_sess_set_vrf(neigh->bfd_session, neigh->interface->vrf->vrf_id); bfd_sess_set_profile(neigh->bfd_session, pim_ifp->bfd_config.profile); diff --git a/pimd/pim_br.c b/pimd/pim_br.c index b3fc8969b..6ec6b11e7 100644 --- a/pimd/pim_br.c +++ b/pimd/pim_br.c @@ -30,35 +30,31 @@ struct pim_br { pim_sgaddr sg; - struct in_addr pmbr; + pim_addr pmbr; }; -struct in_addr pim_br_unknown = {.s_addr = 0}; - static struct list *pim_br_list = NULL; -struct in_addr pim_br_get_pmbr(pim_sgaddr *sg) +pim_addr pim_br_get_pmbr(pim_sgaddr *sg) { struct listnode *node; struct pim_br *pim_br; for (ALL_LIST_ELEMENTS_RO(pim_br_list, node, pim_br)) { - if (sg->src.s_addr == pim_br->sg.src.s_addr - && sg->grp.s_addr == pim_br->sg.grp.s_addr) + if (!pim_sgaddr_cmp(*sg, pim_br->sg)) return pim_br->pmbr; } - return pim_br_unknown; + return PIMADDR_ANY; } -void pim_br_set_pmbr(pim_sgaddr *sg, struct in_addr br) +void pim_br_set_pmbr(pim_sgaddr *sg, pim_addr br) { struct listnode *node, *next; struct pim_br *pim_br; for (ALL_LIST_ELEMENTS(pim_br_list, node, next, pim_br)) { - if (sg->src.s_addr == pim_br->sg.src.s_addr - && sg->grp.s_addr == pim_br->sg.grp.s_addr) + if (!pim_sgaddr_cmp(*sg, pim_br->sg)) break; } @@ -81,8 +77,7 @@ void pim_br_clear_pmbr(pim_sgaddr *sg) struct pim_br *pim_br; for (ALL_LIST_ELEMENTS(pim_br_list, node, next, pim_br)) { - if (sg->src.s_addr == pim_br->sg.src.s_addr - && sg->grp.s_addr == pim_br->sg.grp.s_addr) + if (!pim_sgaddr_cmp(*sg, pim_br->sg)) break; } diff --git a/pimd/pim_br.h b/pimd/pim_br.h index ef24ef3c1..7b87c0f1f 100644 --- a/pimd/pim_br.h +++ b/pimd/pim_br.h @@ -20,13 +20,11 @@ #ifndef PIM_BR_H #define PIM_BR_H -struct in_addr pim_br_get_pmbr(pim_sgaddr *sg); +pim_addr pim_br_get_pmbr(pim_sgaddr *sg); -void pim_br_set_pmbr(pim_sgaddr *sg, struct in_addr value); +void pim_br_set_pmbr(pim_sgaddr *sg, pim_addr value); void pim_br_clear_pmbr(pim_sgaddr *sg); void pim_br_init(void); -extern struct in_addr pim_br_unknown; - #endif diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 238c19d2c..d2e299a00 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -36,6 +36,7 @@ #include "pim_bsm.h" #include "pim_time.h" #include "pim_zebra.h" +#include "pim_util.h" /* Functions forward declaration */ static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout); @@ -59,9 +60,9 @@ void pim_bsm_write_config(struct vty *vty, struct interface *ifp) if (pim_ifp) { if (!pim_ifp->bsm_enable) - vty_out(vty, " no ip pim bsm\n"); + vty_out(vty, " no " PIM_AF_NAME " pim bsm\n"); if (!pim_ifp->ucast_bsm_accept) - vty_out(vty, " no ip pim unicast-bsm\n"); + vty_out(vty, " no " PIM_AF_NAME " pim unicast-bsm\n"); } } @@ -157,7 +158,7 @@ static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt, return bsgrp; } -static int pim_on_bs_timer(struct thread *t) +static void pim_on_bs_timer(struct thread *t) { struct route_node *rn; struct bsm_scope *scope; @@ -200,7 +201,6 @@ static int pim_on_bs_timer(struct thread *t) pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list); bsgrp_node->pend_rp_cnt = 0; } - return 0; } static void pim_bs_timer_stop(struct bsm_scope *scope) @@ -276,7 +276,7 @@ static bool is_hold_time_elapsed(void *data) return true; } -static int pim_on_g2rp_timer(struct thread *t) +static void pim_on_g2rp_timer(struct thread *t) { struct bsm_rpinfo *bsrp; struct bsm_rpinfo *bsrp_node; @@ -285,7 +285,7 @@ static int pim_on_g2rp_timer(struct thread *t) struct rp_info *rp_info; struct route_node *rn; uint16_t elapse; - struct in_addr bsrp_addr; + pim_addr bsrp_addr; bsrp = THREAD_ARG(t); THREAD_OFF(bsrp->g2rp_timer); @@ -312,23 +312,22 @@ static int pim_on_g2rp_timer(struct thread *t) if (!rn) { zlog_warn("%s: Route node doesn't exist", __func__); - return 0; + return; } rp_info = (struct rp_info *)rn->info; if (!rp_info) { route_unlock_node(rn); - return 0; + return; } if (rp_info->rp_src != RP_SRC_STATIC) { /* If new rp available, change it else delete the existing */ if (bsrp) { - bsrp_addr = bsrp->rp_address; pim_g2rp_timer_start( bsrp, (bsrp->rp_holdtime - bsrp->elapse_time)); - pim_rp_change(pim, bsrp_addr, bsgrp_node->group, + pim_rp_change(pim, bsrp->rp_address, bsgrp_node->group, RP_SRC_BSR); } else { pim_rp_del(pim, bsrp_addr, bsgrp_node->group, NULL, @@ -342,8 +341,6 @@ static int pim_on_g2rp_timer(struct thread *t) &bsgrp_node->group); pim_free_bsgrp_data(bsgrp_node); } - - return 0; } static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time) @@ -420,7 +417,7 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) pend = bsm_rpinfos_first(bsgrp_node->partial_bsrp_list); - if (!str2prefix("224.0.0.0/4", &group_all)) + if (!pim_get_all_mcast_group(&group_all)) return; rp_all = pim_rp_find_match_group(pim, &group_all); @@ -433,8 +430,8 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) * install the rp from head(if exists) of partial list. List is * is sorted such that head is the elected RP for the group. */ - if (!rn || (prefix_same(&rp_all->group, &bsgrp_node->group) - && pim_rpf_addr_is_inaddr_none(&rp_all->rp))) { + if (!rn || (prefix_same(&rp_all->group, &bsgrp_node->group) && + pim_rpf_addr_is_inaddr_any(&rp_all->rp))) { if (PIM_DEBUG_BSM) zlog_debug("%s: Route node doesn't exist", __func__); if (pend) @@ -557,8 +554,7 @@ static void pim_bsm_update(struct pim_instance *pim, struct in_addr bsr, uint32_t bsr_prio) { if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) { - if (pim->global_scope.current_bsr.s_addr) - pim_nht_bsr_del(pim, pim->global_scope.current_bsr); + pim_nht_bsr_del(pim, pim->global_scope.current_bsr); pim_nht_bsr_add(pim, bsr); pim->global_scope.current_bsr = bsr; @@ -582,8 +578,7 @@ void pim_bsm_clear(struct pim_instance *pim) struct rp_info *rp_info; bool upstream_updated = false; - if (pim->global_scope.current_bsr.s_addr) - pim_nht_bsr_del(pim, pim->global_scope.current_bsr); + pim_nht_bsr_del(pim, pim->global_scope.current_bsr); /* Reset scope zone data */ pim->global_scope.accept_nofwd_bsm = false; @@ -633,14 +628,13 @@ void pim_bsm_clear(struct pim_instance *pim) pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); - if (!str2prefix("224.0.0.0/4", &g_all)) + if (!pim_get_all_mcast_group(&g_all)) return; rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { - rp_all->rp.rpf_addr.family = AF_INET; - rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; + pim_addr_to_prefix(&rp_all->rp.rpf_addr, PIMADDR_ANY); rp_all->i_am_rp = 0; } else { /* Delete the rp_info from rp-list */ @@ -663,20 +657,17 @@ void pim_bsm_clear(struct pim_instance *pim) /* Find the upstream (*, G) whose upstream address is same as * the RP */ - if (up->sg.src.s_addr != INADDR_ANY) + if (!pim_addr_is_any(up->sg.src)) continue; struct prefix grp; struct rp_info *trp_info; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; - + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); /* RP not found for the group grp */ - if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { + if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) { pim_upstream_rpf_clear(pim, up); pim_rp_set_upstream_addr(pim, &up->upstream_addr, up->sg.src, up->sg.grp); @@ -692,7 +683,7 @@ void pim_bsm_clear(struct pim_instance *pim) } static bool pim_bsm_send_intf(uint8_t *buf, int len, struct interface *ifp, - struct in_addr dst_addr) + pim_addr dst_addr) { struct pim_interface *pim_ifp; @@ -725,8 +716,7 @@ static bool pim_bsm_send_intf(uint8_t *buf, int len, struct interface *ifp, } static bool pim_bsm_frag_send(uint8_t *buf, uint32_t len, struct interface *ifp, - uint32_t pim_mtu, struct in_addr dst_addr, - bool no_fwd) + uint32_t pim_mtu, pim_addr dst_addr, bool no_fwd) { struct bsmmsg_grpinfo *grpinfo, *curgrp; uint8_t *firstgrp_ptr; @@ -897,7 +887,7 @@ static void pim_bsm_fwd_whole_sz(struct pim_instance *pim, uint8_t *buf, { struct interface *ifp; struct pim_interface *pim_ifp; - struct in_addr dst_addr; + pim_addr dst_addr; uint32_t pim_mtu; bool no_fwd = false; bool ret = false; @@ -944,7 +934,7 @@ static void pim_bsm_fwd_whole_sz(struct pim_instance *pim, uint8_t *buf, bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp) { - struct in_addr dst_addr; + pim_addr dst_addr; struct pim_interface *pim_ifp; struct bsm_scope *scope; struct bsm_frag *bsfrag; @@ -953,17 +943,14 @@ bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp) bool no_fwd = true; bool ret = false; - if (PIM_DEBUG_BSM) { - pim_inet4_dump("", neigh->source_addr, neigh_src_str, - sizeof(neigh_src_str)); - zlog_debug("%s: New neighbor %s seen on %s", __func__, - neigh_src_str, ifp->name); - } + if (PIM_DEBUG_BSM) + zlog_debug("%s: New neighbor %pPA seen on %s", __func__, + &neigh->source_addr, ifp->name); pim_ifp = ifp->info; /* DR only forwards BSM packet */ - if (pim_ifp->pim_dr_addr.s_addr == pim_ifp->primary_address.s_addr) { + if (!pim_addr_cmp(pim_ifp->pim_dr_addr, pim_ifp->primary_address)) { if (PIM_DEBUG_BSM) zlog_debug( "%s: It is not DR, so don't forward BSM packet", @@ -1383,7 +1370,12 @@ int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf, } } - if (ip_hdr->ip_dst.s_addr == qpim_all_pim_routers_addr.s_addr) { +#if PIM_IPV == 4 + if (ip_hdr->ip_dst.s_addr == qpim_all_pim_routers_addr.s_addr) +#else + if (0) +#endif + { /* Multicast BSMs are only accepted if source interface & IP * match RPF towards the BSR's IP address, or they have * no-forward set diff --git a/pimd/pim_bsm.h b/pimd/pim_bsm.h index a536b5068..fceabef9e 100644 --- a/pimd/pim_bsm.h +++ b/pimd/pim_bsm.h @@ -115,7 +115,7 @@ struct bsm_rpinfo { uint32_t elapse_time; /* upd at expiry of elected RP node */ uint16_t rp_prio; /* RP priority */ uint16_t rp_holdtime; /* RP holdtime - g2rp timer value */ - struct in_addr rp_address; /* RP Address */ + pim_addr rp_address; /* RP Address */ struct bsgrp_node *bsgrp_node; /* Back ptr to bsgrp_node */ struct thread *g2rp_timer; /* Run only for elected RP node */ }; diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 2926a8ae7..1c7fcd62e 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -67,6 +67,7 @@ #include "lib/northbound_cli.h" #include "pim_errors.h" #include "pim_nb.h" +#include "pim_cmd_common.h" #ifndef VTYSH_EXTRACT_PL #include "pimd/pim_cmd_clippy.c" @@ -79,6 +80,14 @@ static struct cmd_node debug_node = { .config_write = pim_debug_config_write, }; +static inline bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match) +{ + return (pim_addr_is_any(match.grp) || + !pim_addr_cmp(match.grp, item.grp)) && + (pim_addr_is_any(match.src) || + !pim_addr_cmp(match.src, item.src)); +} + static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], const int argc, int *idx) { @@ -100,8 +109,6 @@ static void pim_show_assert_helper(struct vty *vty, struct pim_interface *pim_ifp, struct pim_ifchannel *ch, time_t now) { - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; char winner_str[INET_ADDRSTRLEN]; struct in_addr ifaddr; char uptime[10]; @@ -110,18 +117,16 @@ static void pim_show_assert_helper(struct vty *vty, ifaddr = pim_ifp->primary_address; - pim_inet4_dump("", ch->sg.src, ch_src_str, sizeof(ch_src_str)); - pim_inet4_dump("", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", ch->ifassert_winner, winner_str, sizeof(winner_str)); pim_time_uptime(uptime, sizeof(uptime), now - ch->ifassert_creation); pim_time_timer_to_mmss(timer, sizeof(timer), ch->t_ifassert_timer); - vty_out(vty, "%-16s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n", + vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-6s %-15s %-8s %-5s\n", ch->interface->name, - inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), ch_src_str, - ch_grp_str, pim_ifchannel_ifassert_name(ch->ifassert_state), + inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), &ch->sg.src, + &ch->sg.grp, pim_ifchannel_ifassert_name(ch->ifassert_state), winner_str, uptime, timer); } @@ -143,6 +148,9 @@ static void pim_show_assert(struct pim_instance *pim, struct vty *vty) continue; RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + if (ch->ifassert_state == PIM_IFASSERT_NOINFO) + continue; + pim_show_assert_helper(vty, pim_ifp, ch, now); } /* scan interface channels */ } @@ -152,19 +160,15 @@ static void pim_show_assert_internal_helper(struct vty *vty, struct pim_interface *pim_ifp, struct pim_ifchannel *ch) { - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; struct in_addr ifaddr; char buf[PREFIX_STRLEN]; ifaddr = pim_ifp->primary_address; - pim_inet4_dump("", ch->sg.src, ch_src_str, sizeof(ch_src_str)); - pim_inet4_dump("", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str)); - vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n", + vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-3s %-3s %-3s %-4s\n", ch->interface->name, - inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), - ch_src_str, ch_grp_str, + inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), &ch->sg.src, + &ch->sg.grp, PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no", pim_macro_ch_could_assert_eval(ch) ? "yes" : "no", PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) ? "yes" @@ -201,8 +205,6 @@ static void pim_show_assert_metric_helper(struct vty *vty, struct pim_interface *pim_ifp, struct pim_ifchannel *ch) { - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; char addr_str[INET_ADDRSTRLEN]; struct pim_assert_metric am; struct in_addr ifaddr; @@ -213,14 +215,12 @@ static void pim_show_assert_metric_helper(struct vty *vty, am = pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); - pim_inet4_dump("", ch->sg.src, ch_src_str, sizeof(ch_src_str)); - pim_inet4_dump("", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", am.ip_address, addr_str, sizeof(addr_str)); - vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %4u %6u %-15s\n", + vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-3s %4u %6u %-15s\n", ch->interface->name, - inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), - ch_src_str, ch_grp_str, am.rpt_bit_flag ? "yes" : "no", + inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), &ch->sg.src, + &ch->sg.grp, am.rpt_bit_flag ? "yes" : "no", am.metric_preference, am.route_metric, addr_str); } @@ -248,8 +248,6 @@ static void pim_show_assert_winner_metric_helper(struct vty *vty, struct pim_interface *pim_ifp, struct pim_ifchannel *ch) { - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; char addr_str[INET_ADDRSTRLEN]; struct pim_assert_metric *am; struct in_addr ifaddr; @@ -261,8 +259,6 @@ static void pim_show_assert_winner_metric_helper(struct vty *vty, am = &ch->ifassert_winner_metric; - pim_inet4_dump("", ch->sg.src, ch_src_str, sizeof(ch_src_str)); - pim_inet4_dump("", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", am->ip_address, addr_str, sizeof(addr_str)); if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) @@ -276,11 +272,11 @@ static void pim_show_assert_winner_metric_helper(struct vty *vty, else snprintf(metr_str, sizeof(metr_str), "%6u", am->route_metric); - vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n", + vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-3s %-4s %-6s %-15s\n", ch->interface->name, - inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), ch_src_str, - ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str, metr_str, - addr_str); + inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), &ch->sg.src, + &ch->sg.grp, am->rpt_bit_flag ? "yes" : "no", pref_str, + metr_str, addr_str); } static void pim_show_assert_winner_metric(struct pim_instance *pim, @@ -340,14 +336,10 @@ static void pim_show_membership_helper(struct vty *vty, struct pim_ifchannel *ch, struct json_object *json) { - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; + char ch_grp_str[PIM_ADDRSTRLEN]; json_object *json_iface = NULL; json_object *json_row = NULL; - pim_inet4_dump("", ch->sg.src, ch_src_str, sizeof(ch_src_str)); - pim_inet4_dump("", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str)); - json_object_object_get_ex(json, ch->interface->name, &json_iface); if (!json_iface) { json_iface = json_object_new_object(); @@ -355,8 +347,10 @@ static void pim_show_membership_helper(struct vty *vty, json_object_object_add(json, ch->interface->name, json_iface); } + snprintfrr(ch_grp_str, sizeof(ch_grp_str), "%pPAs", &ch->sg.grp); + json_row = json_object_new_object(); - json_object_string_add(json_row, "source", ch_src_str); + json_object_string_addf(json_row, "source", "%pPAs", &ch->sg.src); json_object_string_add(json_row, "group", ch_grp_str); json_object_string_add(json_row, "localMembership", ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO @@ -364,6 +358,7 @@ static void pim_show_membership_helper(struct vty *vty, : "INCLUDE"); json_object_object_add(json_iface, ch_grp_str, json_row); } + static void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj) { @@ -460,8 +455,7 @@ static void pim_show_membership(struct pim_instance *pim, struct vty *vty, json_object_free(json); } -static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp, - int mloop) +static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp) { vty_out(vty, "Flags\n"); vty_out(vty, "-----\n"); @@ -474,7 +468,6 @@ static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp, vty_out(vty, "Interface Index : %d\n", ifp->ifindex); vty_out(vty, "Multicast : %s\n", if_is_multicast(ifp) ? "yes" : "no"); - vty_out(vty, "Multicast Loop : %d\n", mloop); vty_out(vty, "Promiscuous : %s\n", (ifp->flags & IFF_PROMISC) ? "yes" : "no"); vty_out(vty, "\n"); @@ -581,7 +574,6 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, char other_hhmmss[10]; int found_ifname = 0; int sqi; - int mloop = 0; long gmi_msec; /* Group Membership Interval */ long lmqt_msec; long ohpi_msec; @@ -644,11 +636,6 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, qri_msec = pim_ifp->gm_query_max_response_time_dsec * 100; - if (pim_ifp->pim_sock_fd >= 0) - mloop = pim_socket_mcastloop_get( - pim_ifp->pim_sock_fd); - else - mloop = 0; lmqc = pim_ifp->gm_last_member_query_count; if (uj) { @@ -781,7 +768,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, vty_out(vty, "\n"); vty_out(vty, "\n"); - pim_print_ifp_flags(vty, ifp, mloop); + pim_print_ifp_flags(vty, ifp); } } } @@ -908,7 +895,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim, char src_str[INET_ADDRSTRLEN]; char stat_uptime[10]; char uptime[10]; - int mloop = 0; int found_ifname = 0; int print_header; json_object *json = NULL; @@ -950,10 +936,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim, pim_ifp->pim_hello_period); pim_time_uptime(stat_uptime, sizeof(stat_uptime), now - pim_ifp->pim_ifstat_start); - if (pim_ifp->pim_sock_fd >= 0) - mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd); - else - mloop = 0; if (uj) { char pbuf[PREFIX2STR_BUFFER]; @@ -1045,10 +1027,10 @@ static void pim_show_interfaces_single(struct pim_instance *pim, json_fhr_sources = json_object_new_object(); - pim_inet4_dump("", up->sg.src, src_str, - sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, - sizeof(grp_str)); + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", + &up->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", + &up->sg.src); pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition); @@ -1101,8 +1083,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim, pim_ifp->pim_ifstat_hello_sendfail); json_object_int_add(json_row, "helloGenerationId", pim_ifp->pim_generation_id); - json_object_int_add(json_row, "flagMulticastLoop", - mloop); json_object_int_add( json_row, "effectivePropagationDelay", @@ -1222,15 +1202,11 @@ static void pim_show_interfaces_single(struct pim_instance *pim, print_header = 0; } - pim_inet4_dump("", up->sg.src, src_str, - sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, - sizeof(grp_str)); pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition); vty_out(vty, - "%s : %s is a source, uptime is %s\n", - grp_str, src_str, uptime); + "%pPAs : %pPAs is a source, uptime is %s\n", + &up->sg.grp, &up->sg.src, uptime); } if (!print_header) { @@ -1259,7 +1235,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim, vty_out(vty, "\n"); vty_out(vty, "\n"); - pim_print_ifp_flags(vty, ifp, mloop); + pim_print_ifp_flags(vty, ifp); vty_out(vty, "Join Prune Interval\n"); vty_out(vty, "-------------------\n"); @@ -1308,14 +1284,16 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty, const char *ifname, bool uj) { struct interface *ifp; - struct igmp_stats rx_stats; + struct igmp_stats igmp_stats; - igmp_stats_init(&rx_stats); + igmp_stats_init(&igmp_stats); FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; - struct listnode *sock_node; + struct listnode *sock_node, *source_node, *group_node; struct gm_sock *igmp; + struct gm_group *group; + struct gm_source *src; pim_ifp = ifp->info; @@ -1325,9 +1303,27 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty, if (ifname && strcmp(ifname, ifp->name)) continue; + igmp_stats.joins_failed += pim_ifp->igmp_ifstat_joins_failed; + igmp_stats.joins_sent += pim_ifp->igmp_ifstat_joins_sent; + igmp_stats.total_groups += + pim_ifp->gm_group_list + ? listcount(pim_ifp->gm_group_list) + : 0; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, group_node, + group)) { + for (ALL_LIST_ELEMENTS_RO(group->group_source_list, + source_node, src)) { + if (pim_addr_is_any(src->source_addr)) + continue; + + igmp_stats.total_source_groups++; + } + } + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { - igmp_stats_add(&rx_stats, &igmp->rx_stats); + igmp_stats_add(&igmp_stats, &igmp->igmp_stats); } } if (uj) { @@ -1339,36 +1335,58 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty, json_object_string_add(json_row, "name", ifname ? ifname : "global"); - json_object_int_add(json_row, "queryV1", rx_stats.query_v1); - json_object_int_add(json_row, "queryV2", rx_stats.query_v2); - json_object_int_add(json_row, "queryV3", rx_stats.query_v3); - json_object_int_add(json_row, "leaveV3", rx_stats.leave_v2); - json_object_int_add(json_row, "reportV1", rx_stats.report_v1); - json_object_int_add(json_row, "reportV2", rx_stats.report_v2); - json_object_int_add(json_row, "reportV3", rx_stats.report_v3); + json_object_int_add(json_row, "queryV1", igmp_stats.query_v1); + json_object_int_add(json_row, "queryV2", igmp_stats.query_v2); + json_object_int_add(json_row, "queryV3", igmp_stats.query_v3); + json_object_int_add(json_row, "leaveV2", igmp_stats.leave_v2); + json_object_int_add(json_row, "reportV1", igmp_stats.report_v1); + json_object_int_add(json_row, "reportV2", igmp_stats.report_v2); + json_object_int_add(json_row, "reportV3", igmp_stats.report_v3); json_object_int_add(json_row, "mtraceResponse", - rx_stats.mtrace_rsp); + igmp_stats.mtrace_rsp); json_object_int_add(json_row, "mtraceRequest", - rx_stats.mtrace_req); + igmp_stats.mtrace_req); json_object_int_add(json_row, "unsupported", - rx_stats.unsupported); + igmp_stats.unsupported); + json_object_int_add(json_row, "totalGroups", + igmp_stats.total_groups); + json_object_int_add(json_row, "totalSourceGroups", + igmp_stats.total_source_groups); + json_object_int_add(json_row, "joinsFailed", + igmp_stats.joins_failed); + json_object_int_add(json_row, "joinsSent", + igmp_stats.joins_sent); json_object_object_add(json, ifname ? ifname : "global", json_row); vty_json(vty, json); } else { - vty_out(vty, "IGMP RX statistics\n"); - vty_out(vty, "Interface : %s\n", + vty_out(vty, "IGMP statistics\n"); + vty_out(vty, "Interface : %s\n", ifname ? ifname : "global"); - vty_out(vty, "V1 query : %u\n", rx_stats.query_v1); - vty_out(vty, "V2 query : %u\n", rx_stats.query_v2); - vty_out(vty, "V3 query : %u\n", rx_stats.query_v3); - vty_out(vty, "V2 leave : %u\n", rx_stats.leave_v2); - vty_out(vty, "V1 report : %u\n", rx_stats.report_v1); - vty_out(vty, "V2 report : %u\n", rx_stats.report_v2); - vty_out(vty, "V3 report : %u\n", rx_stats.report_v3); - vty_out(vty, "mtrace response : %u\n", rx_stats.mtrace_rsp); - vty_out(vty, "mtrace request : %u\n", rx_stats.mtrace_req); - vty_out(vty, "unsupported : %u\n", rx_stats.unsupported); + vty_out(vty, "V1 query : %u\n", igmp_stats.query_v1); + vty_out(vty, "V2 query : %u\n", igmp_stats.query_v2); + vty_out(vty, "V3 query : %u\n", igmp_stats.query_v3); + vty_out(vty, "V2 leave : %u\n", igmp_stats.leave_v2); + vty_out(vty, "V1 report : %u\n", + igmp_stats.report_v1); + vty_out(vty, "V2 report : %u\n", + igmp_stats.report_v2); + vty_out(vty, "V3 report : %u\n", + igmp_stats.report_v3); + vty_out(vty, "mtrace response : %u\n", + igmp_stats.mtrace_rsp); + vty_out(vty, "mtrace request : %u\n", + igmp_stats.mtrace_req); + vty_out(vty, "unsupported : %u\n", + igmp_stats.unsupported); + vty_out(vty, "joins failed : %u\n", + igmp_stats.joins_failed); + vty_out(vty, "joins sent : %u\n", + igmp_stats.joins_sent); + vty_out(vty, "total groups : %u\n", + igmp_stats.total_groups); + vty_out(vty, "total source groups : %u\n", + igmp_stats.total_source_groups); } } @@ -1650,8 +1668,6 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp, struct pim_ifchannel *ch, json_object *json, time_t now, bool uj) { - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; json_object *json_iface = NULL; json_object *json_row = NULL; json_object *json_grp = NULL; @@ -1663,9 +1679,6 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp, ifaddr = pim_ifp->primary_address; - pim_inet4_dump("", ch->sg.src, ch_src_str, sizeof(ch_src_str)); - pim_inet4_dump("", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str)); - pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation); pim_time_timer_to_mmss(expire, sizeof(expire), ch->t_ifjoin_expiry_timer); @@ -1673,6 +1686,14 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp, ch->t_ifjoin_prune_pending_timer); if (uj) { + char ch_grp_str[PIM_ADDRSTRLEN]; + char ch_src_str[PIM_ADDRSTRLEN]; + + snprintfrr(ch_grp_str, sizeof(ch_grp_str), "%pPAs", + &ch->sg.grp); + snprintfrr(ch_src_str, sizeof(ch_src_str), "%pPAs", + &ch->sg.src); + json_object_object_get_ex(json, ch->interface->name, &json_iface); @@ -1712,10 +1733,10 @@ CPP_NOTICE("Remove JSON object commands with keys starting with capital") } else json_object_object_add(json_grp, ch_src_str, json_row); } else { - vty_out(vty, "%-16s %-15s %-15s %-15s %-10s %8s %-6s %5s\n", + vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %-10s %8s %-6s %5s\n", ch->interface->name, inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), - ch_src_str, ch_grp_str, + &ch->sg.src, &ch->sg.grp, pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags), uptime, expire, prune); } @@ -1744,11 +1765,7 @@ static void pim_show_join(struct pim_instance *pim, struct vty *vty, continue; RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { - if (sg->grp.s_addr != INADDR_ANY - && sg->grp.s_addr != ch->sg.grp.s_addr) - continue; - if (sg->src.s_addr != INADDR_ANY - && sg->src.s_addr != ch->sg.src.s_addr) + if (!pim_sgaddr_match(ch->sg, *sg)) continue; pim_show_join_helper(vty, pim_ifp, ch, json, now, uj); } /* scan interface channels */ @@ -2439,8 +2456,6 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n"); frr_each (rb_pim_upstream, &pim->upstream_head, up) { - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; char uptime[10]; char join_timer[10]; char rs_timer[10]; @@ -2448,15 +2463,9 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, char msdp_reg_timer[10]; char state_str[PIM_REG_STATE_STR_LEN]; - if (sg->grp.s_addr != INADDR_ANY - && sg->grp.s_addr != up->sg.grp.s_addr) - continue; - if (sg->src.s_addr != INADDR_ANY - && sg->src.s_addr != up->sg.src.s_addr) + if (!pim_sgaddr_match(up->sg, *sg)) continue; - pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition); pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), @@ -2469,9 +2478,9 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, if (!up->t_join_timer && up->rpf.source_nexthop.interface) { struct pim_neighbor *nbr; - nbr = pim_neighbor_find( + nbr = pim_neighbor_find_prefix( up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + &up->rpf.rpf_addr); if (nbr) pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), @@ -2497,6 +2506,14 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, } if (uj) { + char grp_str[PIM_ADDRSTRLEN]; + char src_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", + &up->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", + &up->sg.src); + json_object_object_get_ex(json, grp_str, &json_group); if (!json_group) { @@ -2520,8 +2537,8 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, * we are the FHR, else we just put * the RP as the rpfAddress */ - if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR - || up->sg.src.s_addr == INADDR_ANY) { + if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR || + pim_addr_is_any(up->sg.src)) { char rpf[PREFIX_STRLEN]; struct pim_rpf *rpg; @@ -2560,12 +2577,12 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, json_object_object_add(json_group, src_str, json_row); } else { vty_out(vty, - "%-16s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n", + "%-16s%-15pPAs %-15pPAs %-11s %-8s %-9s %-9s %-9s %6d\n", up->rpf.source_nexthop.interface ? up->rpf.source_nexthop.interface->name : "Unknown", - src_str, grp_str, state_str, uptime, join_timer, - rs_timer, ka_timer, up->ref_count); + &up->sg.src, &up->sg.grp, state_str, uptime, + join_timer, rs_timer, ka_timer, up->ref_count); } } @@ -2581,14 +2598,15 @@ static void pim_show_channel_helper(struct pim_instance *pim, { struct pim_upstream *up = ch->upstream; json_object *json_group = NULL; - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; json_object *json_row = NULL; - pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); - if (uj) { + char grp_str[PIM_ADDRSTRLEN]; + char src_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", &up->sg.src); + json_object_object_get_ex(json, grp_str, &json_group); if (!json_group) { @@ -2619,8 +2637,8 @@ static void pim_show_channel_helper(struct pim_instance *pim, json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-16s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n", - ch->interface->name, src_str, grp_str, + vty_out(vty, "%-16s %-15pPAs %-15pPAs %-10s %-5s %-10s %-11s %-6s\n", + ch->interface->name, &up->sg.src, &up->sg.grp, pim_macro_ch_lost_assert(ch) ? "yes" : "no", pim_macro_chisin_joins(ch) ? "yes" : "no", pim_macro_chisin_pim_include(ch) ? "yes" : "no", @@ -2671,14 +2689,15 @@ static void pim_show_join_desired_helper(struct pim_instance *pim, json_object *json, bool uj) { json_object *json_group = NULL; - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; json_object *json_row = NULL; - pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); - if (uj) { + char grp_str[PIM_ADDRSTRLEN]; + char src_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", &up->sg.src); + json_object_object_get_ex(json, grp_str, &json_group); if (!json_group) { @@ -2698,8 +2717,8 @@ static void pim_show_join_desired_helper(struct pim_instance *pim, json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-15s %-15s %-6s\n", - src_str, grp_str, + vty_out(vty, "%-15pPAs %-15pPAs %-6s\n", + &up->sg.src, &up->sg.grp, pim_upstream_evaluate_join_desired(pim, up) ? "yes" : "no"); } @@ -2743,8 +2762,6 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, "Source Group RpfIface RibNextHop RpfAddress \n"); frr_each (rb_pim_upstream, &pim->upstream_head, up) { - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; char rpf_nexthop_str[PREFIX_STRLEN]; char rpf_addr_str[PREFIX_STRLEN]; struct pim_rpf *rpf; @@ -2752,8 +2769,6 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, rpf = &up->rpf; - pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); pim_addr_dump("", &rpf->source_nexthop.mrib_nexthop_addr, rpf_nexthop_str, sizeof(rpf_nexthop_str)); @@ -2763,6 +2778,14 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""; if (uj) { + char grp_str[PIM_ADDRSTRLEN]; + char src_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", + &up->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", + &up->sg.src); + json_object_object_get_ex(json, grp_str, &json_group); if (!json_group) { @@ -2783,9 +2806,9 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, rpf_addr_str); json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-15s %-15s %-16s %-15s %-15s\n", src_str, - grp_str, rpf_ifname, rpf_nexthop_str, - rpf_addr_str); + vty_out(vty, "%-15pPAs %-15pPAs %-16s %-15s %-15s\n", + &up->sg.src, &up->sg.grp, rpf_ifname, + rpf_nexthop_str, rpf_addr_str); } } @@ -2877,15 +2900,11 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj) } frr_each (rb_pim_upstream, &pim->upstream_head, up) { - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; char rpf_addr_str[PREFIX_STRLEN]; char rib_nexthop_str[PREFIX_STRLEN]; const char *rpf_ifname; struct pim_rpf *rpf = &up->rpf; - pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); pim_addr_dump("", &rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); pim_addr_dump("", @@ -2895,6 +2914,14 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj) rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""; if (uj) { + char grp_str[PIM_ADDRSTRLEN]; + char src_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", + &up->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", + &up->sg.src); + json_object_object_get_ex(json, grp_str, &json_group); if (!json_group) { @@ -2921,9 +2948,9 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj) json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-15s %-15s %-16s %-15s %-15s %6d %4d\n", - src_str, grp_str, rpf_ifname, rpf_addr_str, - rib_nexthop_str, + vty_out(vty, "%-15pPAs %-15pPAs %-16s %-15s %-15s %6d %4d\n", + &up->sg.src, &up->sg.grp, rpf_ifname, + rpf_addr_str, rib_nexthop_str, rpf->source_nexthop.mrib_route_metric, rpf->source_nexthop.mrib_metric_preference); } @@ -3512,15 +3539,24 @@ static void igmp_show_group_retransmission(struct pim_instance *pim, } /* scan interfaces */ } -static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) +static void igmp_show_sources(struct pim_instance *pim, struct vty *vty, + bool uj) { struct interface *ifp; time_t now; + json_object *json = NULL; + json_object *json_iface = NULL; + json_object *json_group = NULL; + json_object *json_source = NULL; + json_object *json_sources = NULL; now = pim_time_monotonic_sec(); - vty_out(vty, - "Interface Group Source Timer Fwd Uptime \n"); + if (uj) + json = json_object_new_object(); + else + vty_out(vty, + "Interface Address Group Source Timer Fwd Uptime \n"); /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -3557,17 +3593,70 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) pim_time_uptime(uptime, sizeof(uptime), now - src->source_creation); - vty_out(vty, "%-16s %-15s %-15s %5s %3s %8s\n", - ifp->name, group_str, source_str, mmss, - IGMP_SOURCE_TEST_FORWARDING( - src->source_flags) - ? "Y" - : "N", - uptime); + if (uj) { + json_object_object_get_ex( + json, ifp->name, &json_iface); + if (!json_iface) { + json_iface = + json_object_new_object(); + json_object_string_add( + json_iface, "name", + ifp->name); + json_object_object_add( + json, ifp->name, + json_iface); + } + json_object_object_get_ex(json_iface, + group_str, + &json_group); + + if (!json_group) { + json_group = + json_object_new_object(); + json_object_string_add( + json_group, "group", + group_str); + json_object_object_add( + json_iface, group_str, + json_group); + json_sources = + json_object_new_array(); + json_object_object_add( + json_group, "sources", + json_sources); + } + json_source = json_object_new_object(); + json_object_string_add(json_source, + "source", + source_str); + json_object_string_add(json_source, + "timer", mmss); + json_object_boolean_add( + json_source, "forwarded", + IGMP_SOURCE_TEST_FORWARDING( + src->source_flags)); + json_object_string_add( + json_source, "uptime", uptime); + json_object_array_add(json_sources, + json_source); + + } else { + vty_out(vty, + "%-16s %-15s %-15s %5s %3s %8s\n", + ifp->name, group_str, + source_str, mmss, + IGMP_SOURCE_TEST_FORWARDING( + src->source_flags) + ? "Y" + : "N", + uptime); + } } /* scan group sources */ } /* scan igmp groups */ } /* scan interfaces */ + if (uj) + vty_json(vty, json); } static void igmp_show_source_retransmission(struct pim_instance *pim, @@ -3722,32 +3811,6 @@ static void clear_interfaces(struct pim_instance *pim) return CMD_WARNING_CONFIG_FAILED; \ } -/** - * Get current node VRF name. - * - * NOTE: - * In case of failure it will print error message to user. - * - * \returns name or NULL if failed to get VRF. - */ -static const char *pim_cli_get_vrf_name(struct vty *vty) -{ - const struct lyd_node *vrf_node; - - /* Not inside any VRF context. */ - if (vty->xpath_index == 0) - return VRF_DEFAULT_NAME; - - vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (vrf_node == NULL) { - vty_out(vty, "%% Failed to get vrf dnode in configuration\n"); - return NULL; - } - - return yang_dnode_get_string(vrf_node, "./name"); -} - -#if PIM_IPV != 6 /** * Compatibility function to keep the legacy mesh group CLI behavior: * Delete group when there are no more configurations in it. @@ -3795,7 +3858,6 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, /* No configurations found: delete it. */ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); } -#endif /* PIM_IPV != 6 */ DEFUN (clear_ip_interfaces, clear_ip_interfaces_cmd, @@ -3863,7 +3925,6 @@ static void clear_mroute(struct pim_instance *pim) /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp = ifp->info; - struct gm_group *grp; struct pim_ifchannel *ch; if (!pim_ifp) @@ -3876,7 +3937,9 @@ static void clear_mroute(struct pim_instance *pim) pim_ifchannel_delete(ch); } +#if PIM_IPV == 4 /* clean up all igmp groups */ + struct gm_group *grp; if (pim_ifp->gm_group_list) { while (pim_ifp->gm_group_list->count) { @@ -3884,6 +3947,7 @@ static void clear_mroute(struct pim_instance *pim) igmp_group_delete(grp); } } +#endif } /* clean up all upstreams*/ @@ -3969,6 +4033,8 @@ DEFUN (clear_ip_pim_interface_traffic, pim_ifp->pim_ifstat_assert_send = 0; pim_ifp->pim_ifstat_bsm_rx = 0; pim_ifp->pim_ifstat_bsm_tx = 0; + pim_ifp->igmp_ifstat_joins_sent = 0; + pim_ifp->igmp_ifstat_joins_failed = 0; } return CMD_SUCCESS; @@ -4213,12 +4279,13 @@ DEFUN (show_ip_igmp_groups_retransmissions, DEFUN (show_ip_igmp_sources, show_ip_igmp_sources_cmd, - "show ip igmp [vrf NAME] sources", + "show ip igmp [vrf NAME] sources [json]", SHOW_STR IP_STR IGMP_STR VRF_CMD_HELP_STR - IGMP_SOURCE_STR) + IGMP_SOURCE_STR + JSON_STR) { int idx = 2; struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); @@ -4226,7 +4293,7 @@ DEFUN (show_ip_igmp_sources, if (!vrf) return CMD_WARNING; - igmp_show_sources(vrf->info, vty); + igmp_show_sources(vrf->info, vty, use_json(argc, argv)); return CMD_SUCCESS; } @@ -4626,18 +4693,13 @@ static void pim_show_jp_agg_helper(struct vty *vty, struct pim_upstream *up, int is_join) { - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; char rpf_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); /* pius->address.s_addr */ pim_inet4_dump("", neigh->source_addr, rpf_str, sizeof(rpf_str)); - vty_out(vty, "%-16s %-15s %-15s %-15s %5s\n", - ifp->name, rpf_str, src_str, - grp_str, is_join?"J":"P"); + vty_out(vty, "%-16s %-15s %-15pPAs %-15pPAs %5s\n", ifp->name, rpf_str, + &up->sg.src, &up->sg.grp, is_join ? "J" : "P"); } static void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty) @@ -4795,8 +4857,8 @@ static void pim_show_mlag_up_detail(struct vrf *vrf, struct vty *vty, const char *src_or_group, const char *group, bool uj) { - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; + char src_str[PIM_ADDRSTRLEN]; + char grp_str[PIM_ADDRSTRLEN]; struct pim_upstream *up; struct pim_instance *pim = vrf->info; json_object *json = NULL; @@ -4813,8 +4875,9 @@ static void pim_show_mlag_up_detail(struct vrf *vrf, && !pim_up_mlag_is_local(up)) continue; - pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", &up->sg.src); + /* XXX: strcmps are clearly inefficient. we should do uint comps * here instead. */ @@ -4840,8 +4903,6 @@ static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj) json_object *json = NULL; json_object *json_row; struct pim_upstream *up; - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; struct pim_instance *pim = vrf->info; json_object *json_group = NULL; @@ -4857,11 +4918,16 @@ static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj) && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE) && !pim_up_mlag_is_local(up)) continue; - pim_inet4_dump("", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", up->sg.grp, grp_str, sizeof(grp_str)); if (uj) { + char src_str[PIM_ADDRSTRLEN]; + char grp_str[PIM_ADDRSTRLEN]; json_object *own_list = NULL; + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", + &up->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", + &up->sg.src); + json_object_object_get_ex(json, grp_str, &json_group); if (!json_group) { json_group = json_object_new_object(); @@ -4908,8 +4974,8 @@ static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj) if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)) strlcat(own_str, "I", sizeof(own_str)); vty_out(vty, - "%-15s %-15s %-6s %-11u %-10u %2s\n", - src_str, grp_str, own_str, + "%-15pPAs %-15pPAs %-6s %-11u %-10u %2s\n", + &up->sg.src, &up->sg.grp, own_str, pim_up_mlag_local_cost(up), pim_up_mlag_peer_cost(up), PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags) @@ -5299,39 +5365,56 @@ DEFUN (show_ip_pim_upstream_rpf, DEFUN (show_ip_pim_rp, show_ip_pim_rp_cmd, - "show ip pim [vrf NAME] rp-info [json]", + "show ip pim [vrf NAME] rp-info [A.B.C.D/M] [json]", SHOW_STR IP_STR PIM_STR VRF_CMD_HELP_STR "PIM RP information\n" + "Multicast Group range\n" JSON_STR) { int idx = 2; struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); bool uj = use_json(argc, argv); + struct prefix *range = NULL; if (!vrf) return CMD_WARNING; - pim_rp_show_information(vrf->info, vty, uj); + if (argv_find(argv, argc, "A.B.C.D/M", &idx)) { + range = prefix_new(); + (void)str2prefix(argv[idx]->arg, range); + apply_mask(range); + } + + pim_rp_show_information(vrf->info, range, vty, uj); return CMD_SUCCESS; } DEFUN (show_ip_pim_rp_vrf_all, show_ip_pim_rp_vrf_all_cmd, - "show ip pim vrf all rp-info [json]", + "show ip pim vrf all rp-info [A.B.C.D/M] [json]", SHOW_STR IP_STR PIM_STR VRF_CMD_HELP_STR "PIM RP information\n" + "Multicast Group range\n" JSON_STR) { + int idx = 0; bool uj = use_json(argc, argv); struct vrf *vrf; bool first = true; + struct prefix *range = NULL; + + if (argv_find(argv, argc, "A.B.C.D/M", &idx)) { + range = prefix_new(); + (void)str2prefix(argv[idx]->arg, range); + apply_mask(range); + } if (uj) vty_out(vty, "{ "); @@ -5343,7 +5426,7 @@ DEFUN (show_ip_pim_rp_vrf_all, first = false; } else vty_out(vty, "VRF: %s\n", vrf->name); - pim_rp_show_information(vrf->info, vty, uj); + pim_rp_show_information(vrf->info, range, vty, uj); } if (uj) vty_out(vty, "}\n"); @@ -5874,11 +5957,11 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, if (!c_oil->installed) continue; - if (sg->grp.s_addr != INADDR_ANY - && sg->grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr) + if (!pim_addr_is_any(sg->grp) && + pim_addr_cmp(sg->grp, c_oil->oil.mfcc_mcastgrp)) continue; - if (sg->src.s_addr != INADDR_ANY - && sg->src.s_addr != c_oil->oil.mfcc_origin.s_addr) + if (!pim_addr_is_any(sg->src) && + pim_addr_cmp(sg->src, c_oil->oil.mfcc_origin)) continue; pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, grp_str, @@ -6712,38 +6795,12 @@ DEFUN (ip_pim_spt_switchover_infinity, "SPT-Switchover\n" "Never switch to SPT Tree\n") { - const char *vrfname; - char spt_plist_xpath[XPATH_MAXLEN]; - char spt_action_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - - snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); - - if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath)) - nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, - NULL); - nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, - "PIM_SPT_INFINITY"); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_spt_switchover_infinity_cmd(vty); } -DEFUN (ip_pim_spt_switchover_infinity_plist, +DEFPY (ip_pim_spt_switchover_infinity_plist, ip_pim_spt_switchover_infinity_plist_cmd, - "ip pim spt-switchover infinity-and-beyond prefix-list WORD", + "ip pim spt-switchover infinity-and-beyond prefix-list WORD$plist", IP_STR PIM_STR "SPT-Switchover\n" @@ -6751,32 +6808,7 @@ DEFUN (ip_pim_spt_switchover_infinity_plist, "Prefix-List to control which groups to switch\n" "Prefix-List name\n") { - const char *vrfname; - char spt_plist_xpath[XPATH_MAXLEN]; - char spt_action_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - - snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); - - nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, - "PIM_SPT_INFINITY"); - nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, - argv[5]->arg); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } DEFUN (no_ip_pim_spt_switchover_infinity, @@ -6788,31 +6820,7 @@ DEFUN (no_ip_pim_spt_switchover_infinity, "SPT_Switchover\n" "Never switch to SPT Tree\n") { - const char *vrfname; - char spt_plist_xpath[XPATH_MAXLEN]; - char spt_action_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - - snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); - - nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, - "PIM_SPT_IMMEDIATE"); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_spt_switchover_cmd(vty); } DEFUN (no_ip_pim_spt_switchover_infinity_plist, @@ -6826,31 +6834,7 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, "Prefix-List to control which groups to switch\n" "Prefix-List name\n") { - const char *vrfname; - char spt_plist_xpath[XPATH_MAXLEN]; - char spt_action_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - - snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); - - nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, - "PIM_SPT_IMMEDIATE"); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_spt_switchover_cmd(vty); } DEFPY (pim_register_accept_list, @@ -6885,23 +6869,15 @@ DEFPY (pim_register_accept_list, return nb_cli_apply_changes(vty, NULL); } -DEFUN (ip_pim_joinprune_time, +DEFPY (ip_pim_joinprune_time, ip_pim_joinprune_time_cmd, - "ip pim join-prune-interval (1-65535)", + "ip pim join-prune-interval (1-65535)$jpi", IP_STR "pim multicast routing\n" "Join Prune Send Interval\n" "Seconds\n") { - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, - "frr-routing:ipv4"); - strlcat(xpath, "/join-prune-interval", sizeof(xpath)); - - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_join_prune_cmd(vty, jpi_str); } DEFUN (no_ip_pim_joinprune_time, @@ -6913,34 +6889,18 @@ DEFUN (no_ip_pim_joinprune_time, "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, - "frr-routing:ipv4"); - strlcat(xpath, "/join-prune-interval", sizeof(xpath)); - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_join_prune_cmd(vty); } -DEFUN (ip_pim_register_suppress, +DEFPY (ip_pim_register_suppress, ip_pim_register_suppress_cmd, - "ip pim register-suppress-time (1-65535)", + "ip pim register-suppress-time (1-65535)$rst", IP_STR "pim multicast routing\n" "Register Suppress Timer\n" "Seconds\n") { - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, - "frr-routing:ipv4"); - strlcat(xpath, "/register-suppress-time", sizeof(xpath)); - - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_register_suppress_cmd(vty, rst_str); } DEFUN (no_ip_pim_register_suppress, @@ -6952,43 +6912,19 @@ DEFUN (no_ip_pim_register_suppress, "Register Suppress Timer\n" IGNORED_IN_NO_STR) { - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, - "frr-routing:ipv4"); - strlcat(xpath, "/register-suppress-time", sizeof(xpath)); - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_register_suppress_cmd(vty); } -DEFUN (ip_pim_rp_keep_alive, +DEFPY (ip_pim_rp_keep_alive, ip_pim_rp_keep_alive_cmd, - "ip pim rp keep-alive-timer (1-65535)", + "ip pim rp keep-alive-timer (1-65535)$kat", IP_STR "pim multicast routing\n" "Rendevous Point\n" "Keep alive Timer\n" "Seconds\n") { - const char *vrfname; - char rp_ka_timer_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); - - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - argv[4]->arg); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_rp_kat_cmd(vty, kat_str); } DEFUN (no_ip_pim_rp_keep_alive, @@ -7001,64 +6937,18 @@ DEFUN (no_ip_pim_rp_keep_alive, "Keep alive Timer\n" IGNORED_IN_NO_STR) { - const char *vrfname; - char rp_ka_timer[6]; - char rp_ka_timer_xpath[XPATH_MAXLEN]; - uint v; - char rs_timer_xpath[XPATH_MAXLEN]; - - snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), - FRR_PIM_ROUTER_XPATH, "frr-routing:ipv4"); - strlcat(rs_timer_xpath, "/register-suppress-time", - sizeof(rs_timer_xpath)); - - /* RFC4601 */ - v = yang_dnode_get_uint16(vty->candidate_config->dnode, - rs_timer_xpath); - v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT; - if (v > UINT16_MAX) - v = UINT16_MAX; - snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v); - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); - - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rp_ka_timer); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_rp_kat_cmd(vty); } -DEFUN (ip_pim_keep_alive, +DEFPY (ip_pim_keep_alive, ip_pim_keep_alive_cmd, - "ip pim keep-alive-timer (1-65535)", + "ip pim keep-alive-timer (1-65535)$kat", IP_STR "pim multicast routing\n" "Keep alive Timer\n" "Seconds\n") { - const char *vrfname; - char ka_timer_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); - - nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, - argv[3]->arg); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_keepalivetimer_cmd(vty, kat_str); } DEFUN (no_ip_pim_keep_alive, @@ -7070,23 +6960,10 @@ DEFUN (no_ip_pim_keep_alive, "Keep alive Timer\n" IGNORED_IN_NO_STR) { - const char *vrfname; - char ka_timer_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); - - nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_keepalivetimer_cmd(vty); } -DEFUN (ip_pim_packets, +DEFPY (ip_pim_packets, ip_pim_packets_cmd, "ip pim packets (1-255)", IP_STR @@ -7094,15 +6971,7 @@ DEFUN (ip_pim_packets, "packets to process at one time per fd\n" "Number of packets\n") { - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, - "frr-routing:ipv4"); - strlcat(xpath, "/packets", sizeof(xpath)); - - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_pim_packet_cmd(vty, packets_str); } DEFUN (no_ip_pim_packets, @@ -7114,15 +6983,7 @@ DEFUN (no_ip_pim_packets, "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, - "frr-routing:ipv4"); - strlcat(xpath, "/packets", sizeof(xpath)); - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_pim_packet_cmd(vty); } DEFPY (igmp_group_watermark, @@ -7207,98 +7068,36 @@ DEFUN (no_ip_pim_v6_secondary, return nb_cli_apply_changes(vty, NULL); } -DEFUN (ip_pim_rp, +DEFPY (ip_pim_rp, ip_pim_rp_cmd, - "ip pim rp A.B.C.D [A.B.C.D/M]", + "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", IP_STR "pim multicast routing\n" "Rendevous Point\n" "ip address of RP\n" "Group Address range to cover\n") { - const char *vrfname; - int idx_rp = 3, idx_group = 4; - char rp_group_xpath[XPATH_MAXLEN]; - int result = 0; - struct prefix group; - struct in_addr rp_addr; - const char *group_str = - (argc == 5) ? argv[idx_group]->arg : "224.0.0.0/4"; - - result = str2prefix(group_str, &group); - if (result) { - struct prefix temp; - - prefix_copy(&temp, &group); - apply_mask(&temp); - if (!prefix_same(&group, &temp)) { - vty_out(vty, "%% Inconsistent address and mask: %s\n", - group_str); - return CMD_WARNING_CONFIG_FAILED; - } - } - - if (!result) { - vty_out(vty, "%% Bad group address specified: %s\n", - group_str); - return CMD_WARNING_CONFIG_FAILED; - } - - result = inet_pton(AF_INET, argv[idx_rp]->arg, &rp_addr); - if (result <= 0) { - vty_out(vty, "%% Bad RP address specified: %s\n", - argv[idx_rp]->arg); - return CMD_WARNING_CONFIG_FAILED; - } + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_group_xpath, sizeof(rp_group_xpath), - FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath)); - - nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_rp_cmd(vty, rp_str, group_str); } -DEFUN (ip_pim_rp_prefix_list, +DEFPY (ip_pim_rp_prefix_list, ip_pim_rp_prefix_list_cmd, - "ip pim rp A.B.C.D prefix-list WORD", + "ip pim rp A.B.C.D$rp prefix-list WORD$plist", IP_STR "pim multicast routing\n" - "Rendevous Point\n" + "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" "Name of a prefix-list\n") { - int idx_rp = 3, idx_plist = 5; - const char *vrfname; - char rp_plist_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), - FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); - - nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, - argv[idx_plist]->arg); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_rp_plist_cmd(vty, rp_str, plist); } -DEFUN (no_ip_pim_rp, +DEFPY (no_ip_pim_rp, no_ip_pim_rp_cmd, - "no ip pim rp A.B.C.D [A.B.C.D/M]", + "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", NO_STR IP_STR "pim multicast routing\n" @@ -7306,106 +7105,23 @@ DEFUN (no_ip_pim_rp, "ip address of RP\n" "Group Address range to cover\n") { - int idx_rp = 4, idx_group = 5; - const char *group_str = - (argc == 6) ? argv[idx_group]->arg : "224.0.0.0/4"; - char group_list_xpath[XPATH_MAXLEN]; - char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; - int printed; - const char *vrfname; - const struct lyd_node *group_dnode; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - - - printed = snprintf(group_list_xpath, sizeof(group_list_xpath), - "%s/group-list", rp_xpath); - - if (printed >= (int)(sizeof(group_list_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']", - group_list_xpath, group_str); - - if (printed >= (int)(sizeof(group_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!yang_dnode_exists(vty->candidate_config->dnode, group_xpath)) { - vty_out(vty, "%% Unable to find specified RP\n"); - return NB_OK; - } - - group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath); - - if (yang_is_last_list_dnode(group_dnode)) - nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); - else - nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY, - group_str); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_rp_cmd(vty, rp_str, group_str); } -DEFUN (no_ip_pim_rp_prefix_list, +DEFPY (no_ip_pim_rp_prefix_list, no_ip_pim_rp_prefix_list_cmd, - "no ip pim rp A.B.C.D prefix-list WORD", + "no ip pim rp A.B.C.D$rp prefix-list WORD$plist", NO_STR IP_STR "pim multicast routing\n" - "Rendevous Point\n" + "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" "Name of a prefix-list\n") { - int idx_rp = 4; - int idx_plist = 6; - char rp_xpath[XPATH_MAXLEN]; - char plist_xpath[XPATH_MAXLEN]; - const char *vrfname; - const struct lyd_node *plist_dnode; - const char *plist; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - - snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", - argv[idx_rp]->arg); - strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); - - plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); - if (!plist_dnode) { - vty_out(vty, "%% Unable to find specified RP\n"); - return NB_OK; - } - - plist = yang_dnode_get_string(plist_dnode, plist_xpath); - if (strcmp(argv[idx_plist]->arg, plist)) { - vty_out(vty, "%% Unable to find specified RP\n"); - return NB_OK; - } - - nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); + return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } DEFUN (ip_pim_ssm_prefix_list, @@ -8169,11 +7885,7 @@ DEFUN (interface_ip_pim_drprio, { int idx_number = 3; - nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY, - argv[idx_number]->arg); - - return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_ip_pim_drprio_cmd(vty, argv[idx_number]->arg); } DEFUN (interface_no_ip_pim_drprio, @@ -8185,10 +7897,7 @@ DEFUN (interface_no_ip_pim_drprio, "Revert the Designated Router Priority to default\n" "Old Value of the Priority\n") { - nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_drprio_cmd(vty); } DEFPY_HIDDEN (interface_ip_igmp_query_generate, @@ -8200,8 +7909,10 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate, "IGMP version\n" "IGMP version number\n") { +#if PIM_IPV == 4 VTY_DECLVAR_CONTEXT(interface, ifp); - int igmp_version = 2; + int igmp_version; + struct pim_interface *pim_ifp = ifp->info; if (!ifp->info) { vty_out(vty, "IGMP/PIM is not enabled on the interface %s\n", @@ -8209,11 +7920,14 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate, return CMD_WARNING_CONFIG_FAILED; } + /* It takes the igmp version configured on the interface as default */ + igmp_version = pim_ifp->igmp_version; + if (argc > 3) igmp_version = atoi(argv[4]->arg); igmp_send_query_on_intf(ifp, igmp_version); - +#endif return CMD_SUCCESS; } @@ -8255,13 +7969,12 @@ DEFPY_HIDDEN (pim_test_sg_keepalive, up = pim_upstream_find(pim, &sg); if (!up) { - vty_out(vty, "%% Unable to find %s specified\n", - pim_str_sg_dump(&sg)); + vty_out(vty, "%% Unable to find %pSG specified\n", &sg); return CMD_WARNING; } - vty_out(vty, "Setting %s to current keep alive time: %d\n", - pim_str_sg_dump(&sg), pim->keep_alive_time); + vty_out(vty, "Setting %pSG to current keep alive time: %d\n", &sg, + pim->keep_alive_time); pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); return CMD_SUCCESS; @@ -8275,20 +7988,7 @@ DEFPY (interface_ip_pim_activeactive, PIM_STR "Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n") { - if (no) - nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, - "false"); - else { - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "true"); - - nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, - "true"); - } - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_ip_pim_activeactive_cmd(vty, no); } DEFUN_HIDDEN (interface_ip_pim_ssm, @@ -8300,11 +8000,7 @@ DEFUN_HIDDEN (interface_ip_pim_ssm, { int ret; - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - - ret = nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + ret = pim_process_ip_pim_cmd(vty); if (ret != NB_OK) return ret; @@ -8322,11 +8018,7 @@ DEFUN_HIDDEN (interface_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_ip_pim_cmd(vty); } DEFUN (interface_ip_pim, @@ -8335,12 +8027,7 @@ DEFUN (interface_ip_pim, IP_STR PIM_STR) { - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); - + return pim_process_ip_pim_cmd(vty); } DEFUN_HIDDEN (interface_no_ip_pim_ssm, @@ -8351,39 +8038,7 @@ DEFUN_HIDDEN (interface_no_ip_pim_ssm, PIM_STR IFACE_PIM_STR) { - const struct lyd_node *igmp_enable_dnode; - char igmp_if_xpath[XPATH_MAXLEN]; - - int printed = - snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-gmp:gmp/address-family[address-family='%s']", - VTY_CURR_XPATH, "frr-routing:ipv4"); - - if (printed >= (int)(sizeof(igmp_if_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - FRR_GMP_ENABLE_XPATH, - VTY_CURR_XPATH, - "frr-routing:ipv4"); - if (!igmp_enable_dnode) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else { - if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, - NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "false"); - } - - return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_cmd(vty); } DEFUN_HIDDEN (interface_no_ip_pim_sm, @@ -8394,41 +8049,7 @@ DEFUN_HIDDEN (interface_no_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { - const struct lyd_node *igmp_enable_dnode; - char igmp_if_xpath[XPATH_MAXLEN]; - - int printed = - snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-gmp:gmp/address-family[address-family='%s']", - VTY_CURR_XPATH, "frr-routing:ipv4"); - - if (printed >= (int)(sizeof(igmp_if_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - igmp_enable_dnode = - yang_dnode_getf(vty->candidate_config->dnode, - FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, - "frr-routing:ipv4"); - - if (!igmp_enable_dnode) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else { - if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, - NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "false"); - } - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_cmd(vty); } DEFUN (interface_no_ip_pim, @@ -8438,41 +8059,7 @@ DEFUN (interface_no_ip_pim, IP_STR PIM_STR) { - const struct lyd_node *igmp_enable_dnode; - char igmp_if_xpath[XPATH_MAXLEN]; - - int printed = - snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-gmp:gmp/address-family[address-family='%s']", - VTY_CURR_XPATH, "frr-routing:ipv4"); - - if (printed >= (int)(sizeof(igmp_if_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - igmp_enable_dnode = - yang_dnode_getf(vty->candidate_config->dnode, - FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, - "frr-routing:ipv4"); - - if (!igmp_enable_dnode) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else { - if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) { - nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, - NULL); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - } else - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "false"); - } - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_cmd(vty); } /* boundaries */ @@ -8485,13 +8072,7 @@ DEFUN(interface_ip_pim_boundary_oil, "Filter OIL by group using prefix list\n" "Prefix list to filter OIL with\n") { - nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY, - argv[4]->arg); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); - + return pim_process_ip_pim_boundary_oil_cmd(vty, argv[4]->arg); } DEFUN(interface_no_ip_pim_boundary_oil, @@ -8504,12 +8085,7 @@ DEFUN(interface_no_ip_pim_boundary_oil, "Filter OIL by group using prefix list\n" "Prefix list to filter OIL with\n") { - nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY, - NULL); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_boundary_oil_cmd(vty); } DEFUN (interface_ip_mroute, @@ -8530,13 +8106,8 @@ DEFUN (interface_ip_mroute, else source_str = argv[idx_ipv4 + 1]->arg; - nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY, - argv[idx_interface]->arg); - - return nb_cli_apply_changes(vty, - FRR_PIM_MROUTE_XPATH, - "frr-routing:ipv4", source_str, - argv[idx_ipv4]->arg); + return pim_process_ip_mroute_cmd(vty, argv[idx_interface]->arg, + argv[idx_ipv4]->arg, source_str); } DEFUN (interface_no_ip_mroute, @@ -8549,6 +8120,7 @@ DEFUN (interface_no_ip_mroute, "Group Address\n" "Source Address\n") { + int idx_interface = 3; int idx_ipv4 = 4; const char *source_str; @@ -8557,12 +8129,8 @@ DEFUN (interface_no_ip_mroute, else source_str = argv[idx_ipv4 + 1]->arg; - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, - FRR_PIM_MROUTE_XPATH, - "frr-routing:ipv4", source_str, - argv[idx_ipv4]->arg); + return pim_process_no_ip_mroute_cmd(vty, argv[idx_interface]->arg, + argv[idx_ipv4]->arg, source_str); } DEFUN (interface_ip_pim_hello, @@ -8576,31 +8144,14 @@ DEFUN (interface_ip_pim_hello, { int idx_time = 3; int idx_hold = 4; - const struct lyd_node *igmp_enable_dnode; - - igmp_enable_dnode = - yang_dnode_getf(vty->candidate_config->dnode, - FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, - "frr-routing:ipv4"); - if (!igmp_enable_dnode) { - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "true"); - } else { - if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) - nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, - "true"); - } - - nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, - argv[idx_time]->arg); if (argc == idx_hold + 1) - nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY, - argv[idx_hold]->arg); + return pim_process_ip_pim_hello_cmd(vty, argv[idx_time]->arg, + argv[idx_hold]->arg); - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + else + return pim_process_ip_pim_hello_cmd(vty, argv[idx_time]->arg, + NULL); } DEFUN (interface_no_ip_pim_hello, @@ -8613,12 +8164,7 @@ DEFUN (interface_no_ip_pim_hello, IGNORED_IN_NO_STR IGNORED_IN_NO_STR) { - nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, - "frr-routing:ipv4"); + return pim_process_no_ip_pim_hello_cmd(vty); } DEFUN (debug_igmp, @@ -9501,7 +9047,6 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, "Desired min transmit interval\n") #endif /* !HAVE_BFDD */ -#if PIM_IPV != 6 DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, "ip msdp peer A.B.C.D$peer source A.B.C.D$source", IP_STR @@ -10171,8 +9716,6 @@ static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, bool uj) { struct listnode *sanode; struct pim_msdp_sa *sa; - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; char rp_str[INET_ADDRSTRLEN]; char timebuf[PIM_MSDP_UPTIME_STRLEN]; char spt_str[8]; @@ -10192,8 +9735,6 @@ static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, bool uj) for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { now = pim_time_monotonic_sec(); pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime); - pim_inet4_dump("", sa->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", sa->sg.grp, grp_str, sizeof(grp_str)); if (sa->flags & PIM_MSDP_SAF_PEER) { pim_inet4_dump("", sa->rp, rp_str, sizeof(rp_str)); if (sa->up) { @@ -10211,6 +9752,14 @@ static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, bool uj) strlcpy(local_str, "no", sizeof(local_str)); } if (uj) { + char src_str[PIM_ADDRSTRLEN]; + char grp_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", + &sa->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", + &sa->sg.src); + json_object_object_get_ex(json, grp_str, &json_group); if (!json_group) { @@ -10228,8 +9777,8 @@ static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, bool uj) json_object_string_add(json_row, "upTime", timebuf); json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-15s %15s %15s %5c %3c %8s\n", - src_str, grp_str, rp_str, local_str[0], + vty_out(vty, "%-15pPAs %15pPAs %15s %5c %3c %8s\n", + &sa->sg.src, &sa->sg.grp, rp_str, local_str[0], spt_str[0], timebuf); } } @@ -10309,8 +9858,6 @@ static void ip_msdp_show_sa_detail(struct pim_instance *pim, struct vty *vty, { struct listnode *sanode; struct pim_msdp_sa *sa; - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; json_object *json = NULL; if (uj) { @@ -10318,8 +9865,12 @@ static void ip_msdp_show_sa_detail(struct pim_instance *pim, struct vty *vty, } for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { - pim_inet4_dump("", sa->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", sa->sg.grp, grp_str, sizeof(grp_str)); + char src_str[PIM_ADDRSTRLEN]; + char grp_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &sa->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", &sa->sg.src); + ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, json); } @@ -10389,8 +9940,6 @@ static void ip_msdp_show_sa_addr(struct pim_instance *pim, struct vty *vty, { struct listnode *sanode; struct pim_msdp_sa *sa; - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; json_object *json = NULL; if (uj) { @@ -10398,8 +9947,12 @@ static void ip_msdp_show_sa_addr(struct pim_instance *pim, struct vty *vty, } for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { - pim_inet4_dump("", sa->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", sa->sg.grp, grp_str, sizeof(grp_str)); + char src_str[PIM_ADDRSTRLEN]; + char grp_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &sa->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", &sa->sg.src); + if (!strcmp(addr, src_str) || !strcmp(addr, grp_str)) { ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, json); @@ -10415,8 +9968,6 @@ static void ip_msdp_show_sa_sg(struct pim_instance *pim, struct vty *vty, { struct listnode *sanode; struct pim_msdp_sa *sa; - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; json_object *json = NULL; if (uj) { @@ -10424,8 +9975,12 @@ static void ip_msdp_show_sa_sg(struct pim_instance *pim, struct vty *vty, } for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { - pim_inet4_dump("", sa->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", sa->sg.grp, grp_str, sizeof(grp_str)); + char src_str[PIM_ADDRSTRLEN]; + char grp_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &sa->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", &sa->sg.src); + if (!strcmp(src, src_str) && !strcmp(grp, grp_str)) { ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, json); @@ -10519,7 +10074,6 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all, return CMD_SUCCESS; } -#endif /* PIM_IPV != 6 */ struct pim_sg_cache_walk_data { struct vty *vty; @@ -10534,8 +10088,6 @@ static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg, { struct vty *vty = cwd->vty; json_object *json = cwd->json; - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; json_object *json_row; bool installed = (vxlan_sg->up) ? true : false; const char *iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-"; @@ -10546,13 +10098,19 @@ static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg, else oif_name = vxlan_sg->term_oif?vxlan_sg->term_oif->name:""; - if (cwd->addr_match && (vxlan_sg->sg.src.s_addr != cwd->addr.s_addr) && - (vxlan_sg->sg.grp.s_addr != cwd->addr.s_addr)) { + if (cwd->addr_match && pim_addr_cmp(vxlan_sg->sg.src, cwd->addr) && + pim_addr_cmp(vxlan_sg->sg.grp, cwd->addr)) { return; } - pim_inet4_dump("", vxlan_sg->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", vxlan_sg->sg.grp, grp_str, sizeof(grp_str)); if (json) { + char src_str[PIM_ADDRSTRLEN]; + char grp_str[PIM_ADDRSTRLEN]; + + snprintfrr(grp_str, sizeof(grp_str), "%pPAs", + &vxlan_sg->sg.grp); + snprintfrr(src_str, sizeof(src_str), "%pPAs", + &vxlan_sg->sg.src); + json_object_object_get_ex(json, grp_str, &cwd->json_group); if (!cwd->json_group) { @@ -10572,9 +10130,9 @@ static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg, json_object_boolean_false_add(json_row, "installed"); json_object_object_add(cwd->json_group, src_str, json_row); } else { - vty_out(vty, "%-15s %-15s %-15s %-15s %-5s\n", - src_str, grp_str, iif_name, oif_name, - installed?"I":""); + vty_out(vty, "%-15pPAs %-15pPAs %-15s %-15s %-5s\n", + &vxlan_sg->sg.src, &vxlan_sg->sg.grp, iif_name, + oif_name, installed ? "I" : ""); } } @@ -10949,12 +10507,10 @@ void pim_cmd_init(void) install_element(VRF_NODE, &ip_ssmpingd_cmd); install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); install_element(VRF_NODE, &no_ip_ssmpingd_cmd); -#if PIM_IPV != 6 install_element(CONFIG_NODE, &ip_msdp_peer_cmd); install_element(VRF_NODE, &ip_msdp_peer_cmd); install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); install_element(VRF_NODE, &no_ip_msdp_peer_cmd); -#endif /* PIM_IPV != 6 */ install_element(CONFIG_NODE, &ip_pim_ecmp_cmd); install_element(VRF_NODE, &ip_pim_ecmp_cmd); install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd); @@ -11123,14 +10679,12 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); -#if PIM_IPV != 6 install_element(ENABLE_NODE, &debug_msdp_cmd); install_element(ENABLE_NODE, &no_debug_msdp_cmd); install_element(ENABLE_NODE, &debug_msdp_events_cmd); install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); install_element(ENABLE_NODE, &debug_msdp_packets_cmd); install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); -#endif /* PIM_IPV != 6 */ install_element(ENABLE_NODE, &debug_mtrace_cmd); install_element(ENABLE_NODE, &no_debug_mtrace_cmd); install_element(ENABLE_NODE, &debug_bsm_cmd); @@ -11176,20 +10730,17 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd); install_element(CONFIG_NODE, &debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd); -#if PIM_IPV != 6 install_element(CONFIG_NODE, &debug_msdp_cmd); install_element(CONFIG_NODE, &no_debug_msdp_cmd); install_element(CONFIG_NODE, &debug_msdp_events_cmd); install_element(CONFIG_NODE, &no_debug_msdp_events_cmd); install_element(CONFIG_NODE, &debug_msdp_packets_cmd); install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd); -#endif /* PIM_IPV != 6 */ install_element(CONFIG_NODE, &debug_mtrace_cmd); install_element(CONFIG_NODE, &no_debug_mtrace_cmd); install_element(CONFIG_NODE, &debug_bsm_cmd); install_element(CONFIG_NODE, &no_debug_bsm_cmd); -#if PIM_IPV != 6 install_element(CONFIG_NODE, &ip_msdp_timers_cmd); install_element(VRF_NODE, &ip_msdp_timers_cmd); install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); @@ -11212,7 +10763,6 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); -#endif /* PIM_IPV != 6 */ install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c new file mode 100644 index 000000000..c5d89f806 --- /dev/null +++ b/pimd/pim_cmd_common.c @@ -0,0 +1,655 @@ +/* + * PIM for IPv6 FRR + * Copyright (C) 2022 Vmware, Inc. + * Mobashshera Rasool + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "lib/json.h" +#include "command.h" +#include "if.h" +#include "prefix.h" +#include "zclient.h" +#include "plist.h" +#include "hash.h" +#include "nexthop.h" +#include "vrf.h" +#include "ferr.h" +#include "lib/srcdest_table.h" + +#include "pimd.h" +#include "pim_vty.h" +#include "lib/northbound_cli.h" +#include "pim_errors.h" +#include "pim_nb.h" +#include "pim_cmd_common.h" + +/** + * Get current node VRF name. + * + * NOTE: + * In case of failure it will print error message to user. + * + * \returns name or NULL if failed to get VRF. + */ +const char *pim_cli_get_vrf_name(struct vty *vty) +{ + const struct lyd_node *vrf_node; + + /* Not inside any VRF context. */ + if (vty->xpath_index == 0) + return VRF_DEFAULT_NAME; + + vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); + if (vrf_node == NULL) { + vty_out(vty, "%% Failed to get vrf dnode in configuration\n"); + return NULL; + } + + return yang_dnode_get_string(vrf_node, "./name"); +} + +int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); + strlcat(xpath, "/join-prune-interval", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, jpi_str); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_join_prune_cmd(struct vty *vty) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); + strlcat(xpath, "/join-prune-interval", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_spt_switchover_infinity_cmd(struct vty *vty) +{ + const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL); + strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", + sizeof(spt_plist_xpath)); + + snprintf(spt_action_xpath, sizeof(spt_action_xpath), + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL); + strlcat(spt_action_xpath, "/spt-switchover/spt-action", + sizeof(spt_action_xpath)); + + if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath)) + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, + "PIM_SPT_INFINITY"); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty, + const char *plist) +{ + const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL); + strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", + sizeof(spt_plist_xpath)); + + snprintf(spt_action_xpath, sizeof(spt_action_xpath), + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL); + strlcat(spt_action_xpath, "/spt-switchover/spt-action", + sizeof(spt_action_xpath)); + + nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, + "PIM_SPT_INFINITY"); + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, + plist); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_spt_switchover_cmd(struct vty *vty) +{ + const char *vrfname; + char spt_plist_xpath[XPATH_MAXLEN]; + char spt_action_xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL); + strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", + sizeof(spt_plist_xpath)); + + snprintf(spt_action_xpath, sizeof(spt_action_xpath), + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL); + strlcat(spt_action_xpath, "/spt-switchover/spt-action", + sizeof(spt_action_xpath)); + + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, + "PIM_SPT_IMMEDIATE"); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_pim_packet_cmd(struct vty *vty, const char *packet) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); + strlcat(xpath, "/packets", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, packet); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_pim_packet_cmd(struct vty *vty) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); + strlcat(xpath, "/packets", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat) +{ + const char *vrfname; + char ka_timer_xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, + kat); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_keepalivetimer_cmd(struct vty *vty) +{ + const char *vrfname; + char ka_timer_xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat) +{ + const char *vrfname; + char rp_ka_timer_xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL); + strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", + sizeof(rp_ka_timer_xpath)); + + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, + rpkat); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_rp_kat_cmd(struct vty *vty) +{ + const char *vrfname; + char rp_ka_timer[6]; + char rp_ka_timer_xpath[XPATH_MAXLEN]; + uint v; + char rs_timer_xpath[XPATH_MAXLEN]; + + snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), + FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL); + strlcat(rs_timer_xpath, "/register-suppress-time", + sizeof(rs_timer_xpath)); + + /* RFC4601 */ + v = yang_dnode_get_uint16(vty->candidate_config->dnode, + rs_timer_xpath); + v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT; + if (v > UINT16_MAX) + v = UINT16_MAX; + snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v); + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL); + strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", + sizeof(rp_ka_timer_xpath)); + + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, + rp_ka_timer); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_register_suppress_cmd(struct vty *vty, const char *rst) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); + strlcat(xpath, "/register-suppress-time", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, rst); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_register_suppress_cmd(struct vty *vty) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); + strlcat(xpath, "/register-suppress-time", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_ip_pim_cmd(struct vty *vty) +{ + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_no_ip_pim_cmd(struct vty *vty) +{ + const struct lyd_node *mld_enable_dnode; + char mld_if_xpath[XPATH_MAXLEN]; + + int printed = + snprintf(mld_if_xpath, sizeof(mld_if_xpath), + "%s/frr-gmp:gmp/address-family[address-family='%s']", + VTY_CURR_XPATH, FRR_PIM_AF_XPATH_VAL); + + if (printed >= (int)(sizeof(mld_if_xpath))) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); + return CMD_WARNING_CONFIG_FAILED; + } + + mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + FRR_PIM_AF_XPATH_VAL); + + if (!mld_enable_dnode) { + nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + if (!yang_dnode_get_bool(mld_enable_dnode, ".")) { + nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY, + NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "false"); + } + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str) +{ + nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY, + drpriority_str); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_no_ip_pim_drprio_cmd(struct vty *vty) +{ + nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str, + const char *hold_str) +{ + const struct lyd_node *mld_enable_dnode; + + mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + FRR_PIM_AF_XPATH_VAL); + + if (!mld_enable_dnode) { + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + } else { + if (!yang_dnode_get_bool(mld_enable_dnode, ".")) + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + } + + nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, hello_str); + + if (hold_str) + nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY, + hold_str); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_no_ip_pim_hello_cmd(struct vty *vty) +{ + nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no) +{ + if (no) + nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, + "false"); + else { + nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, + "true"); + + nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY, + "true"); + } + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil) +{ + nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY, + oil); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty) +{ + nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + +int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface, + const char *group_str, const char *source_str) +{ + nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY, interface); + + if (!source_str) { + char buf[SRCDEST2STR_BUFFER]; + + inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf)); + return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH, + FRR_PIM_AF_XPATH_VAL, buf, + group_str); + } + + return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH, + FRR_PIM_AF_XPATH_VAL, source_str, + group_str); +} + +int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, + const char *group_str, const char *source_str) +{ + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + + if (!source_str) { + char buf[SRCDEST2STR_BUFFER]; + + inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf)); + return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH, + FRR_PIM_AF_XPATH_VAL, buf, + group_str); + } + + return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH, + FRR_PIM_AF_XPATH_VAL, source_str, + group_str); +} + +int pim_process_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str) +{ + const char *vrfname; + char rp_group_xpath[XPATH_MAXLEN]; + int result = 0; + struct prefix group; + pim_addr rp_addr; + + result = str2prefix(group_str, &group); + if (result) { + struct prefix temp; + + prefix_copy(&temp, &group); + apply_mask(&temp); + if (!prefix_same(&group, &temp)) { + vty_out(vty, "%% Inconsistent address and mask: %s\n", + group_str); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (!result) { + vty_out(vty, "%% Bad group address specified: %s\n", group_str); + return CMD_WARNING_CONFIG_FAILED; + } + + result = inet_pton(PIM_AF, rp_str, &rp_addr); + if (result <= 0) { + vty_out(vty, "%% Bad RP address specified: %s\n", rp_str); + return CMD_WARNING_CONFIG_FAILED; + } + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_group_xpath, sizeof(rp_group_xpath), + FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL, rp_str); + strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath)); + + nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str) +{ + char group_list_xpath[XPATH_MAXLEN]; + char group_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN]; + int printed; + const char *vrfname; + const struct lyd_node *group_dnode; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + + printed = snprintf(group_list_xpath, sizeof(group_list_xpath), + "%s/group-list", rp_xpath); + + if (printed >= (int)(sizeof(group_list_xpath))) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); + return CMD_WARNING_CONFIG_FAILED; + } + + printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']", + group_list_xpath, group_str); + + if (printed >= (int)(sizeof(group_xpath))) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); + return CMD_WARNING_CONFIG_FAILED; + } + + group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath); + if (!group_dnode) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; + } + + if (yang_is_last_list_dnode(group_dnode)) + nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY, + group_str); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list) +{ + const char *vrfname; + char rp_plist_xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), + FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_AF_XPATH_VAL, rp_str); + strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); + + nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list) +{ + char rp_xpath[XPATH_MAXLEN]; + char plist_xpath[XPATH_MAXLEN]; + const char *vrfname; + const struct lyd_node *plist_dnode; + const char *plist; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + + snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); + + plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); + if (!plist_dnode) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; + } + + plist = yang_dnode_get_string(plist_dnode, plist_xpath); + if (strcmp(prefix_list, plist)) { + vty_out(vty, "%% Unable to find specified RP\n"); + return NB_OK; + } + + nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h new file mode 100644 index 000000000..b7e6b6ac8 --- /dev/null +++ b/pimd/pim_cmd_common.h @@ -0,0 +1,62 @@ +/* + * PIM for IPv6 FRR + * Copyright (C) 2022 Vmware, Inc. + * Mobashshera Rasool + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef PIM_CMD_COMMON_H +#define PIM_CMD_COMMON_H + +const char *pim_cli_get_vrf_name(struct vty *vty); +int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str); +int pim_process_no_join_prune_cmd(struct vty *vty); +int pim_process_spt_switchover_infinity_cmd(struct vty *vty); +int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty, + const char *plist); +int pim_process_no_spt_switchover_cmd(struct vty *vty); +int pim_process_pim_packet_cmd(struct vty *vty, const char *packet); +int pim_process_no_pim_packet_cmd(struct vty *vty); +int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat); +int pim_process_no_keepalivetimer_cmd(struct vty *vty); +int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat); +int pim_process_no_rp_kat_cmd(struct vty *vty); +int pim_process_register_suppress_cmd(struct vty *vty, const char *rst); +int pim_process_no_register_suppress_cmd(struct vty *vty); +int pim_process_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str); +int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, + const char *group_str); +int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list); +int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, + const char *prefix_list); + +int pim_process_ip_pim_cmd(struct vty *vty); +int pim_process_no_ip_pim_cmd(struct vty *vty); +int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str); +int pim_process_no_ip_pim_drprio_cmd(struct vty *vty); +int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str, + const char *hold_str); +int pim_process_no_ip_pim_hello_cmd(struct vty *vty); +int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no); +int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil); +int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty); +int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface, + const char *group_str, const char *source_str); +int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, + const char *group_str, const char *src_str); + +#endif /* PIM_CMD_COMMON_H */ diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 45ea6a956..fe4f10aa6 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -33,81 +33,62 @@ #include "pim_upstream.h" #include "pim_bsm.h" -static void on_trace(const char *label, struct interface *ifp, - struct in_addr src) +static void on_trace(const char *label, struct interface *ifp, pim_addr src) { - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src, src_str, sizeof(src_str)); - zlog_debug("%s: from %s on %s", label, src_str, ifp->name); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: from %pPAs on %s", label, &src, ifp->name); } static void tlv_trace_bool(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, - int isset, int value) + const char *ifname, pim_addr src_addr, int isset, + int value) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s=%d", - label, src_str, ifname, tlv_name, value); - } + "%s: PIM hello option from %pPAs on interface %s: %s=%d", + label, &src_addr, ifname, tlv_name, value); } static void tlv_trace_uint16(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, - int isset, uint16_t value) + const char *ifname, pim_addr src_addr, int isset, + uint16_t value) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s=%u", - label, src_str, ifname, tlv_name, value); - } + "%s: PIM hello option from %pPAs on interface %s: %s=%u", + label, &src_addr, ifname, tlv_name, value); } static void tlv_trace_uint32(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, - int isset, uint32_t value) + const char *ifname, pim_addr src_addr, int isset, + uint32_t value) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s=%u", - label, src_str, ifname, tlv_name, value); - } + "%s: PIM hello option from %pPAs on interface %s: %s=%u", + label, &src_addr, ifname, tlv_name, value); } static void tlv_trace_uint32_hex(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, + const char *ifname, pim_addr src_addr, int isset, uint32_t value) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s=%08x", - label, src_str, ifname, tlv_name, value); - } + "%s: PIM hello option from %pPAs on interface %s: %s=%08x", + label, &src_addr, ifname, tlv_name, value); } static void tlv_trace_list(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, - int isset, struct list *addr_list) + const char *ifname, pim_addr src_addr, int isset, + struct list *addr_list) { - if (isset) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (isset) zlog_debug( - "%s: PIM hello option from %s on interface %s: %s size=%d list=%p", - label, src_str, ifname, tlv_name, + "%s: PIM hello option from %pPAs on interface %s: %s size=%d list=%p", + label, &src_addr, ifname, tlv_name, addr_list ? ((int)listcount(addr_list)) : -1, (void *)addr_list); - } } #define FREE_ADDR_LIST \ @@ -121,8 +102,8 @@ static void tlv_trace_list(const char *label, const char *tlv_name, return (code); \ } -int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, - uint8_t *tlv_buf, int tlv_buf_size) +int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf, + int tlv_buf_size) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; @@ -158,15 +139,11 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, int remain = tlv_pastend - tlv_curr; if (remain < PIM_TLV_MIN_SIZE) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: short PIM hello TLV size=%d < min=%d from %s on interface %s", + "%s: short PIM hello TLV size=%d < min=%d from %pPAs on interface %s", __func__, remain, PIM_TLV_MIN_SIZE, - src_str, ifp->name); - } + &src_addr, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-1); } @@ -176,28 +153,20 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, tlv_curr += PIM_TLV_LENGTH_SIZE; if ((tlv_curr + option_len) > tlv_pastend) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s", + "%s: long PIM hello TLV type=%d length=%d > left=%td from %pPAs on interface %s", __func__, option_type, option_len, - tlv_pastend - tlv_curr, src_str, + tlv_pastend - tlv_curr, &src_addr, ifp->name); - } FREE_ADDR_LIST_THEN_RETURN(-2); } - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s", + "%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %pPAs on %s", __func__, remain, option_type, option_len, - src_str, ifp->name); - } + &src_addr, ifp->name); switch (option_type) { case PIM_MSG_OPTION_TYPE_HOLDTIME: @@ -242,26 +211,18 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, } break; case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH: - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s", + "%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %pPAs on interface %s", __func__, option_type, option_len, - src_str, ifp->name); - } + &src_addr, ifp->name); break; default: - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s", + "%s: ignoring unknown PIM hello TLV type=%d length=%d from %pPAs on interface %s", __func__, option_type, option_len, - src_str, ifp->name); - } + &src_addr, ifp->name); } tlv_curr += option_len; @@ -310,14 +271,10 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, } if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: PIM hello missing holdtime from %s on interface %s", - __func__, src_str, ifp->name); - } + "%s: PIM hello missing holdtime from %pPAs on interface %s", + __func__, &src_addr, ifp->name); } /* @@ -335,14 +292,10 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, hello_option_dr_priority, hello_option_generation_id, hello_option_addr_list, PIM_NEIGHBOR_SEND_DELAY); if (!neigh) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_warn( - "%s: failure creating PIM neighbor %s on interface %s", - __func__, src_str, ifp->name); - } + "%s: failure creating PIM neighbor %pPAs on interface %s", + __func__, &src_addr, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-8); } /* Forward BSM if required */ @@ -368,16 +321,12 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, || (hello_option_generation_id != neigh->generation_id)) { /* GenID mismatch, then replace neighbor */ - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s", + "%s: GenId mismatch new=%08x old=%08x: replacing neighbor %pPAs on %s", __func__, hello_option_generation_id, - neigh->generation_id, src_str, + neigh->generation_id, &src_addr, ifp->name); - } pim_upstream_rpf_genid_changed(pim_ifp->pim, neigh->source_addr); @@ -392,15 +341,10 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, hello_option_addr_list, PIM_NEIGHBOR_SEND_NOW); if (!neigh) { - if (PIM_DEBUG_PIM_HELLO) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, - src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_HELLO) zlog_debug( - "%s: failure re-creating PIM neighbor %s on interface %s", - __func__, src_str, ifp->name); - } + "%s: failure re-creating PIM neighbor %pPAs on interface %s", + __func__, &src_addr, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-9); } /* Forward BSM if required */ diff --git a/pimd/pim_hello.h b/pimd/pim_hello.h index df41f97d9..56084e06d 100644 --- a/pimd/pim_hello.h +++ b/pimd/pim_hello.h @@ -24,8 +24,8 @@ #include "if.h" -int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, - uint8_t *tlv_buf, int tlv_buf_size); +int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf, + int tlv_buf_size); int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 72e04460d..98fa4c488 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -50,10 +50,12 @@ #include "pim_igmp_join.h" #include "pim_vxlan.h" +#if PIM_IPV == 4 static void pim_if_igmp_join_del_all(struct interface *ifp); static int igmp_join_sock(const char *ifname, ifindex_t ifindex, - struct in_addr group_addr, - struct in_addr source_addr); + struct in_addr group_addr, struct in_addr source_addr, + struct pim_interface *pim_ifp); +#endif void pim_if_init(struct pim_instance *pim) { @@ -83,6 +85,7 @@ static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr) XFREE(MTYPE_PIM_SEC_ADDR, sec_addr); } +__attribute__((unused)) static int pim_sec_addr_comp(const void *p1, const void *p2) { const struct pim_secondary_addr *sec1 = p1; @@ -149,10 +152,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, if (pim) PIM_IF_DO_PIM(pim_ifp->options); +#if PIM_IPV == 4 if (igmp) PIM_IF_DO_IGMP(pim_ifp->options); PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options); +#endif pim_ifp->gm_join_list = NULL; pim_ifp->pim_neighbor_list = NULL; @@ -182,7 +187,9 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, ifp->info = pim_ifp; +#if PIM_IPV == 4 pim_sock_reset(ifp); +#endif pim_if_add_vif(ifp, ispimreg, is_vxlan_term); pim_ifp->pim->mcast_if_count++; @@ -193,23 +200,26 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, void pim_if_delete(struct interface *ifp) { struct pim_interface *pim_ifp; - struct pim_ifchannel *ch; assert(ifp); pim_ifp = ifp->info; assert(pim_ifp); + pim_ifp->pim->mcast_if_count--; +#if PIM_IPV == 4 if (pim_ifp->gm_join_list) { pim_if_igmp_join_del_all(ifp); } +#endif pim_ifchannel_delete_all(ifp); +#if PIM_IPV == 4 igmp_sock_delete_all(ifp); +#endif pim_neighbor_delete_all(ifp, "Interface removed from configuration"); pim_if_del_vif(ifp); - pim_ifp->pim->mcast_if_count--; pim_igmp_if_fini(pim_ifp); @@ -218,13 +228,6 @@ void pim_if_delete(struct interface *ifp) list_delete(&pim_ifp->sec_addr_list); XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); - - while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) { - ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb); - - pim_ifchannel_delete(ch); - } - XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = NULL; @@ -299,27 +302,20 @@ static int detect_primary_address_change(struct interface *ifp, const char *caller) { struct pim_interface *pim_ifp = ifp->info; - struct in_addr new_prim_addr; + pim_addr new_prim_addr; int changed; if (force_prim_as_any) - new_prim_addr.s_addr = INADDR_ANY; + new_prim_addr = PIMADDR_ANY; else new_prim_addr = pim_find_primary_addr(ifp); - changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr; + changed = pim_addr_cmp(new_prim_addr, pim_ifp->primary_address); - if (PIM_DEBUG_ZEBRA) { - char new_prim_str[INET_ADDRSTRLEN]; - char old_prim_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", new_prim_addr, new_prim_str, - sizeof(new_prim_str)); - pim_inet4_dump("", pim_ifp->primary_address, old_prim_str, - sizeof(old_prim_str)); - zlog_debug("%s: old=%s new=%s on interface %s: %s", __func__, - old_prim_str, new_prim_str, ifp->name, - changed ? "changed" : "unchanged"); - } + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s: old=%pPA new=%pPA on interface %s: %s", + __func__, &pim_ifp->primary_address, &new_prim_addr, + ifp->name, changed ? "changed" : "unchanged"); if (changed) { /* Before updating pim_ifp send Hello time with 0 hold time */ @@ -401,19 +397,18 @@ static int pim_sec_addr_update(struct interface *ifp) } for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { - struct prefix *p = ifc->address; + pim_addr addr = pim_addr_from_prefix(ifc->address); - if (PIM_INADDR_IS_ANY(p->u.prefix4)) { + if (pim_addr_is_any(addr)) continue; - } - if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) { + if (!pim_addr_cmp(addr, pim_ifp->primary_address)) { /* don't add the primary address into the secondary * address list */ continue; } - if (pim_sec_addr_add(pim_ifp, p)) { + if (pim_sec_addr_add(pim_ifp, ifc->address)) { changed = 1; } } @@ -480,7 +475,7 @@ static void detect_address_change(struct interface *ifp, int force_prim_as_any, * address change on all of them when the lo address changes */ } -int pim_update_source_set(struct interface *ifp, struct in_addr source) +int pim_update_source_set(struct interface *ifp, pim_addr source) { struct pim_interface *pim_ifp = ifp->info; @@ -488,7 +483,7 @@ int pim_update_source_set(struct interface *ifp, struct in_addr source) return PIM_IFACE_NOT_FOUND; } - if (pim_ifp->update_source.s_addr == source.s_addr) { + if (!pim_addr_cmp(pim_ifp->update_source, source)) { return PIM_UPDATE_SOURCE_DUP; } @@ -502,7 +497,6 @@ void pim_if_addr_add(struct connected *ifc) { struct pim_interface *pim_ifp; struct interface *ifp; - struct in_addr ifaddr; bool vxlan_term; assert(ifc); @@ -522,14 +516,35 @@ void pim_if_addr_add(struct connected *ifc) CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); - - ifaddr = ifc->address->u.prefix4; +#if PIM_IPV != 4 + if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) || + IN6_IS_ADDR_LOOPBACK(&ifc->address->u.prefix6)) { + if (IN6_IS_ADDR_UNSPECIFIED(&pim_ifp->ll_lowest)) + pim_ifp->ll_lowest = ifc->address->u.prefix6; + else if (IPV6_ADDR_CMP(&ifc->address->u.prefix6, + &pim_ifp->ll_lowest) < 0) + pim_ifp->ll_lowest = ifc->address->u.prefix6; + + if (IPV6_ADDR_CMP(&ifc->address->u.prefix6, + &pim_ifp->ll_highest) > 0) + pim_ifp->ll_highest = ifc->address->u.prefix6; + + if (PIM_DEBUG_ZEBRA) + zlog_debug( + "%s: new link-local %pI6, lowest now %pI6, highest %pI6", + ifc->ifp->name, &ifc->address->u.prefix6, + &pim_ifp->ll_lowest, &pim_ifp->ll_highest); + } +#endif detect_address_change(ifp, 0, __func__); // if (ifc->address->family != AF_INET) // return; +#if PIM_IPV == 4 + struct in_addr ifaddr = ifc->address->u.prefix4; + if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct gm_sock *igmp; @@ -561,7 +576,7 @@ void pim_if_addr_add(struct connected *ifc) close(ij->sock_fd); join_fd = igmp_join_sock( ifp->name, ifp->ifindex, ij->group_addr, - ij->source_addr); + ij->source_addr, pim_ifp); if (join_fd < 0) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -595,10 +610,11 @@ void pim_if_addr_add(struct connected *ifc) true); } } /* igmp mtrace only */ +#endif if (PIM_IF_TEST_PIM(pim_ifp->options)) { - if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + if (!pim_addr_is_any(pim_ifp->primary_address)) { /* Interface has a valid socket ? */ if (pim_ifp->pim_sock_fd < 0) { @@ -646,6 +662,7 @@ void pim_if_addr_add(struct connected *ifc) static void pim_if_addr_del_igmp(struct connected *ifc) { +#if PIM_IPV == 4 struct pim_interface *pim_ifp = ifc->ifp->info; struct gm_sock *igmp; struct in_addr ifaddr; @@ -668,6 +685,7 @@ static void pim_if_addr_del_igmp(struct connected *ifc) /* if addr found, del IGMP socket */ igmp_sock_delete(igmp); } +#endif } static void pim_if_addr_del_pim(struct connected *ifc) @@ -684,7 +702,7 @@ static void pim_if_addr_del_pim(struct connected *ifc) return; } - if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + if (!pim_addr_is_any(pim_ifp->primary_address)) { /* Interface keeps a valid primary address */ return; } @@ -717,6 +735,43 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) ? "secondary" : "primary"); +#if PIM_IPV == 6 + struct pim_interface *pim_ifp = ifc->ifp->info; + + if (pim_ifp && + (!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_lowest) || + !IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_highest))) { + struct listnode *cnode; + struct connected *cc; + + memset(&pim_ifp->ll_lowest, 0xff, sizeof(pim_ifp->ll_lowest)); + memset(&pim_ifp->ll_highest, 0, sizeof(pim_ifp->ll_highest)); + + for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, cnode, cc)) { + if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) && + !IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6)) + continue; + + if (IPV6_ADDR_CMP(&cc->address->u.prefix6, + &pim_ifp->ll_lowest) < 0) + pim_ifp->ll_lowest = cc->address->u.prefix6; + if (IPV6_ADDR_CMP(&cc->address->u.prefix6, + &pim_ifp->ll_highest) > 0) + pim_ifp->ll_highest = cc->address->u.prefix6; + } + + if (pim_ifp->ll_lowest.s6_addr[0] == 0xff) + memset(&pim_ifp->ll_lowest, 0, + sizeof(pim_ifp->ll_lowest)); + + if (PIM_DEBUG_ZEBRA) + zlog_debug( + "%s: removed link-local %pI6, lowest now %pI6, highest %pI6", + ifc->ifp->name, &ifc->address->u.prefix6, + &pim_ifp->ll_lowest, &pim_ifp->ll_highest); + } +#endif + detect_address_change(ifp, force_prim_as_any, __func__); pim_if_addr_del_igmp(ifc); @@ -752,7 +807,7 @@ void pim_if_addr_add_all(struct interface *ifp) if (PIM_IF_TEST_PIM(pim_ifp->options)) { /* Interface has a valid primary address ? */ - if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + if (!pim_addr_is_any(pim_ifp->primary_address)) { /* Interface has a valid socket ? */ if (pim_ifp->pim_sock_fd < 0) { @@ -827,40 +882,58 @@ void pim_if_addr_del_all_igmp(struct interface *ifp) } } -struct in_addr pim_find_primary_addr(struct interface *ifp) +pim_addr pim_find_primary_addr(struct interface *ifp) { struct connected *ifc; struct listnode *node; - struct in_addr addr = {0}; - int v4_addrs = 0; - int v6_addrs = 0; struct pim_interface *pim_ifp = ifp->info; - if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) { + if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source)) return pim_ifp->update_source; - } + +#if PIM_IPV == 6 + if (pim_ifp) + return pim_ifp->ll_highest; + + pim_addr best_addr = PIMADDR_ANY; for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { - struct prefix *p = ifc->address; + pim_addr addr; - if (p->family != AF_INET) { - v6_addrs++; + if (ifc->address->family != AF_INET6) continue; - } - if (PIM_INADDR_IS_ANY(p->u.prefix4)) { - zlog_warn( - "%s: null IPv4 address connected to interface %s", - __func__, ifp->name); + addr = pim_addr_from_prefix(ifc->address); + if (!IN6_IS_ADDR_LINKLOCAL(&addr)) continue; - } + if (pim_addr_cmp(addr, best_addr) > 0) + best_addr = addr; + } + + return best_addr; +#else + int v4_addrs = 0; + int v6_addrs = 0; - v4_addrs++; + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + switch (ifc->address->family) { + case AF_INET: + v4_addrs++; + break; + case AF_INET6: + v6_addrs++; + break; + default: + continue; + } if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) continue; - return p->u.prefix4; + if (ifc->address->family != PIM_AF) + continue; + + return pim_addr_from_prefix(ifc->address); } /* @@ -882,10 +955,8 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) if (lo_ifp && (lo_ifp != ifp)) return pim_find_primary_addr(lo_ifp); } - - addr.s_addr = PIM_NET_INADDR_ANY; - - return addr; + return PIMADDR_ANY; +#endif } static int pim_iface_next_vif_index(struct interface *ifp) @@ -916,7 +987,7 @@ static int pim_iface_next_vif_index(struct interface *ifp) int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term) { struct pim_interface *pim_ifp = ifp->info; - struct in_addr ifaddr; + pim_addr ifaddr; unsigned char flags = 0; assert(pim_ifp); @@ -935,7 +1006,7 @@ int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term) } ifaddr = pim_ifp->primary_address; - if (!ispimreg && !is_vxlan_term && PIM_INADDR_IS_ANY(ifaddr)) { + if (!ispimreg && !is_vxlan_term && pim_addr_is_any(ifaddr)) { zlog_warn( "%s: could not get address for interface %s ifindex=%d", __func__, ifp->name, ifp->ifindex); @@ -1094,8 +1165,7 @@ uint16_t pim_if_jp_override_interval_msec(struct interface *ifp) router (Section 4.3.4). The primary IP address of a neighbor is the address that it uses as the source of its PIM Hello messages. */ -struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, - struct in_addr addr) +struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, pim_addr addr) { struct listnode *neighnode; struct pim_neighbor *neigh; @@ -1111,15 +1181,13 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return 0; } - p.family = AF_INET; - p.u.prefix4 = addr; - p.prefixlen = IPV4_MAX_BITLEN; + pim_addr_to_prefix(&p, addr); for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { /* primary address ? */ - if (neigh->source_addr.s_addr == addr.s_addr) + if (!pim_addr_cmp(neigh->source_addr, addr)) return neigh; /* secondary address ? */ @@ -1127,13 +1195,10 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return neigh; } - if (PIM_DEBUG_PIM_TRACE) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: neighbor not found for address %s on interface %s", - __func__, addr_str, ifp->name); - } + "%s: neighbor not found for address %pPA on interface %s", + __func__, &addr, ifp->name); return NULL; } @@ -1158,6 +1223,7 @@ long pim_if_t_suppressed_msec(struct interface *ifp) return t_suppressed_msec; } +#if PIM_IPV == 4 static void igmp_join_free(struct gm_join *ij) { XFREE(MTYPE_PIM_IGMP_JOIN, ij); @@ -1182,12 +1248,16 @@ static struct gm_join *igmp_join_find(struct list *join_list, } static int igmp_join_sock(const char *ifname, ifindex_t ifindex, - struct in_addr group_addr, struct in_addr source_addr) + struct in_addr group_addr, struct in_addr source_addr, + struct pim_interface *pim_ifp) { int join_fd; + pim_ifp->igmp_ifstat_joins_sent++; + join_fd = pim_socket_raw(IPPROTO_IGMP); if (join_fd < 0) { + pim_ifp->igmp_ifstat_joins_failed++; return -1; } @@ -1203,6 +1273,8 @@ static int igmp_join_sock(const char *ifname, ifindex_t ifindex, __func__, join_fd, group_str, source_str, ifindex, ifname, errno, safe_strerror(errno)); + pim_ifp->igmp_ifstat_joins_failed++; + close(join_fd); return -2; } @@ -1222,7 +1294,7 @@ static struct gm_join *igmp_join_new(struct interface *ifp, assert(pim_ifp); join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, - source_addr); + source_addr, pim_ifp); if (join_fd < 0) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -1348,6 +1420,7 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, return 0; } +__attribute__((unused)) static void pim_if_igmp_join_del_all(struct interface *ifp) { struct pim_interface *pim_ifp; @@ -1368,6 +1441,19 @@ static void pim_if_igmp_join_del_all(struct interface *ifp) for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij)) pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr); } +#else /* PIM_IPV != 4 */ +ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, + struct in_addr source_addr) +{ + return ferr_ok(); +} + +int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, + struct in_addr source_addr) +{ + return 0; +} +#endif /* PIM_IPV != 4 */ /* RFC 4601 @@ -1383,8 +1469,7 @@ static void pim_if_igmp_join_del_all(struct interface *ifp) gone down (and may have come back up), and so we must assume it no longer knows it was the winner. */ -void pim_if_assert_on_neighbor_down(struct interface *ifp, - struct in_addr neigh_addr) +void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; @@ -1397,7 +1482,7 @@ void pim_if_assert_on_neighbor_down(struct interface *ifp, if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) continue; /* Dead neighbor was winner ? */ - if (ch->ifassert_winner.s_addr != neigh_addr.s_addr) + if (pim_addr_cmp(ch->ifassert_winner, neigh_addr)) continue; assert_action_a5(ch); @@ -1473,7 +1558,7 @@ void pim_if_create_pimreg(struct pim_instance *pim) } } -struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr src) +struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src) { struct listnode *cnode; struct connected *c; @@ -1482,12 +1567,10 @@ struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr if (!ifp) return NULL; - p.family = AF_INET; - p.u.prefix4 = src; - p.prefixlen = IPV4_MAX_BITLEN; + pim_addr_to_prefix(&p, src); for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { - if (c->address->family != AF_INET) + if (c->address->family != PIM_AF) continue; if (prefix_match(c->address, &p)) return c->address; @@ -1558,6 +1641,7 @@ static int pim_ifp_create(struct interface *ifp) pim_if_create_pimreg(pim); } +#if PIM_IPV == 4 /* * If we are a vrf device that is up, open up the pim_socket for * listening @@ -1585,15 +1669,16 @@ static int pim_ifp_create(struct interface *ifp) "%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.", __func__, ifp->name, MAXVIFS); } +#endif return 0; } static int pim_ifp_up(struct interface *ifp) { + uint32_t table_id; struct pim_interface *pim_ifp; struct pim_instance *pim; - uint32_t table_id; if (PIM_DEBUG_ZEBRA) { zlog_debug( @@ -1663,6 +1748,7 @@ static int pim_ifp_down(struct interface *ifp) */ pim_if_addr_del_all(ifp); +#if PIM_IPV == 4 /* pim_sock_delete() closes the socket, stops read and timer threads, @@ -1671,11 +1757,14 @@ static int pim_ifp_down(struct interface *ifp) if (ifp->info) { pim_sock_delete(ifp, "link down"); } +#endif } if (ifp->info) { pim_if_del_vif(ifp); +#if PIM_IPV == 4 pim_ifstat_reset(ifp); +#endif } return 0; @@ -1683,8 +1772,6 @@ static int pim_ifp_down(struct interface *ifp) static int pim_ifp_destroy(struct interface *ifp) { - struct pim_instance *pim; - if (PIM_DEBUG_ZEBRA) { zlog_debug( "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d", @@ -1696,9 +1783,13 @@ static int pim_ifp_destroy(struct interface *ifp) if (!if_is_operative(ifp)) pim_if_addr_del_all(ifp); +#if PIM_IPV == 4 + struct pim_instance *pim; + pim = ifp->vrf->info; if (pim && pim->vxlan.term_if == ifp) pim_vxlan_del_term_dev(pim); +#endif return 0; } diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 1ddf74361..244e1aedd 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -59,7 +59,8 @@ #define PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPPRESSION(options) \ ((options) &= ~PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPPRESSION) -#define PIM_I_am_DR(pim_ifp) (pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr +#define PIM_I_am_DR(pim_ifp) \ + !pim_addr_cmp((pim_ifp)->pim_dr_addr, (pim_ifp)->primary_address) #define PIM_I_am_DualActive(pim_ifp) (pim_ifp)->activeactive == true /* Macros for interface flags */ @@ -95,6 +96,13 @@ struct pim_interface { uint32_t options; /* bit vector */ ifindex_t mroute_vif_index; struct pim_instance *pim; + +#if PIM_IPV == 6 + /* link-locals: MLD uses lowest addr, PIM uses highest... */ + pim_addr ll_lowest; + pim_addr ll_highest; +#endif + pim_addr primary_address; /* remember addr to detect change */ struct list *sec_addr_list; /* list of struct pim_secondary_addr */ pim_addr update_source; /* user can statically set the primary @@ -181,6 +189,9 @@ struct pim_interface { bool bsm_enable; /* bsm processing enable */ bool ucast_bsm_accept; /* ucast bsm processing */ + uint32_t igmp_ifstat_joins_sent; + uint32_t igmp_ifstat_joins_failed; + struct { bool enabled; uint32_t min_rx; @@ -225,13 +236,12 @@ int pim_if_lan_delay_enabled(struct interface *ifp); uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp); uint16_t pim_if_effective_override_interval_msec(struct interface *ifp); uint16_t pim_if_jp_override_interval_msec(struct interface *ifp); -struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, - struct in_addr addr); +struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, pim_addr addr); long pim_if_t_suppressed_msec(struct interface *ifp); int pim_if_t_override_msec(struct interface *ifp); -struct in_addr pim_find_primary_addr(struct interface *ifp); +pim_addr pim_find_primary_addr(struct interface *ifp); ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr); @@ -240,8 +250,7 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, void pim_if_update_could_assert(struct interface *ifp); -void pim_if_assert_on_neighbor_down(struct interface *ifp, - struct in_addr neigh_addr); +void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr); void pim_if_rpf_interface_changed(struct interface *old_rpf_ifp, struct pim_upstream *up); @@ -252,8 +261,8 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp); void pim_if_create_pimreg(struct pim_instance *pim); -struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr src); -int pim_update_source_set(struct interface *ifp, struct in_addr source); +struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src); +int pim_update_source_set(struct interface *ifp, pim_addr source); bool pim_if_is_vrf_device(struct interface *ifp); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index c0d693071..f9fb8cf09 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -62,19 +62,7 @@ int pim_ifchannel_compare(const struct pim_ifchannel *ch1, if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index) return 1; - if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr)) - return -1; - - if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr)) - return 1; - - if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr)) - return -1; - - if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr)) - return 1; - - return 0; + return pim_sgaddr_cmp(ch1->sg, ch2->sg); } /* @@ -107,18 +95,15 @@ static void pim_ifchannel_find_new_children(struct pim_ifchannel *ch) struct pim_ifchannel *child; // Basic Sanity that we are not being silly - if ((ch->sg.src.s_addr != INADDR_ANY) - && (ch->sg.grp.s_addr != INADDR_ANY)) + if (!pim_addr_is_any(ch->sg.src) && !pim_addr_is_any(ch->sg.grp)) return; - if ((ch->sg.src.s_addr == INADDR_ANY) - && (ch->sg.grp.s_addr == INADDR_ANY)) + if (pim_addr_is_any(ch->sg.src) && pim_addr_is_any(ch->sg.grp)) return; RB_FOREACH (child, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { - if ((ch->sg.grp.s_addr != INADDR_ANY) - && (child->sg.grp.s_addr == ch->sg.grp.s_addr) - && (child != ch)) { + if (!pim_addr_is_any(ch->sg.grp) && + !pim_addr_cmp(child->sg.grp, ch->sg.grp) && (child != ch)) { child->parent = ch; listnode_add_sort(ch->sources, child); } @@ -162,9 +147,9 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) * being inherited. So let's figure out what * needs to be done here */ - if ((ch->sg.src.s_addr != INADDR_ANY) && - pim_upstream_evaluate_join_desired_interface( - ch->upstream, ch, ch->parent)) + if (!pim_addr_is_any(ch->sg.src) && + pim_upstream_evaluate_join_desired_interface( + ch->upstream, ch, ch->parent)) pim_channel_add_oif(ch->upstream->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR, @@ -284,7 +269,7 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, if (old_state == new_state) { if (PIM_DEBUG_PIM_EVENTS) { zlog_debug( - "%s calledby %s: non-transition on state %d (%s)", + "%s called by %s: non-transition on state %d (%s)", __func__, caller, new_state, pim_ifchannel_ifjoin_name(new_state, 0)); } @@ -293,7 +278,7 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, ch->ifjoin_state = new_state; - if (ch->sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(ch->sg.src)) { struct pim_upstream *up = ch->upstream; struct pim_upstream *child; struct listnode *up_node; @@ -321,8 +306,8 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, * supplying the implied * if channel. So remove it. */ - if (c_oil->oil.mfcc_ttls - [pim_ifp->mroute_vif_index]) + if (oil_if_has(c_oil, + pim_ifp->mroute_vif_index)) pim_channel_del_inherited_oif( c_oil, ch->interface, __func__); @@ -438,11 +423,9 @@ const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state) */ void reset_ifassert_state(struct pim_ifchannel *ch) { - struct in_addr any = {.s_addr = INADDR_ANY}; - THREAD_OFF(ch->t_ifassert_timer); - pim_ifassert_winner_set(ch, PIM_IFASSERT_NOINFO, any, + pim_ifassert_winner_set(ch, PIM_IFASSERT_NOINFO, PIMADDR_ANY, router->infinite_assert_metric); } @@ -455,8 +438,8 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, pim_sgaddr *sg) pim_ifp = ifp->info; if (!pim_ifp) { - zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s", - __func__, pim_str_sg_dump(sg), ifp->name); + zlog_warn("%s: (S,G)=%pSG: multicast not enabled on interface %s", + __func__, sg, ifp->name); return NULL; } @@ -527,9 +510,9 @@ static struct pim_ifchannel *pim_ifchannel_find_parent(struct pim_ifchannel *ch) struct pim_ifchannel *parent = NULL; // (S,G) - if ((parent_sg.src.s_addr != INADDR_ANY) - && (parent_sg.grp.s_addr != INADDR_ANY)) { - parent_sg.src.s_addr = INADDR_ANY; + if (!pim_addr_is_any(parent_sg.src) && + !pim_addr_is_any(parent_sg.grp)) { + parent_sg.src = PIMADDR_ANY; parent = pim_ifchannel_find(ch->interface, &parent_sg); if (parent) @@ -558,8 +541,7 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, if (ch->upstream) ch->upstream->flags |= up_flags; else if (PIM_DEBUG_EVENTS) - zlog_debug("%s:%s No Upstream found", __func__, - pim_str_sg_dump(sg)); + zlog_debug("%s:%pSG No Upstream found", __func__, sg); return ch; } @@ -575,9 +557,9 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, ch->interface = ifp; ch->sg = *sg; - pim_str_sg_set(sg, ch->sg_str); + snprintfrr(ch->sg_str, sizeof(ch->sg_str), "%pSG", sg); ch->parent = pim_ifchannel_find_parent(ch); - if (ch->sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(ch->sg.src)) { ch->sources = list_new(); ch->sources->cmp = (int (*)(void *, void *))pim_ifchannel_compare; @@ -603,7 +585,7 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch); ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch); - ch->ifassert_winner.s_addr = INADDR_ANY; + ch->ifassert_winner = PIMADDR_ANY; /* Assert state */ ch->t_ifassert_timer = NULL; @@ -662,7 +644,7 @@ static void ifjoin_to_noinfo(struct pim_ifchannel *ch) delete_on_noinfo(ch); } -static int on_ifjoin_expiry_timer(struct thread *t) +static void on_ifjoin_expiry_timer(struct thread *t) { struct pim_ifchannel *ch; @@ -674,11 +656,9 @@ static int on_ifjoin_expiry_timer(struct thread *t) ifjoin_to_noinfo(ch); /* ch may have been deleted */ - - return 0; } -static int on_ifjoin_prune_pending_timer(struct thread *t) +static void on_ifjoin_prune_pending_timer(struct thread *t) { struct pim_ifchannel *ch; int send_prune_echo; /* boolean */ @@ -688,10 +668,9 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) ch = THREAD_ARG(t); if (PIM_DEBUG_PIM_TRACE) - zlog_debug( - "%s: IFCHANNEL%s %s Prune Pending Timer Popped", - __func__, pim_str_sg_dump(&ch->sg), - pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags)); + zlog_debug("%s: IFCHANNEL%pSG %s Prune Pending Timer Popped", + __func__, &ch->sg, + pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags)); if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING) { ifp = ch->interface; @@ -705,8 +684,8 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) struct pim_rpf rpf; rpf.source_nexthop.interface = ifp; - rpf.rpf_addr.u.prefix4 = - pim_ifp->primary_address; + pim_addr_to_prefix(&rpf.rpf_addr, + pim_ifp->primary_address); pim_jp_agg_single_upstream_send( &rpf, ch->upstream, 0); } @@ -745,16 +724,15 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) } /* from here ch may have been deleted */ } - - return 0; } static void check_recv_upstream(int is_join, struct interface *recv_ifp, - struct in_addr upstream, pim_sgaddr *sg, + pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, int holdtime) { struct pim_upstream *up; struct pim_interface *pim_ifp = recv_ifp->info; + pim_addr rpf_addr; /* Upstream (S,G) in Joined state ? */ up = pim_upstream_find(pim_ifp->pim, sg); @@ -772,16 +750,13 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp, return; } + rpf_addr = pim_addr_from_prefix(&up->rpf.rpf_addr); + /* upstream directed to RPF'(S,G) ? */ - if (upstream.s_addr != up->rpf.rpf_addr.u.prefix4.s_addr) { - char up_str[INET_ADDRSTRLEN]; - char rpf_str[PREFIX_STRLEN]; - pim_inet4_dump("", upstream, up_str, sizeof(up_str)); - pim_addr_dump("", &up->rpf.rpf_addr, rpf_str, - sizeof(rpf_str)); + if (pim_addr_cmp(upstream, rpf_addr)) { zlog_warn( - "%s %s: (S,G)=%s upstream=%s not directed to RPF'(S,G)=%s on interface %s", - __FILE__, __func__, up->sg_str, up_str, rpf_str, + "%s %s: (S,G)=%s upstream=%pPAs not directed to RPF'(S,G)=%pPAs on interface %s", + __FILE__, __func__, up->sg_str, &upstream, &rpf_addr, recv_ifp->name); return; } @@ -789,8 +764,7 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp, if (is_join) { /* Join(S,G) to RPF'(S,G) */ - pim_upstream_join_suppress(up, up->rpf.rpf_addr.u.prefix4, - holdtime); + pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime); return; } @@ -815,7 +789,7 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp, } static int nonlocal_upstream(int is_join, struct interface *recv_ifp, - struct in_addr upstream, pim_sgaddr *sg, + pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *recv_pim_ifp; @@ -824,18 +798,16 @@ static int nonlocal_upstream(int is_join, struct interface *recv_ifp, recv_pim_ifp = recv_ifp->info; assert(recv_pim_ifp); - is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr); + is_local = !pim_addr_cmp(upstream, recv_pim_ifp->primary_address); if (is_local) return 0; - if (PIM_DEBUG_PIM_TRACE_DETAIL) { - char up_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", upstream, up_str, sizeof(up_str)); - zlog_warn("%s: recv %s (S,G)=%s to non-local upstream=%s on %s", - __func__, is_join ? "join" : "prune", - pim_str_sg_dump(sg), up_str, recv_ifp->name); - } + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_warn( + "%s: recv %s (S,G)=%pSG to non-local upstream=%pPAs on %s", + __func__, is_join ? "join" : "prune", sg, &upstream, + recv_ifp->name); /* * Since recv upstream addr was not directed to our primary @@ -868,8 +840,8 @@ static void pim_ifchannel_ifjoin_handler(struct pim_ifchannel *ch, } -void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, - struct in_addr upstream, pim_sgaddr *sg, +void pim_ifchannel_join_add(struct interface *ifp, pim_addr neigh_addr, + pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *pim_ifp; @@ -900,11 +872,8 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, address of the join message is our primary address. */ if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { - char neigh_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", neigh_addr, neigh_str, - sizeof(neigh_str)); - zlog_warn("%s: Assert Loser recv Join%s from %s on %s", - __func__, ch->sg_str, neigh_str, ifp->name); + zlog_warn("%s: Assert Loser recv Join%s from %pPA on %s", + __func__, ch->sg_str, &neigh_addr, ifp->name); assert_action_a5(ch); } @@ -994,8 +963,8 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, THREAD_OFF(ch->t_ifjoin_prune_pending_timer); /* Check if SGRpt join Received */ - if ((source_flags & PIM_ENCODE_RPT_BIT) - && (sg->src.s_addr != INADDR_ANY)) { + if ((source_flags & PIM_ENCODE_RPT_BIT) && + !pim_addr_is_any(sg->src)) { /* * Transitions from Prune-Pending State (Rcv SGRpt Join) * RFC 7761 Sec 4.5.3: @@ -1033,7 +1002,7 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, } } -void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, +void pim_ifchannel_prune(struct interface *ifp, pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { @@ -1049,10 +1018,9 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, ch = pim_ifchannel_find(ifp, sg); if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT)) { if (PIM_DEBUG_PIM_TRACE) - zlog_debug( - "%s: Received prune with no relevant ifchannel %s%s state: %d", - __func__, ifp->name, pim_str_sg_dump(sg), - source_flags); + zlog_debug("%s: Received prune with no relevant ifchannel %s%pSG state: %d", + __func__, ifp->name, sg, + source_flags); return; } @@ -1182,28 +1150,26 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg, pim_ifp = ifp->info; if (!pim_ifp) { if (PIM_DEBUG_EVENTS) - zlog_debug("%s:%s Expected pim interface setup for %s", - __func__, pim_str_sg_dump(sg), ifp->name); + zlog_debug("%s:%pSG Expected pim interface setup for %s", + __func__, sg, ifp->name); return 0; } if (!PIM_IF_TEST_PIM(pim_ifp->options)) { if (PIM_DEBUG_EVENTS) - zlog_debug( - "%s:%s PIM is not configured on this interface %s", - __func__, pim_str_sg_dump(sg), ifp->name); + zlog_debug("%s:%pSG PIM is not configured on this interface %s", + __func__, sg, ifp->name); return 0; } pim = pim_ifp->pim; /* skip (*,G) ch creation if G is of type SSM */ - if (sg->src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(sg->src)) { if (pim_is_grp_ssm(pim, sg->grp)) { if (PIM_DEBUG_PIM_EVENTS) - zlog_debug( - "%s: local membership (S,G)=%s ignored as group is SSM", - __func__, pim_str_sg_dump(sg)); + zlog_debug("%s: local membership (S,G)=%pSG ignored as group is SSM", + __func__, sg); return 1; } } @@ -1217,7 +1183,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg, ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE); - if (sg->src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(sg->src)) { struct pim_upstream *up = pim_upstream_find(pim, sg); struct pim_upstream *child; struct listnode *up_node; @@ -1255,10 +1221,8 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg, struct prefix_list *plist = prefix_list_lookup( AFI_IP, pim->spt.plist); struct prefix g; - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; - g.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&g, up->sg.grp); if (prefix_list_apply(plist, &g) == PREFIX_DENY) { pim_channel_add_oif( @@ -1293,7 +1257,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, pim_sgaddr *sg) return; ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); - if (sg->src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(sg->src)) { struct pim_upstream *up = pim_upstream_find(pim_ifp->pim, sg); struct pim_upstream *child; struct listnode *up_node, *up_nnode; @@ -1322,7 +1286,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, pim_sgaddr *sg) if (!pim_upstream_evaluate_join_desired_interface( child, ch, starch) || (!chchannel && - c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])) { + oil_if_has(c_oil, pim_ifp->mroute_vif_index))) { pim_channel_del_inherited_oif(c_oil, ifp, __func__); } @@ -1351,15 +1315,11 @@ void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch) if (new_couldassert == old_couldassert) return; - if (PIM_DEBUG_PIM_EVENTS) { - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", ch->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", ch->sg.grp, grp_str, sizeof(grp_str)); - zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d", - __func__, src_str, grp_str, ch->interface->name, - old_couldassert, new_couldassert); - } + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: CouldAssert(%pPAs,%pPAs,%s) changed from %d to %d", + __func__, &ch->sg.src, &ch->sg.grp, + ch->interface->name, old_couldassert, + new_couldassert); if (new_couldassert) { /* CouldAssert(S,G,I) switched from false to true */ @@ -1392,27 +1352,17 @@ void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch) if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric)) return; - if (PIM_DEBUG_PIM_EVENTS) { - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; - char old_addr_str[INET_ADDRSTRLEN]; - char new_addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", ch->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", ch->sg.grp, grp_str, sizeof(grp_str)); - pim_inet4_dump("", ch->ifassert_my_metric.ip_address, - old_addr_str, sizeof(old_addr_str)); - pim_inet4_dump("", my_metric_new.ip_address, - new_addr_str, sizeof(new_addr_str)); + if (PIM_DEBUG_PIM_EVENTS) zlog_debug( - "%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s", - __func__, src_str, grp_str, ch->interface->name, + "%s: my_assert_metric(%pPAs,%pPAs,%s) changed from %u,%u,%u,%pPAs to %u,%u,%u,%pPAs", + __func__, &ch->sg.src, &ch->sg.grp, ch->interface->name, ch->ifassert_my_metric.rpt_bit_flag, ch->ifassert_my_metric.metric_preference, - ch->ifassert_my_metric.route_metric, old_addr_str, + ch->ifassert_my_metric.route_metric, + &ch->ifassert_my_metric.ip_address, my_metric_new.rpt_bit_flag, my_metric_new.metric_preference, - my_metric_new.route_metric, new_addr_str); - } + my_metric_new.route_metric, &my_metric_new.ip_address); ch->ifassert_my_metric = my_metric_new; @@ -1432,16 +1382,11 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch) if (new_atd == old_atd) return; - if (PIM_DEBUG_PIM_EVENTS) { - char src_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", ch->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("", ch->sg.grp, grp_str, sizeof(grp_str)); + if (PIM_DEBUG_PIM_EVENTS) zlog_debug( - "%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d", - __func__, src_str, grp_str, ch->interface->name, + "%s: AssertTrackingDesired(%pPAs,%pPAs,%s) changed from %d to %d", + __func__, &ch->sg.src, &ch->sg.grp, ch->interface->name, old_atd, new_atd); - } if (new_atd) { /* AssertTrackingDesired(S,G,I) switched from false to true */ diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index ab405202e..0c5b6780d 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -126,10 +126,10 @@ void pim_ifchannel_delete_on_noinfo(struct interface *ifp); struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, pim_sgaddr *sg); struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, uint8_t ch_flags, int up_flags); -void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, - struct in_addr upstream, pim_sgaddr *sg, +void pim_ifchannel_join_add(struct interface *ifp, pim_addr neigh_addr, + pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime); -void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, +void pim_ifchannel_prune(struct interface *ifp, pim_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime); int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg, diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index cf7613f4e..fcb335a5b 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -37,10 +37,179 @@ #include "pim_str.h" #include "pim_util.h" #include "pim_time.h" -#include "pim_zebra.h" +#include "pim_ssm.h" +#include "pim_tib.h" static void group_timer_off(struct gm_group *group); -static int pim_igmp_general_query(struct thread *t); +static void pim_igmp_general_query(struct thread *t); + +void igmp_anysource_forward_start(struct pim_instance *pim, + struct gm_group *group) +{ + struct gm_source *source; + struct in_addr src_addr = {.s_addr = 0}; + /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ + assert(group->group_filtermode_isexcl); + assert(listcount(group->group_source_list) < 1); + + source = igmp_get_source_by_addr(group, src_addr, NULL); + if (!source) { + zlog_warn("%s: Failure to create * source", __func__); + return; + } + + igmp_source_forward_start(pim, source); +} + +void igmp_anysource_forward_stop(struct gm_group *group) +{ + struct gm_source *source; + struct in_addr star = {.s_addr = 0}; + + source = igmp_find_source_by_addr(group, star); + if (source) + igmp_source_forward_stop(source); +} + +static void igmp_source_forward_reevaluate_one(struct pim_instance *pim, + struct gm_source *source) +{ + pim_sgaddr sg; + struct gm_group *group = source->source_group; + struct pim_ifchannel *ch; + + if ((source->source_addr.s_addr != INADDR_ANY) || + !IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) + return; + + memset(&sg, 0, sizeof(sg)); + sg.src = source->source_addr; + sg.grp = group->group_addr; + + ch = pim_ifchannel_find(group->interface, &sg); + if (pim_is_grp_ssm(pim, group->group_addr)) { + /* If SSM group withdraw local membership */ + if (ch && + (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug( + "local membership del for %pSG as G is now SSM", + &sg); + pim_ifchannel_local_membership_del(group->interface, + &sg); + } + } else { + /* If ASM group add local membership */ + if (!ch || + (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug( + "local membership add for %pSG as G is now ASM", + &sg); + pim_ifchannel_local_membership_add( + group->interface, &sg, false /*is_vxlan*/); + } + } +} + +void igmp_source_forward_reevaluate_all(struct pim_instance *pim) +{ + struct interface *ifp; + + FOR_ALL_INTERFACES (pim->vrf, ifp) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *grpnode; + struct gm_group *grp; + struct pim_ifchannel *ch, *ch_temp; + + if (!pim_ifp) + continue; + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, + grp)) { + struct listnode *srcnode; + struct gm_source *src; + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, + srcnode, src)) { + igmp_source_forward_reevaluate_one(pim, src); + } /* scan group sources */ + } /* scan igmp groups */ + + RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb, + ch_temp) { + if (pim_is_grp_ssm(pim, ch->sg.grp)) { + if (pim_addr_is_any(ch->sg.src)) + pim_ifchannel_delete(ch); + } + } + } /* scan interfaces */ +} + +void igmp_source_forward_start(struct pim_instance *pim, + struct gm_source *source) +{ + struct gm_group *group; + pim_sgaddr sg; + + memset(&sg, 0, sizeof(sg)); + sg.src = source->source_addr; + sg.grp = source->source_group->group_addr; + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg, + source->source_group->interface->name, + IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); + } + + /* Prevent IGMP interface from installing multicast route multiple + times */ + if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { + return; + } + + group = source->source_group; + + if (tib_sg_gm_join(pim, sg, group->interface, + &source->source_channel_oil)) + IGMP_SOURCE_DO_FORWARDING(source->source_flags); +} + +/* + igmp_source_forward_stop: stop fowarding, but keep the source + igmp_source_delete: stop fowarding, and delete the source + */ +void igmp_source_forward_stop(struct gm_source *source) +{ + struct pim_interface *pim_oif; + struct gm_group *group; + pim_sgaddr sg; + + memset(&sg, 0, sizeof(sg)); + sg.src = source->source_addr; + sg.grp = source->source_group->group_addr; + + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg, + source->source_group->interface->name, + IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); + } + + /* Prevent IGMP interface from removing multicast route multiple + times */ + if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { + return; + } + + group = source->source_group; + pim_oif = group->interface->info; + + tib_sg_gm_prune(pim_oif->pim, sg, group->interface, + &source->source_channel_oil); + IGMP_SOURCE_DONT_FORWARDING(source->source_flags); +} /* This socket is used for TXing IGMP packets only, IGMP RX happens * in pim_mroute_msg() @@ -51,6 +220,7 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp, int fd; int join = 0; struct in_addr group; + struct pim_interface *pim_ifp = ifp->info; fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, ifp, 1); @@ -59,7 +229,8 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp, if (PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(pim_options)) { if (inet_aton(PIM_ALL_ROUTERS, &group)) { - if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex)) + if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex, + pim_ifp)) ++join; } else { zlog_warn( @@ -75,7 +246,7 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp, IGMP routers must receive general queries for querier election. */ if (inet_aton(PIM_ALL_SYSTEMS, &group)) { - if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex)) + if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex, pim_ifp)) ++join; } else { zlog_warn( @@ -85,7 +256,8 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp, } if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) { - if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex)) { + if (!pim_socket_join(fd, group, ifaddr, ifp->ifindex, + pim_ifp)) { ++join; } } else { @@ -141,7 +313,7 @@ struct gm_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, return NULL; } -static int pim_igmp_other_querier_expire(struct thread *t) +static void pim_igmp_other_querier_expire(struct thread *t) { struct gm_sock *igmp; @@ -166,8 +338,6 @@ static int pim_igmp_other_querier_expire(struct thread *t) Query, Set Gen. Query. timer) */ pim_igmp_general_query(t); - - return 0; } void pim_igmp_other_querier_timer_on(struct gm_sock *igmp) @@ -322,16 +492,16 @@ static int igmp_recv_query(struct gm_sock *igmp, int query_version, /* Collecting IGMP Rx stats */ switch (query_version) { case 1: - igmp->rx_stats.query_v1++; + igmp->igmp_stats.query_v1++; break; case 2: - igmp->rx_stats.query_v2++; + igmp->igmp_stats.query_v2++; break; case 3: - igmp->rx_stats.query_v3++; + igmp->igmp_stats.query_v3++; break; default: - igmp->rx_stats.unsupported++; + igmp->igmp_stats.unsupported++; } /* @@ -377,6 +547,30 @@ static int igmp_recv_query(struct gm_sock *igmp, int query_version, */ if (ntohl(from.s_addr) < ntohl(igmp->ifaddr.s_addr)) { + /* As per RFC 2236 section 3: + * When a Querier receives a Leave Group message for a group + * that has group members on the reception interface, it sends + * [Last Member Query Count] Group-Specific Queries every [Last + * Member Query Interval] to the group being left. These + * Group-Specific Queries have their Max Response time set to + * [Last Member Query Interval]. If no Reports are received + * after the response time of the last query expires, the + * routers assume that the group has no local members, as above. + * Any Querier to non-Querier transition is ignored during this + * time; the same router keeps sending the Group-Specific + * Queries. + */ + struct gm_group *group; + + group = find_group_by_addr(igmp, group_addr); + if (group && group->t_group_query_retransmit_timer) { + if (PIM_DEBUG_IGMP_TRACE) + zlog_debug( + "%s: lower address query packet from %s is ignored when last member query interval timer is running", + ifp->name, from_str); + return 0; + } + if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[INET_ADDRSTRLEN]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, @@ -439,7 +633,7 @@ static int igmp_v1_recv_report(struct gm_sock *igmp, struct in_addr from, } /* Collecting IGMP Rx stats */ - igmp->rx_stats.report_v1++; + igmp->igmp_stats.report_v1++; if (PIM_DEBUG_IGMP_TRACE) { zlog_warn("%s %s: FIXME WRITEME", __FILE__, __func__); @@ -504,17 +698,6 @@ bool pim_igmp_verify_header(struct ip *ip_hdr, size_t len, size_t *hlen) } } - if ((msg_type == PIM_IGMP_V3_MEMBERSHIP_REPORT) - || ((msg_type == PIM_IGMP_MEMBERSHIP_QUERY) - && (igmp_msg_len >= IGMP_V3_SOURCES_OFFSET))) { - /* All IGMPv3 messages must be received with TOS set to 0xC0*/ - if (ip_hdr->ip_tos != IPTOS_PREC_INTERNETCONTROL) { - zlog_warn("Received IGMP Packet with invalid TOS %u", - ip_hdr->ip_tos); - return false; - } - } - return true; } @@ -602,7 +785,7 @@ int pim_igmp_packet(struct gm_sock *igmp, char *buf, size_t len) zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type); /* Collecting IGMP Rx stats */ - igmp->rx_stats.unsupported++; + igmp->igmp_stats.unsupported++; return -1; } @@ -681,7 +864,7 @@ void pim_igmp_general_query_off(struct gm_sock *igmp) } /* Issue IGMP general query */ -static int pim_igmp_general_query(struct thread *t) +static void pim_igmp_general_query(struct thread *t) { struct gm_sock *igmp; struct in_addr dst_addr; @@ -735,8 +918,6 @@ static int pim_igmp_general_query(struct thread *t) igmp->querier_query_interval); pim_igmp_general_query_on(igmp); - - return 0; } static void sock_close(struct gm_sock *igmp) @@ -981,7 +1162,7 @@ static struct gm_sock *igmp_sock_new(int fd, struct in_addr ifaddr, pim_ifp->gm_default_robustness_variable; igmp->sock_creation = pim_time_monotonic_sec(); - igmp_stats_init(&igmp->rx_stats); + igmp_stats_init(&igmp->igmp_stats); if (mtrace_only) { igmp->mtrace_only = mtrace_only; @@ -1003,12 +1184,12 @@ static struct gm_sock *igmp_sock_new(int fd, struct in_addr ifaddr, static void igmp_read_on(struct gm_sock *igmp); -static int pim_igmp_read(struct thread *t) +static void pim_igmp_read(struct thread *t) { uint8_t buf[10000]; struct gm_sock *igmp = (struct gm_sock *)THREAD_ARG(t); - struct sockaddr_in from; - struct sockaddr_in to; + struct sockaddr_storage from; + struct sockaddr_storage to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); ifindex_t ifindex = -1; @@ -1029,7 +1210,6 @@ static int pim_igmp_read(struct thread *t) done: igmp_read_on(igmp); - return 0; } static void igmp_read_on(struct gm_sock *igmp) @@ -1099,7 +1279,7 @@ struct gm_sock *pim_igmp_sock_add(struct list *igmp_sock_list, source records. Source records whose timers are zero (from the previous EXCLUDE mode) are deleted. */ -static int igmp_group_timer(struct thread *t) +static void igmp_group_timer(struct thread *t) { struct gm_group *group; @@ -1133,8 +1313,6 @@ static int igmp_group_timer(struct thread *t) if (listcount(group->group_source_list) < 1) { igmp_group_delete_empty_include(group); } - - return 0; } static void group_timer_off(struct gm_group *group) diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index b82b62ea7..4160dcb11 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -100,11 +100,12 @@ struct gm_sock { bool mtrace_only; - struct igmp_stats rx_stats; + struct igmp_stats igmp_stats; }; struct pim_interface; +#if PIM_IPV == 4 void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp); void pim_igmp_if_reset(struct pim_interface *pim_ifp); void pim_igmp_if_fini(struct pim_interface *pim_ifp); @@ -126,6 +127,33 @@ void pim_igmp_other_querier_timer_off(struct gm_sock *igmp); int igmp_validate_checksum(char *igmp_msg, int igmp_msg_len); +#else /* PIM_IPV != 4 */ +static inline void pim_igmp_if_init(struct pim_interface *pim_ifp, + struct interface *ifp) +{ +} + +static inline void pim_igmp_if_fini(struct pim_interface *pim_ifp) +{ +} + +static inline void pim_igmp_general_query_on(struct gm_sock *igmp) +{ +} + +static inline void pim_igmp_general_query_off(struct gm_sock *igmp) +{ +} + +static inline void pim_igmp_other_querier_timer_on(struct gm_sock *igmp) +{ +} + +static inline void pim_igmp_other_querier_timer_off(struct gm_sock *igmp) +{ +} +#endif /* PIM_IPV == 4 */ + #define IGMP_SOURCE_MASK_FORWARDING (1 << 0) #define IGMP_SOURCE_MASK_DELETE (1 << 1) #define IGMP_SOURCE_MASK_SEND (1 << 2) @@ -184,6 +212,18 @@ struct gm_group { int64_t last_igmp_v2_report_dsec; }; +#if PIM_IPV == 4 +struct pim_instance; + +void igmp_anysource_forward_start(struct pim_instance *pim, + struct gm_group *group); +void igmp_anysource_forward_stop(struct gm_group *group); + +void igmp_source_forward_start(struct pim_instance *pim, + struct gm_source *source); +void igmp_source_forward_stop(struct gm_source *source); +void igmp_source_forward_reevaluate_all(struct pim_instance *pim); + struct gm_group *find_group_by_addr(struct gm_sock *igmp, struct in_addr group_addr); struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp, @@ -210,4 +250,11 @@ void igmp_send_query(int igmp_version, struct gm_group *group, int fd, void igmp_group_delete(struct gm_group *group); void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver); + +#else /* PIM_IPV != 4 */ +static inline void igmp_startup_mode_on(struct gm_sock *igmp) +{ +} +#endif /* PIM_IPV != 4 */ + #endif /* PIM_IGMP_H */ diff --git a/pimd/pim_igmp_join.h b/pimd/pim_igmp_join.h index c32390276..8027b8b94 100644 --- a/pimd/pim_igmp_join.h +++ b/pimd/pim_igmp_join.h @@ -39,9 +39,9 @@ struct group_source_req { }; #endif -static int pim_igmp_join_source(int fd, ifindex_t ifindex, - struct in_addr group_addr, - struct in_addr source_addr) +static inline int pim_igmp_join_source(int fd, ifindex_t ifindex, + struct in_addr group_addr, + struct in_addr source_addr) { struct group_source_req req; struct sockaddr_in group; diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index 1518ef232..11bb2db7e 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -119,7 +119,7 @@ static bool mtrace_fwd_info(struct pim_instance *pim, up = pim_upstream_find(pim, &sg); if (!up) { - sg.src.s_addr = INADDR_ANY; + sg.src = PIMADDR_ANY; up = pim_upstream_find(pim, &sg); } @@ -154,7 +154,7 @@ static bool mtrace_fwd_info(struct pim_instance *pim, rspp->rtg_proto = MTRACE_RTG_PROTO_PIM; /* 6.2.2. 4. Fill in ... S, and Src Mask */ - if (sg.src.s_addr != INADDR_ANY) { + if (!pim_addr_is_any(sg.src)) { rspp->s = 1; rspp->src_mask = MTRACE_SRC_MASK_SOURCE; } else { @@ -626,7 +626,7 @@ int igmp_mtrace_recv_qry_req(struct gm_sock *igmp, struct ip *ip_hdr, } /* Collecting IGMP Rx stats */ - igmp->rx_stats.mtrace_req++; + igmp->igmp_stats.mtrace_req++; if (PIM_DEBUG_MTRACE) mtrace_debug(pim_ifp, mtracep, igmp_msg_len); @@ -843,7 +843,7 @@ int igmp_mtrace_recv_response(struct gm_sock *igmp, struct ip *ip_hdr, mtracep->checksum = checksum; /* Collecting IGMP Rx stats */ - igmp->rx_stats.mtrace_rsp++; + igmp->igmp_stats.mtrace_rsp++; if (PIM_DEBUG_MTRACE) mtrace_debug(pim_ifp, mtracep, igmp_msg_len); diff --git a/pimd/pim_igmp_stats.c b/pimd/pim_igmp_stats.c index 40851a452..e1eb166b6 100644 --- a/pimd/pim_igmp_stats.c +++ b/pimd/pim_igmp_stats.c @@ -43,4 +43,8 @@ void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b) a->mtrace_rsp += b->mtrace_rsp; a->mtrace_req += b->mtrace_req; a->unsupported += b->unsupported; + a->total_groups += b->total_groups; + a->total_source_groups += b->total_source_groups; + a->joins_sent += b->joins_sent; + a->joins_failed += b->joins_failed; } diff --git a/pimd/pim_igmp_stats.h b/pimd/pim_igmp_stats.h index 57b5cc62f..42c0c9ee3 100644 --- a/pimd/pim_igmp_stats.h +++ b/pimd/pim_igmp_stats.h @@ -33,9 +33,23 @@ struct igmp_stats { uint32_t mtrace_rsp; uint32_t mtrace_req; uint32_t unsupported; + uint32_t total_groups; + uint32_t total_source_groups; + uint32_t joins_sent; + uint32_t joins_failed; }; +#if PIM_IPV == 4 void igmp_stats_init(struct igmp_stats *stats); void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b); +#else +static inline void igmp_stats_init(struct igmp_stats *stats) +{ +} + +static inline void igmp_stats_add(struct igmp_stats *a, struct igmp_stats *b) +{ +} +#endif #endif /* PIM_IGMP_STATS_H */ diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c index a7c7c99eb..09a82069a 100644 --- a/pimd/pim_igmpv2.c +++ b/pimd/pim_igmpv2.c @@ -130,7 +130,7 @@ int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from, } /* Collecting IGMP Rx stats */ - igmp->rx_stats.report_v2++; + igmp->igmp_stats.report_v2++; memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); @@ -221,7 +221,7 @@ int igmp_v2_recv_leave(struct gm_sock *igmp, struct ip *ip_hdr, } /* Collecting IGMP Rx stats */ - igmp->rx_stats.leave_v2++; + igmp->igmp_stats.leave_v2++; /* * RFC 3376 diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 492af5f2d..1ce5fdc4b 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -118,7 +118,7 @@ void igmp_group_reset_gmi(struct gm_group *group) igmp_group_timer_on(group, group_membership_interval_msec, ifp->name); } -static int igmp_source_timer(struct thread *t) +static void igmp_source_timer(struct thread *t) { struct gm_source *source; struct gm_group *group; @@ -179,8 +179,6 @@ static int igmp_source_timer(struct thread *t) igmp_group_delete_empty_include(group); } } - - return 0; } static void source_timer_off(struct gm_group *group, struct gm_source *source) @@ -1212,7 +1210,7 @@ static int group_retransmit_sources(struct gm_group *group, return num_retransmit_sources_left; } -static int igmp_group_retransmit(struct thread *t) +static void igmp_group_retransmit(struct thread *t) { struct gm_group *group; int num_retransmit_sources_left; @@ -1262,8 +1260,6 @@ static int igmp_group_retransmit(struct thread *t) || (group->group_specific_query_retransmit_count > 0)) { group_retransmit_timer_on(group); } - - return 0; } /* @@ -1675,7 +1671,7 @@ void igmp_v3_send_query(struct gm_group *group, int fd, const char *ifname, */ if (!s_flag) { /* general query? */ - if (PIM_INADDR_IS_ANY(group_addr)) { + if (group_addr.s_addr == INADDR_ANY) { char dst_str[INET_ADDRSTRLEN]; char group_str[INET_ADDRSTRLEN]; pim_inet4_dump("", dst_addr, dst_str, @@ -1762,7 +1758,7 @@ void igmp_v3_recv_query(struct gm_sock *igmp, const char *from_str, if (!s_flag) { /* s_flag is clear */ - if (PIM_INADDR_IS_ANY(group_addr)) { + if (group_addr.s_addr == INADDR_ANY) { /* this is a general query */ /* log that general query should have the s_flag set */ zlog_warn( @@ -1858,7 +1854,7 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from, } /* Collecting IGMP Rx stats */ - igmp->rx_stats.report_v3++; + igmp->igmp_stats.report_v3++; num_groups = ntohs( *(uint16_t *)(igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET)); diff --git a/pimd/pim_igmpv3.h b/pimd/pim_igmpv3.h index 7449e420e..5041e54cb 100644 --- a/pimd/pim_igmpv3.h +++ b/pimd/pim_igmpv3.h @@ -53,6 +53,7 @@ /* OHPI: Older Host Present Interval */ #define PIM_IGMP_OHPI_DSEC(qrv,qqi,qri_dsec) ((qrv) * (10 * (qqi)) + (qri_dsec)) +#if PIM_IPV == 4 void igmp_group_reset_gmi(struct gm_group *group); void igmp_source_reset_gmi(struct gm_group *group, struct gm_source *source); @@ -98,4 +99,16 @@ void igmp_v3_recv_query(struct gm_sock *igmp, const char *from_str, int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len); +#else /* PIM_IPV != 4 */ +static inline void igmp_group_reset_gmi(struct gm_group *group) +{ +} + + +static inline void igmp_source_reset_gmi(struct gm_group *group, + struct gm_source *source) +{ +} +#endif + #endif /* PIM_IGMPV3_H */ diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 5e96d39e8..929beea26 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -54,24 +54,17 @@ static void on_trace(const char *label, struct interface *ifp, } static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, - uint16_t holdtime, struct in_addr upstream, - pim_sgaddr *sg, uint8_t source_flags) + uint16_t holdtime, pim_addr upstream, pim_sgaddr *sg, + uint8_t source_flags) { struct pim_interface *pim_ifp = NULL; - if (PIM_DEBUG_PIM_TRACE) { - char up_str[INET_ADDRSTRLEN]; - char neigh_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", upstream, up_str, sizeof(up_str)); - pim_inet4_dump("", neigh->source_addr, neigh_str, - sizeof(neigh_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", - __func__, pim_str_sg_dump(sg), - !!(source_flags & PIM_RPT_BIT_MASK), - !!(source_flags & PIM_WILDCARD_BIT_MASK), up_str, - holdtime, neigh_str, ifp->name); - } + "%s: join (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s", + __func__, sg, !!(source_flags & PIM_RPT_BIT_MASK), + !!(source_flags & PIM_WILDCARD_BIT_MASK), &upstream, + holdtime, &neigh->source_addr, ifp->name); pim_ifp = ifp->info; assert(pim_ifp); @@ -85,6 +78,7 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, if ((source_flags & PIM_RPT_BIT_MASK) && (source_flags & PIM_WILDCARD_BIT_MASK)) { struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp); + pim_addr rpf_addr; if (!rp) { zlog_warn("%s: Lookup of RP failed for %pSG", __func__, @@ -95,27 +89,22 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, * If the RP sent in the message is not * our RP for the group, drop the message */ - if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) { - char received_rp[INET_ADDRSTRLEN]; - char local_rp[INET_ADDRSTRLEN]; - pim_inet4_dump("", sg->src, received_rp, - sizeof(received_rp)); - pim_inet4_dump("", rp->rpf_addr.u.prefix4, - local_rp, sizeof(local_rp)); + rpf_addr = pim_addr_from_prefix(&rp->rpf_addr); + if (pim_addr_cmp(sg->src, rpf_addr)) { zlog_warn( - "%s: Specified RP(%s) in join is different than our configured RP(%s)", - __func__, received_rp, local_rp); + "%s: Specified RP(%pPAs) in join is different than our configured RP(%pPAs)", + __func__, &sg->src, &rpf_addr); return; } if (pim_is_grp_ssm(pim_ifp->pim, sg->grp)) { zlog_warn( - "%s: Specified Group(%pI4) in join is now in SSM, not allowed to create PIM state", + "%s: Specified Group(%pPA) in join is now in SSM, not allowed to create PIM state", __func__, &sg->grp); return; } - sg->src.s_addr = INADDR_ANY; + sg->src = PIMADDR_ANY; } /* Restart join expiry timer */ @@ -124,24 +113,17 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, } static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, - uint16_t holdtime, struct in_addr upstream, - pim_sgaddr *sg, uint8_t source_flags) + uint16_t holdtime, pim_addr upstream, pim_sgaddr *sg, + uint8_t source_flags) { struct pim_interface *pim_ifp = NULL; - if (PIM_DEBUG_PIM_TRACE) { - char up_str[INET_ADDRSTRLEN]; - char neigh_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", upstream, up_str, sizeof(up_str)); - pim_inet4_dump("", neigh->source_addr, neigh_str, - sizeof(neigh_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", - __func__, pim_str_sg_dump(sg), - source_flags & PIM_RPT_BIT_MASK, - source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime, - neigh_str, ifp->name); - } + "%s: prune (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s", + __func__, sg, source_flags & PIM_RPT_BIT_MASK, + source_flags & PIM_WILDCARD_BIT_MASK, &upstream, + holdtime, &neigh->source_addr, ifp->name); pim_ifp = ifp->info; assert(pim_ifp); @@ -155,26 +137,21 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, * Received Prune(*,G) messages are processed even if the * RP in the message does not match RP(G). */ - if (PIM_DEBUG_PIM_TRACE) { - char received_rp[INET_ADDRSTRLEN]; - - pim_inet4_dump("", sg->src, received_rp, - sizeof(received_rp)); - zlog_debug("%s: Prune received with RP(%s) for %pSG", - __func__, received_rp, sg); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: Prune received with RP(%pPAs) for %pSG", + __func__, &sg->src, sg); - sg->src.s_addr = INADDR_ANY; + sg->src = PIMADDR_ANY; } pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime); } int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, - struct in_addr src_addr, uint8_t *tlv_buf, - int tlv_buf_size) + pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) { - struct prefix msg_upstream_addr; + pim_addr msg_upstream_addr; + bool wrong_af = false; struct pim_interface *pim_ifp; uint8_t msg_num_groups; uint16_t msg_holdtime; @@ -193,13 +170,11 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, /* Parse ucast addr */ - addr_offset = - pim_parse_addr_ucast(&msg_upstream_addr, buf, pastend - buf); + addr_offset = pim_parse_addr_ucast(&msg_upstream_addr, buf, + pastend - buf, &wrong_af); if (addr_offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", - __func__, src_str, ifp->name); + zlog_warn("%s: pim_parse_addr_ucast() failure: from %pPA on %s", + __func__, &src_addr, ifp->name); return -1; } buf += addr_offset; @@ -207,22 +182,18 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, /* Check upstream address family */ - if (msg_upstream_addr.family != AF_INET) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (wrong_af) { zlog_warn( - "%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", - __func__, msg_upstream_addr.family, src_str, ifp->name); + "%s: ignoring join/prune directed to unexpected addr family from %pPA on %s", + __func__, &src_addr, ifp->name); return -2; } remain = pastend - buf; if (remain < 4) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s", - __func__, remain, 4, src_str, ifp->name); + "%s: short join/prune message buffer for group list: size=%d minimum=%d from %pPA on %s", + __func__, remain, 4, &src_addr, ifp->name); return -4; } @@ -233,17 +204,11 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, ++buf; ++buf; - if (PIM_DEBUG_PIM_J_P) { - char src_str[INET_ADDRSTRLEN]; - char upstream_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - pim_inet4_dump("", msg_upstream_addr.u.prefix4, - upstream_str, sizeof(upstream_str)); + if (PIM_DEBUG_PIM_J_P) zlog_debug( - "%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s", - __func__, upstream_str, msg_num_groups, msg_holdtime, - src_str, ifp->name); - } + "%s: join/prune upstream=%pPAs groups=%d holdtime=%d from %pPA on %s", + __func__, &msg_upstream_addr, msg_num_groups, + msg_holdtime, &src_addr, ifp->name); /* Scan groups */ for (group = 0; group < msg_num_groups; ++group) { @@ -264,12 +229,9 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, remain = pastend - buf; if (remain < 4) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); zlog_warn( - "%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s", - __func__, remain, 4, src_str, ifp->name); + "%s: short join/prune buffer for source list: size=%d minimum=%d from %pPA on %s", + __func__, remain, 4, &src_addr, ifp->name); return -6; } @@ -278,22 +240,12 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, msg_num_pruned_sources = ntohs(*(const uint16_t *)buf); buf += 2; - if (PIM_DEBUG_PIM_J_P) { - char src_str[INET_ADDRSTRLEN]; - char upstream_str[INET_ADDRSTRLEN]; - char group_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); - pim_inet4_dump("", msg_upstream_addr.u.prefix4, - upstream_str, sizeof(upstream_str)); - pim_inet4_dump("", sg.grp, group_str, - sizeof(group_str)); + if (PIM_DEBUG_PIM_J_P) zlog_debug( - "%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s", - __func__, upstream_str, group_str, + "%s: join/prune upstream=%pPAs group=%pPA/32 join_src=%d prune_src=%d from %pPA on %s", + __func__, &msg_upstream_addr, &sg.grp, msg_num_joined_sources, msg_num_pruned_sources, - src_str, ifp->name); - } + &src_addr, ifp->name); /* boundary check */ filtered = pim_is_group_filtered(pim_ifp, &sg.grp); @@ -312,11 +264,10 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, if (filtered) continue; - recv_join(ifp, neigh, msg_holdtime, - msg_upstream_addr.u.prefix4, &sg, - msg_source_flags); + recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr, + &sg, msg_source_flags); - if (sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(sg.src)) { starg_ch = pim_ifchannel_find(ifp, &sg); if (starg_ch) pim_ifchannel_set_star_g_join_state( @@ -338,9 +289,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, if (filtered) continue; - recv_prune(ifp, neigh, msg_holdtime, - msg_upstream_addr.u.prefix4, &sg, - msg_source_flags); + recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr, + &sg, msg_source_flags); /* * So if we are receiving a S,G,RPT prune * before we have any data for that S,G @@ -489,7 +439,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) return -1; } - if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4)) { + if (rpf->rpf_addr.u.prefix4.s_addr == INADDR_ANY) { if (PIM_DEBUG_PIM_J_P) { char dst_str[INET_ADDRSTRLEN]; pim_inet4_dump("", rpf->rpf_addr.u.prefix4, @@ -528,7 +478,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) grp = &msg->groups[0]; curr_ptr = (uint8_t *)grp; packet_size = sizeof(struct pim_msg_header); - packet_size += sizeof(struct pim_encoded_ipv4_unicast); + packet_size += sizeof(pim_encoded_unicast); packet_size += 4; // reserved (1) + groups (1) + holdtime (2) @@ -537,14 +487,11 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) } if (PIM_DEBUG_PIM_J_P) { char dst_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; pim_inet4_dump("", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str)); - pim_inet4_dump("", group->group, grp_str, - sizeof(grp_str)); zlog_debug( - "%s: sending (G)=%s to upstream=%s on interface %s", - __func__, grp_str, dst_str, + "%s: sending (G)=%pPAs to upstream=%s on interface %s", + __func__, &group->group, dst_str, rpf->source_nexthop.interface->name); } @@ -576,7 +523,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) grp = &msg->groups[0]; curr_ptr = (uint8_t *)grp; packet_size = sizeof(struct pim_msg_header); - packet_size += sizeof(struct pim_encoded_ipv4_unicast); + packet_size += sizeof(pim_encoded_unicast); packet_size += 4; // reserved (1) + groups (1) + holdtime (2) diff --git a/pimd/pim_join.h b/pimd/pim_join.h index 5d28f2ba3..b359f2e5b 100644 --- a/pimd/pim_join.h +++ b/pimd/pim_join.h @@ -27,8 +27,7 @@ #include "pim_neighbor.h" int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, - struct in_addr src_addr, uint8_t *tlv_buf, - int tlv_buf_size); + pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); int pim_joinprune_send(struct pim_rpf *nexthop, struct list *groups); diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index 5c6f55e99..7cbd0304a 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -60,13 +60,7 @@ int pim_jp_agg_group_list_cmp(void *arg1, void *arg2) const struct pim_jp_agg_group *jag2 = (const struct pim_jp_agg_group *)arg2; - if (jag1->group.s_addr < jag2->group.s_addr) - return -1; - - if (jag1->group.s_addr > jag2->group.s_addr) - return 1; - - return 0; + return pim_addr_cmp(jag1->group, jag2->group); } static int pim_jp_agg_src_cmp(void *arg1, void *arg2) @@ -80,13 +74,7 @@ static int pim_jp_agg_src_cmp(void *arg1, void *arg2) if (!js1->is_join && js2->is_join) return 1; - if ((uint32_t)js1->up->sg.src.s_addr < (uint32_t)js2->up->sg.src.s_addr) - return -1; - - if ((uint32_t)js1->up->sg.src.s_addr > (uint32_t)js2->up->sg.src.s_addr) - return 1; - - return 0; + return pim_addr_cmp(js1->up->sg.src, js2->up->sg.src); } /* @@ -121,6 +109,7 @@ pim_jp_agg_get_interface_upstream_switch_list(struct pim_rpf *rpf) struct pim_interface *pim_ifp; struct pim_iface_upstream_switch *pius; struct listnode *node, *nnode; + pim_addr rpf_addr; if (!ifp) return NULL; @@ -131,16 +120,18 @@ pim_jp_agg_get_interface_upstream_switch_list(struct pim_rpf *rpf) if (!pim_ifp) return NULL; + rpf_addr = pim_addr_from_prefix(&rpf->rpf_addr); + for (ALL_LIST_ELEMENTS(pim_ifp->upstream_switch_list, node, nnode, pius)) { - if (pius->address.s_addr == rpf->rpf_addr.u.prefix4.s_addr) + if (!pim_addr_cmp(pius->address, rpf_addr)) break; } if (!pius) { pius = XCALLOC(MTYPE_PIM_JP_AGG_GROUP, sizeof(struct pim_iface_upstream_switch)); - pius->address.s_addr = rpf->rpf_addr.u.prefix4.s_addr; + pius->address = rpf_addr; pius->us = list_new(); listnode_add_sort(pim_ifp->upstream_switch_list, pius); } @@ -156,7 +147,7 @@ void pim_jp_agg_remove_group(struct list *group, struct pim_upstream *up, struct pim_jp_sources *js = NULL; for (ALL_LIST_ELEMENTS(group, node, nnode, jag)) { - if (jag->group.s_addr == up->sg.grp.s_addr) + if (!pim_addr_cmp(jag->group, up->sg.grp)) break; } @@ -169,17 +160,10 @@ void pim_jp_agg_remove_group(struct list *group, struct pim_upstream *up, } if (nbr) { - if (PIM_DEBUG_TRACE) { - char src_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("", nbr->source_addr, src_str, - sizeof(src_str)); - zlog_debug( - "up %s remove from nbr %s/%s jp-agg-list", - up->sg_str, - nbr->interface->name, - src_str); - } + if (PIM_DEBUG_TRACE) + zlog_debug("up %s remove from nbr %s/%pPAs jp-agg-list", + up->sg_str, nbr->interface->name, + &nbr->source_addr); } if (js) { @@ -202,7 +186,7 @@ int pim_jp_agg_is_in_list(struct list *group, struct pim_upstream *up) struct pim_jp_sources *js = NULL; for (ALL_LIST_ELEMENTS(group, node, nnode, jag)) { - if (jag->group.s_addr == up->sg.grp.s_addr) + if (!pim_addr_cmp(jag->group, up->sg.grp)) break; } @@ -276,14 +260,14 @@ void pim_jp_agg_add_group(struct list *group, struct pim_upstream *up, struct pim_jp_sources *js = NULL; for (ALL_LIST_ELEMENTS(group, node, nnode, jag)) { - if (jag->group.s_addr == up->sg.grp.s_addr) + if (!pim_addr_cmp(jag->group, up->sg.grp)) break; } if (!jag) { jag = XCALLOC(MTYPE_PIM_JP_AGG_GROUP, sizeof(struct pim_jp_agg_group)); - jag->group.s_addr = up->sg.grp.s_addr; + jag->group = up->sg.grp; jag->sources = list_new(); jag->sources->cmp = pim_jp_agg_src_cmp; jag->sources->del = (void (*)(void *))pim_jp_agg_src_free; @@ -296,17 +280,11 @@ void pim_jp_agg_add_group(struct list *group, struct pim_upstream *up, } if (nbr) { - if (PIM_DEBUG_TRACE) { - char src_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("", nbr->source_addr, src_str, - sizeof(src_str)); - zlog_debug( - "up %s add to nbr %s/%s jp-agg-list", - up->sg_str, - up->rpf.source_nexthop.interface->name, - src_str); - } + if (PIM_DEBUG_TRACE) + zlog_debug("up %s add to nbr %s/%pPAs jp-agg-list", + up->sg_str, + up->rpf.source_nexthop.interface->name, + &nbr->source_addr); } if (!js) { @@ -378,7 +356,7 @@ void pim_jp_agg_single_upstream_send(struct pim_rpf *rpf, listnode_add(&groups, &jag); listnode_add(jag.sources, &js); - jag.group.s_addr = up->sg.grp.s_addr; + jag.group = up->sg.grp; js.up = up; js.is_join = is_join; diff --git a/pimd/pim_macro.c b/pimd/pim_macro.c index 81ef6962d..0896c52a7 100644 --- a/pimd/pim_macro.c +++ b/pimd/pim_macro.c @@ -128,11 +128,11 @@ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch) return 0; /* false */ } - if (PIM_INADDR_IS_ANY(ch->ifassert_winner)) + if (pim_addr_is_any(ch->ifassert_winner)) return 0; /* false */ /* AssertWinner(S,G,I) == me ? */ - if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) + if (!pim_addr_cmp(ch->ifassert_winner, pim_ifp->primary_address)) return 0; /* false */ spt_assert_metric = pim_macro_spt_assert_metric( @@ -170,7 +170,7 @@ int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch) return 0; /* false */ /* OR AssertWinner(S,G,I) == me ? */ - if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) + if (!pim_addr_cmp(ch->ifassert_winner, pim_ifp->primary_address)) return 1; /* true */ /* @@ -412,8 +412,8 @@ int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch) return 1; /* true */ /* AssertWinner(S,G,I) == me ? */ - if (ch->ifassert_winner.s_addr - == pim_ifp->primary_address.s_addr) + if (!pim_addr_cmp(ch->ifassert_winner, + pim_ifp->primary_address)) return 1; /* true */ } diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c index 1f38b1c93..68f77ad6d 100644 --- a/pimd/pim_mlag.c +++ b/pimd/pim_mlag.c @@ -174,8 +174,8 @@ bool pim_mlag_up_df_role_update(struct pim_instance *pim, /* If DF role changed on a (*,G) termination mroute update the * associated DF role on the inherited (S,G) entries */ - if ((up->sg.src.s_addr == INADDR_ANY) && - PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags)) + if (pim_addr_is_any(up->sg.src) && + PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags)) pim_vxlan_inherit_mlag_flags(pim, up, true /* inherit */); return true; @@ -255,17 +255,14 @@ static void pim_mlag_up_peer_add(struct mlag_mroute_add *msg) int flags = 0; pim_sgaddr sg; struct vrf *vrf; - char sg_str[PIM_SG_LEN]; memset(&sg, 0, sizeof(sg)); sg.src.s_addr = htonl(msg->source_ip); sg.grp.s_addr = htonl(msg->group_ip); - if (PIM_DEBUG_MLAG) - pim_str_sg_set(&sg, sg_str); if (PIM_DEBUG_MLAG) - zlog_debug("peer MLAG mroute add %s:%s cost %d", - msg->vrf_name, sg_str, msg->cost_to_rp); + zlog_debug("peer MLAG mroute add %s:%pSG cost %d", + msg->vrf_name, &sg, msg->cost_to_rp); /* XXX - this is not correct. we MUST cache updates to avoid losing * an entry because of race conditions with the peer switch. @@ -273,8 +270,9 @@ static void pim_mlag_up_peer_add(struct mlag_mroute_add *msg) vrf = vrf_lookup_by_name(msg->vrf_name); if (!vrf) { if (PIM_DEBUG_MLAG) - zlog_debug("peer MLAG mroute add failed %s:%s; no vrf", - msg->vrf_name, sg_str); + zlog_debug( + "peer MLAG mroute add failed %s:%pSG; no vrf", + msg->vrf_name, &sg); return; } pim = vrf->info; @@ -294,8 +292,9 @@ static void pim_mlag_up_peer_add(struct mlag_mroute_add *msg) if (!up) { if (PIM_DEBUG_MLAG) - zlog_debug("peer MLAG mroute add failed %s:%s", - vrf->name, sg_str); + zlog_debug( + "peer MLAG mroute add failed %s:%pSG", + vrf->name, &sg); return; } } @@ -329,23 +328,20 @@ static void pim_mlag_up_peer_del(struct mlag_mroute_del *msg) struct pim_instance *pim; pim_sgaddr sg; struct vrf *vrf; - char sg_str[PIM_SG_LEN]; memset(&sg, 0, sizeof(sg)); sg.src.s_addr = htonl(msg->source_ip); sg.grp.s_addr = htonl(msg->group_ip); - if (PIM_DEBUG_MLAG) - pim_str_sg_set(&sg, sg_str); if (PIM_DEBUG_MLAG) - zlog_debug("peer MLAG mroute del %s:%s", msg->vrf_name, - sg_str); + zlog_debug("peer MLAG mroute del %s:%pSG", msg->vrf_name, &sg); vrf = vrf_lookup_by_name(msg->vrf_name); if (!vrf) { if (PIM_DEBUG_MLAG) - zlog_debug("peer MLAG mroute del skipped %s:%s; no vrf", - msg->vrf_name, sg_str); + zlog_debug( + "peer MLAG mroute del skipped %s:%pSG; no vrf", + msg->vrf_name, &sg); return; } pim = vrf->info; @@ -353,8 +349,9 @@ static void pim_mlag_up_peer_del(struct mlag_mroute_del *msg) up = pim_upstream_find(pim, &sg); if (!up) { if (PIM_DEBUG_MLAG) - zlog_debug("peer MLAG mroute del skipped %s:%s; no up", - vrf->name, sg_str); + zlog_debug( + "peer MLAG mroute del skipped %s:%pSG; no up", + vrf->name, &sg); return; } @@ -933,12 +930,12 @@ int pim_zebra_mlag_process_down(ZAPI_CALLBACK_ARGS) return 0; } -static int pim_mlag_register_handler(struct thread *thread) +static void pim_mlag_register_handler(struct thread *thread) { uint32_t bit_mask = 0; if (!zclient) - return -1; + return; SET_FLAG(bit_mask, (1 << MLAG_STATUS_UPDATE)); SET_FLAG(bit_mask, (1 << MLAG_MROUTE_ADD)); @@ -955,7 +952,6 @@ static int pim_mlag_register_handler(struct thread *thread) __func__, bit_mask); zclient_send_mlag_register(zclient, bit_mask); - return 0; } void pim_mlag_register(void) @@ -969,17 +965,16 @@ void pim_mlag_register(void) NULL); } -static int pim_mlag_deregister_handler(struct thread *thread) +static void pim_mlag_deregister_handler(struct thread *thread) { if (!zclient) - return -1; + return; if (PIM_DEBUG_MLAG) zlog_debug("%s: Posting Client De-Register to MLAG from PIM", __func__); router->connected_to_mlag = false; zclient_send_mlag_deregister(zclient); - return 0; } void pim_mlag_deregister(void) diff --git a/pimd/pim_mlag.h b/pimd/pim_mlag.h index 996e4d473..0555c7d3f 100644 --- a/pimd/pim_mlag.h +++ b/pimd/pim_mlag.h @@ -28,6 +28,7 @@ #include "mlag.h" #include "pim_iface.h" +#if PIM_IPV == 4 extern void pim_mlag_init(void); extern void pim_mlag_terminate(void); extern void pim_instance_mlag_init(struct pim_instance *pim); @@ -52,4 +53,49 @@ extern void pim_mlag_up_local_del(struct pim_instance *pim, extern bool pim_mlag_up_df_role_update(struct pim_instance *pim, struct pim_upstream *up, bool is_df, const char *reason); +#else /* PIM_IPV == 4 */ +static inline void pim_mlag_terminate(void) +{ +} + +static inline void pim_instance_mlag_init(struct pim_instance *pim) +{ +} + +static inline void pim_instance_mlag_terminate(struct pim_instance *pim) +{ +} + +static inline void pim_if_configure_mlag_dualactive( + struct pim_interface *pim_ifp) +{ +} + +static inline void pim_if_unconfigure_mlag_dualactive( + struct pim_interface *pim_ifp) +{ +} + +static inline void pim_mlag_register(void) +{ +} + +static inline void pim_mlag_up_local_add(struct pim_instance *pim, + struct pim_upstream *upstream) +{ +} + +static inline void pim_mlag_up_local_del(struct pim_instance *pim, + struct pim_upstream *upstream) +{ +} + +static inline bool pim_mlag_up_df_role_update(struct pim_instance *pim, + struct pim_upstream *up, + bool is_df, const char *reason) +{ + return false; +} +#endif + #endif diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index a01256dfb..f381a764c 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -145,6 +145,7 @@ static int pim_mroute_set(struct pim_instance *pim, int enable) return 0; } +#if PIM_IPV == 4 static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = { "", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"}; @@ -162,7 +163,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, * the Interface type is SSM we don't need to * do anything here */ - if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) { + if (!rpg || pim_rpf_addr_is_inaddr_any(rpg)) { if (PIM_DEBUG_MROUTE_DETAIL) zlog_debug( "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP", @@ -189,9 +190,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, if (!(PIM_I_am_DR(pim_ifp))) { if (PIM_DEBUG_MROUTE_DETAIL) - zlog_debug( - "%s: Interface is not the DR blackholing incoming traffic for %s", - __func__, pim_str_sg_dump(&sg)); + zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %pSG", + __func__, &sg); /* * We are not the DR, but we are still receiving packets @@ -228,7 +228,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, up->channel_oil->cc.pktcnt++; // resolve mfcc_parent prior to mroute_add in channel_add_oif if (up->rpf.source_nexthop.interface && - up->channel_oil->oil.mfcc_parent >= MAXVIFS) { + *oil_parent(up->channel_oil) >= MAXVIFS) { pim_upstream_mroute_iif_update(up->channel_oil, __func__); } pim_register_join(up); @@ -258,7 +258,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, up = pim_upstream_find(pim_ifp->pim, &sg); if (!up) { pim_sgaddr star = sg; - star.src.s_addr = INADDR_ANY; + star.src = PIMADDR_ANY; up = pim_upstream_find(pim_ifp->pim, &star); @@ -268,9 +268,8 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, __func__, NULL); if (!up) { if (PIM_DEBUG_MROUTE) - zlog_debug( - "%s: Unable to create upstream information for %s", - __func__, pim_str_sg_dump(&sg)); + zlog_debug("%s: Unable to create upstream information for %pSG", + __func__, &sg); return 0; } pim_upstream_keep_alive_timer_start( @@ -284,9 +283,8 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, return 0; } if (PIM_DEBUG_MROUTE_DETAIL) { - zlog_debug( - "%s: Unable to find upstream channel WHOLEPKT%s", - __func__, pim_str_sg_dump(&sg)); + zlog_debug("%s: Unable to find upstream channel WHOLEPKT%pSG", + __func__, &sg); } return 0; } @@ -302,8 +300,8 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL; - if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp) - || (!(PIM_I_am_DR(pim_ifp)))) { + if ((pim_rpf_addr_is_inaddr_any(rpg)) || (!pim_ifp) || + (!(PIM_I_am_DR(pim_ifp)))) { if (PIM_DEBUG_MROUTE) { zlog_debug("%s: Failed Check send packet", __func__); } @@ -316,9 +314,8 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, if (!up->t_rs_timer) { if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) { if (PIM_DEBUG_PIM_REG) - zlog_debug( - "%s register forward skipped as group is SSM", - pim_str_sg_dump(&sg)); + zlog_debug("%pSG register forward skipped as group is SSM", + &sg); return 0; } @@ -361,18 +358,16 @@ static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, if (!ifp) { if (PIM_DEBUG_MROUTE) - zlog_debug( - "%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d", - __func__, pim_str_sg_dump(&sg), msg->im_vif); + zlog_debug("%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d", + __func__, &sg, msg->im_vif); return -1; } pim_ifp = ifp->info; if (!pim_ifp) { if (PIM_DEBUG_MROUTE) - zlog_debug( - "%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s", - __func__, pim_str_sg_dump(&sg), ifp->name); + zlog_debug("%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s", + __func__, &sg, ifp->name); return -2; } @@ -380,18 +375,16 @@ static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, if (!ch) { pim_sgaddr star_g = sg; if (PIM_DEBUG_MROUTE) - zlog_debug( - "%s: WRONGVIF (S,G)=%s could not find channel on interface %s", - __func__, pim_str_sg_dump(&sg), ifp->name); + zlog_debug("%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s", + __func__, &sg, ifp->name); - star_g.src.s_addr = INADDR_ANY; + star_g.src = PIMADDR_ANY; ch = pim_ifchannel_find(ifp, &star_g); if (!ch) { if (PIM_DEBUG_MROUTE) - zlog_debug( - "%s: WRONGVIF (*,G)=%s could not find channel on interface %s", - __func__, pim_str_sg_dump(&star_g), - ifp->name); + zlog_debug("%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s", + __func__, &star_g, + ifp->name); return -3; } } @@ -467,7 +460,7 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, } star_g = sg; - star_g.src.s_addr = INADDR_ANY; + star_g.src = PIMADDR_ANY; pim = pim_ifp->pim; /* @@ -558,9 +551,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, NULL); if (!up) { if (PIM_DEBUG_MROUTE) - zlog_debug( - "%s: WRONGVIF%s unable to create upstream on interface", - pim_str_sg_dump(&sg), ifp->name); + zlog_debug("%pSG: WRONGVIF%s unable to create upstream on interface", + &sg, ifp->name); return -2; } PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); @@ -589,12 +581,8 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf, int buf_size, ifindex_t ifindex) { struct interface *ifp; - struct pim_interface *pim_ifp; const struct ip *ip_hdr; const struct igmpmsg *msg; - struct in_addr ifaddr; - struct gm_sock *igmp; - const struct prefix *connected_src; if (buf_size < (int)sizeof(struct ip)) return 0; @@ -602,6 +590,11 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf, ip_hdr = (const struct ip *)buf; if (ip_hdr->ip_p == IPPROTO_IGMP) { +#if PIM_IPV == 4 + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct gm_sock *igmp; + const struct prefix *connected_src; /* We have the IP packet but we do not know which interface this * packet was @@ -641,6 +634,7 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf, zlog_debug("No IGMP socket on interface: %s with connected source: %pFX", ifp->name, connected_src); } +#endif } else if (ip_hdr->ip_p) { if (PIM_DEBUG_MROUTE_DETAIL) { zlog_debug( @@ -685,13 +679,20 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf, return 0; } +#else /* PIM_IPV != 4 */ -static int mroute_read(struct thread *t) +static int pim_mroute_msg(struct pim_instance *pim, const char *buf, + int buf_size, ifindex_t ifindex) +{ + return 0; +} +#endif /* PIM_IPV != 4 */ + +static void mroute_read(struct thread *t) { struct pim_instance *pim; static long long count; char buf[10000]; - int result = 0; int cont = 1; int rd; ifindex_t ifindex; @@ -714,7 +715,7 @@ static int mroute_read(struct thread *t) goto done; } - result = pim_mroute_msg(pim, buf, rd, ifindex); + pim_mroute_msg(pim, buf, rd, ifindex); count++; if (count % router->packet_process == 0) @@ -723,8 +724,6 @@ static int mroute_read(struct thread *t) /* Keep reading */ done: mroute_read_on(pim); - - return result; } static void mroute_read_on(struct pim_instance *pim) @@ -809,7 +808,7 @@ int pim_mroute_socket_disable(struct pim_instance *pim) would be used for multicast forwarding, a corresponding multicast interface must be added to the kernel. */ -int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, +int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr, unsigned char flags) { struct pim_interface *pim_ifp = ifp->info; @@ -848,15 +847,10 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF, (void *)&vc, sizeof(vc)); if (err) { - char ifaddr_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("", ifaddr, ifaddr_str, - sizeof(ifaddr_str)); - zlog_warn( - "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s", + "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s", __func__, pim_ifp->pim->mroute_socket, ifp->ifindex, - ifaddr_str, flags, errno, safe_strerror(errno)); + &ifaddr, flags, errno, safe_strerror(errno)); return -2; } @@ -930,26 +924,26 @@ bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil, #endif } -static inline void pim_mroute_copy(struct mfcctl *oil, - struct channel_oil *c_oil) +static inline void pim_mroute_copy(struct channel_oil *out, + struct channel_oil *in) { int i; - oil->mfcc_origin = c_oil->oil.mfcc_origin; - oil->mfcc_mcastgrp = c_oil->oil.mfcc_mcastgrp; - oil->mfcc_parent = c_oil->oil.mfcc_parent; + *oil_origin(out) = *oil_origin(in); + *oil_mcastgrp(out) = *oil_mcastgrp(in); + *oil_parent(out) = *oil_parent(in); for (i = 0; i < MAXVIFS; ++i) { - if ((oil->mfcc_parent == i) && - !pim_mroute_allow_iif_in_oil(c_oil, i)) { - oil->mfcc_ttls[i] = 0; + if (*oil_parent(out) == i && + !pim_mroute_allow_iif_in_oil(in, i)) { + oil_if_set(out, i, 0); continue; } - if (c_oil->oif_flags[i] & PIM_OIF_FLAG_MUTE) - oil->mfcc_ttls[i] = 0; + if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE) + oil_if_set(out, i, 0); else - oil->mfcc_ttls[i] = c_oil->oil.mfcc_ttls[i]; + oil_if_set(out, i, oil_if_has(in, i)); } } @@ -959,7 +953,7 @@ static inline void pim_mroute_copy(struct mfcctl *oil, static int pim_mroute_add(struct channel_oil *c_oil, const char *name) { struct pim_instance *pim = c_oil->pim; - struct mfcctl tmp_oil = { {0} }; + struct channel_oil tmp_oil[1] = { }; int err; pim->mroute_add_last = pim_time_monotonic_sec(); @@ -968,14 +962,14 @@ static int pim_mroute_add(struct channel_oil *c_oil, const char *name) /* Copy the oil to a temporary structure to fixup (without need to * later restore) before sending the mroute add to the dataplane */ - pim_mroute_copy(&tmp_oil, c_oil); + pim_mroute_copy(tmp_oil, c_oil); /* The linux kernel *expects* the incoming * vif to be part of the outgoing list * in the case of a (*,G). */ - if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) { - tmp_oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1; + if (pim_addr_is_any(*oil_origin(c_oil))) { + oil_if_set(tmp_oil, *oil_parent(c_oil), 1); } /* @@ -985,19 +979,19 @@ static int pim_mroute_add(struct channel_oil *c_oil, const char *name) * the packets to be forwarded. Then set it * to the correct IIF afterwords. */ - if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY - && c_oil->oil.mfcc_parent != 0) { - tmp_oil.mfcc_parent = 0; + if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil)) + && *oil_parent(c_oil) != 0) { + *oil_parent(tmp_oil) = 0; } err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC, - &tmp_oil, sizeof(tmp_oil)); + &tmp_oil->oil, sizeof(tmp_oil->oil)); if (!err && !c_oil->installed - && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY - && c_oil->oil.mfcc_parent != 0) { - tmp_oil.mfcc_parent = c_oil->oil.mfcc_parent; + && !pim_addr_is_any(*oil_origin(c_oil)) + && *oil_parent(c_oil) != 0) { + *oil_parent(tmp_oil) = *oil_parent(c_oil); err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC, - &tmp_oil, sizeof(tmp_oil)); + &tmp_oil->oil, sizeof(tmp_oil->oil)); } if (err) { @@ -1052,7 +1046,7 @@ static int pim_upstream_mroute_update(struct channel_oil *c_oil, { char buf[1000]; - if (c_oil->oil.mfcc_parent >= MAXVIFS) { + if (*oil_parent(c_oil) >= MAXVIFS) { /* the c_oil cannot be installed as a mroute yet */ if (PIM_DEBUG_MROUTE) zlog_debug( @@ -1099,13 +1093,13 @@ int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name) iif = pim_upstream_get_mroute_iif(c_oil, name); - if (c_oil->oil.mfcc_parent != iif) { - c_oil->oil.mfcc_parent = iif; - if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY && + if (*oil_parent(c_oil) != iif) { + *oil_parent(c_oil) = iif; + if (pim_addr_is_any(*oil_origin(c_oil)) && c_oil->up) pim_upstream_all_sources_iif_update(c_oil->up); } else { - c_oil->oil.mfcc_parent = iif; + *oil_parent(c_oil) = iif; } return pim_upstream_mroute_update(c_oil, name); @@ -1120,13 +1114,13 @@ int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name) char buf[1000]; iif = pim_upstream_get_mroute_iif(c_oil, name); - if (c_oil->oil.mfcc_parent == iif) { + if (*oil_parent(c_oil) == iif) { /* no change */ return 0; } - c_oil->oil.mfcc_parent = iif; + *oil_parent(c_oil) = iif; - if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY && + if (pim_addr_is_any(*oil_origin(c_oil)) && c_oil->up) pim_upstream_all_sources_iif_update(c_oil->up); @@ -1149,10 +1143,10 @@ void pim_static_mroute_iif_update(struct channel_oil *c_oil, int input_vif_index, const char *name) { - if (c_oil->oil.mfcc_parent == input_vif_index) + if (*oil_parent(c_oil) == input_vif_index) return; - c_oil->oil.mfcc_parent = input_vif_index; + *oil_parent(c_oil) = input_vif_index; if (input_vif_index == MAXVIFS) pim_mroute_del(c_oil, name); else @@ -1172,7 +1166,7 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name) char buf[1000]; zlog_debug( "%s %s: vifi %d for route is %s not installed, do not need to send del req. ", - __FILE__, __func__, c_oil->oil.mfcc_parent, + __FILE__, __func__, *oil_parent(c_oil), pim_channel_oil_dump(c_oil, buf, sizeof(buf))); } return -2; @@ -1205,7 +1199,6 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name) void pim_mroute_update_counters(struct channel_oil *c_oil) { struct pim_instance *pim = c_oil->pim; - struct sioc_sg_req sgreq; c_oil->cc.oldpktcnt = c_oil->cc.pktcnt; c_oil->cc.oldbytecnt = c_oil->cc.bytecnt; @@ -1216,28 +1209,30 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) if (PIM_DEBUG_MROUTE) { pim_sgaddr sg; - sg.src = c_oil->oil.mfcc_origin; - sg.grp = c_oil->oil.mfcc_mcastgrp; - zlog_debug( - "Channel%s is not installed no need to collect data from kernel", - pim_str_sg_dump(&sg)); + sg.src = *oil_origin(c_oil); + sg.grp = *oil_mcastgrp(c_oil); + zlog_debug("Channel%pSG is not installed no need to collect data from kernel", + &sg); } return; } +#if PIM_IPV == 4 + struct sioc_sg_req sgreq; + memset(&sgreq, 0, sizeof(sgreq)); - sgreq.src = c_oil->oil.mfcc_origin; - sgreq.grp = c_oil->oil.mfcc_mcastgrp; + sgreq.src = *oil_origin(c_oil); + sgreq.grp = *oil_mcastgrp(c_oil); pim_zlookup_sg_statistics(c_oil); if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) { pim_sgaddr sg; - sg.src = c_oil->oil.mfcc_origin; - sg.grp = c_oil->oil.mfcc_mcastgrp; + sg.src = *oil_origin(c_oil); + sg.grp = *oil_mcastgrp(c_oil); - zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s", - (unsigned long)SIOCGETSGCNT, pim_str_sg_dump(&sg), + zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s", + (unsigned long)SIOCGETSGCNT, &sg, errno, safe_strerror(errno)); return; } @@ -1245,6 +1240,6 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) c_oil->cc.pktcnt = sgreq.pktcnt; c_oil->cc.bytecnt = sgreq.bytecnt; c_oil->cc.wrong_if = sgreq.wrong_if; - +#endif return; } diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h index 4cd6b9f0a..14b0a8cca 100644 --- a/pimd/pim_mroute.h +++ b/pimd/pim_mroute.h @@ -37,6 +37,7 @@ #define PIM_MROUTE_MIN_TTL (1) +#if PIM_IPV == 4 #if defined(HAVE_LINUX_MROUTE_H) #include #else @@ -157,6 +158,19 @@ struct igmpmsg { struct in_addr im_src, im_dst; }; #endif + +#endif /* HAVE_LINUX_MROUTE_H */ + +typedef struct mfcctl pim_mfcctl; + +#else /* PIM_IPV != 4 */ +#if defined(HAVE_LINUX_MROUTE6_H) +#include +#endif + +typedef struct mf6cctl pim_mfcctl; + +#define MAXVIFS IF_SETSIZE #endif #ifndef IGMPMSG_WRVIFWHOLE @@ -172,7 +186,7 @@ struct channel_oil; int pim_mroute_socket_enable(struct pim_instance *pim); int pim_mroute_socket_disable(struct pim_instance *pim); -int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, +int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr, unsigned char flags); int pim_mroute_del_vif(struct interface *ifp); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 673347b4f..7c1c80f71 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -66,7 +66,7 @@ static void pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa *sa, } /* RFC-3618:Sec-5.1 - global active source advertisement timer */ -static int pim_msdp_sa_adv_timer_cb(struct thread *t) +static void pim_msdp_sa_adv_timer_cb(struct thread *t) { struct pim_instance *pim = THREAD_ARG(t); @@ -76,8 +76,8 @@ static int pim_msdp_sa_adv_timer_cb(struct thread *t) pim_msdp_sa_adv_timer_setup(pim, true /* start */); pim_msdp_pkt_sa_tx(pim); - return 0; } + static void pim_msdp_sa_adv_timer_setup(struct pim_instance *pim, bool start) { THREAD_OFF(pim->msdp.sa_adv_timer); @@ -89,7 +89,7 @@ static void pim_msdp_sa_adv_timer_setup(struct pim_instance *pim, bool start) } /* RFC-3618:Sec-5.3 - SA cache state timer */ -static int pim_msdp_sa_state_timer_cb(struct thread *t) +static void pim_msdp_sa_state_timer_cb(struct thread *t) { struct pim_msdp_sa *sa; @@ -100,8 +100,8 @@ static int pim_msdp_sa_state_timer_cb(struct thread *t) } pim_msdp_sa_deref(sa, PIM_MSDP_SAF_PEER); - return 0; } + static void pim_msdp_sa_state_timer_setup(struct pim_msdp_sa *sa, bool start) { THREAD_OFF(sa->sa_state_timer); @@ -244,7 +244,7 @@ static struct pim_msdp_sa *pim_msdp_sa_new(struct pim_instance *pim, sa->pim = pim; sa->sg = *sg; - pim_str_sg_set(sg, sa->sg_str); + snprintfrr(sa->sg_str, sizeof(sa->sg_str), "%pSG", sg); sa->rp = rp; sa->uptime = pim_time_monotonic_sec(); @@ -314,7 +314,7 @@ static void pim_msdp_sa_peer_ip_set(struct pim_msdp_sa *sa, } /* any time the peer ip changes also update the rp address */ - if (PIM_INADDR_ISNOT_ANY(sa->peer)) { + if (sa->peer.s_addr != INADDR_ANY) { old_mp = pim_msdp_peer_find(sa->pim, sa->peer); if (old_mp && old_mp->sa_cnt) { --old_mp->sa_cnt; @@ -624,15 +624,14 @@ void pim_msdp_up_join_state_changed(struct pim_instance *pim, } /* If this is not really an XG entry just move on */ - if ((xg_up->sg.src.s_addr != INADDR_ANY) - || (xg_up->sg.grp.s_addr == INADDR_ANY)) { + if (!pim_addr_is_any(xg_up->sg.src) || pim_addr_is_any(xg_up->sg.grp)) { return; } /* XXX: Need to maintain SAs per-group to avoid all this unnecessary * walking */ for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { - if (sa->sg.grp.s_addr != xg_up->sg.grp.s_addr) { + if (pim_addr_cmp(sa->sg.grp, xg_up->sg.grp)) { continue; } pim_msdp_sa_upstream_update(sa, xg_up, "up-jp-change"); @@ -645,18 +644,18 @@ static void pim_msdp_up_xg_del(struct pim_instance *pim, pim_sgaddr *sg) struct pim_msdp_sa *sa; if (PIM_DEBUG_MSDP_INTERNAL) { - zlog_debug("MSDP %s del", pim_str_sg_dump(sg)); + zlog_debug("MSDP %pSG del", sg); } /* If this is not really an XG entry just move on */ - if ((sg->src.s_addr != INADDR_ANY) || (sg->grp.s_addr == INADDR_ANY)) { + if (!pim_addr_is_any(sg->src) || pim_addr_is_any(sg->grp)) { return; } /* XXX: Need to maintain SAs per-group to avoid all this unnecessary * walking */ for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { - if (sa->sg.grp.s_addr != sg->grp.s_addr) { + if (pim_addr_cmp(sa->sg.grp, sg->grp)) { continue; } pim_msdp_sa_upstream_update(sa, NULL /* xg */, "up-jp-change"); @@ -666,9 +665,9 @@ static void pim_msdp_up_xg_del(struct pim_instance *pim, pim_sgaddr *sg) void pim_msdp_up_del(struct pim_instance *pim, pim_sgaddr *sg) { if (PIM_DEBUG_MSDP_INTERNAL) { - zlog_debug("MSDP up %s del", pim_str_sg_dump(sg)); + zlog_debug("MSDP up %pSG del", sg); } - if (sg->src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(sg->src)) { pim_msdp_up_xg_del(pim, sg); } else { pim_msdp_sa_local_del_on_up_del(pim, sg); @@ -680,7 +679,7 @@ static unsigned int pim_msdp_sa_hash_key_make(const void *p) { const struct pim_msdp_sa *sa = p; - return (jhash_2words(sa->sg.src.s_addr, sa->sg.grp.s_addr, 0)); + return pim_sgaddr_hash(sa->sg, 0); } static bool pim_msdp_sa_hash_eq(const void *p1, const void *p2) @@ -688,8 +687,7 @@ static bool pim_msdp_sa_hash_eq(const void *p1, const void *p2) const struct pim_msdp_sa *sa1 = p1; const struct pim_msdp_sa *sa2 = p2; - return ((sa1->sg.src.s_addr == sa2->sg.src.s_addr) - && (sa1->sg.grp.s_addr == sa2->sg.grp.s_addr)); + return !pim_sgaddr_cmp(sa1->sg, sa2->sg); } static int pim_msdp_sa_comp(const void *p1, const void *p2) @@ -697,19 +695,7 @@ static int pim_msdp_sa_comp(const void *p1, const void *p2) const struct pim_msdp_sa *sa1 = p1; const struct pim_msdp_sa *sa2 = p2; - if (ntohl(sa1->sg.grp.s_addr) < ntohl(sa2->sg.grp.s_addr)) - return -1; - - if (ntohl(sa1->sg.grp.s_addr) > ntohl(sa2->sg.grp.s_addr)) - return 1; - - if (ntohl(sa1->sg.src.s_addr) < ntohl(sa2->sg.src.s_addr)) - return -1; - - if (ntohl(sa1->sg.src.s_addr) > ntohl(sa2->sg.src.s_addr)) - return 1; - - return 0; + return pim_sgaddr_cmp(sa1->sg, sa2->sg); } /* RFC-3618:Sec-10.1.3 - Peer-RPF forwarding */ @@ -887,7 +873,7 @@ static void pim_msdp_peer_timer_expiry_log(struct pim_msdp_peer *mp, } /* RFC-3618:Sec-5.4 - peer hold timer */ -static int pim_msdp_peer_hold_timer_cb(struct thread *t) +static void pim_msdp_peer_hold_timer_cb(struct thread *t) { struct pim_msdp_peer *mp; @@ -898,14 +884,13 @@ static int pim_msdp_peer_hold_timer_cb(struct thread *t) } if (mp->state != PIM_MSDP_ESTABLISHED) { - return 0; + return; } if (PIM_DEBUG_MSDP_EVENTS) { pim_msdp_peer_state_chg_log(mp); } pim_msdp_peer_reset_tcp_conn(mp, "ht-expired"); - return 0; } static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer *mp, bool start) @@ -920,7 +905,7 @@ static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer *mp, bool start) /* RFC-3618:Sec-5.5 - peer keepalive timer */ -static int pim_msdp_peer_ka_timer_cb(struct thread *t) +static void pim_msdp_peer_ka_timer_cb(struct thread *t) { struct pim_msdp_peer *mp; @@ -932,8 +917,8 @@ static int pim_msdp_peer_ka_timer_cb(struct thread *t) pim_msdp_pkt_ka_tx(mp); pim_msdp_peer_ka_timer_setup(mp, true /* start */); - return 0; } + static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start) { THREAD_OFF(mp->ka_timer); @@ -981,7 +966,7 @@ static void pim_msdp_peer_active_connect(struct pim_msdp_peer *mp) } /* RFC-3618:Sec-5.6 - connection retry on active peer */ -static int pim_msdp_peer_cr_timer_cb(struct thread *t) +static void pim_msdp_peer_cr_timer_cb(struct thread *t) { struct pim_msdp_peer *mp; @@ -992,12 +977,12 @@ static int pim_msdp_peer_cr_timer_cb(struct thread *t) } if (mp->state != PIM_MSDP_CONNECTING || PIM_MSDP_PEER_IS_LISTENER(mp)) { - return 0; + return; } pim_msdp_peer_active_connect(mp); - return 0; } + static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer *mp, bool start) { THREAD_OFF(mp->cr_timer); diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index d2501adc4..4e1114aff 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -240,7 +240,7 @@ void pim_msdp_peer_established(struct pim_msdp_peer *mp); void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp); void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state); void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str); -int pim_msdp_write(struct thread *thread); +void pim_msdp_write(struct thread *thread); int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, const char *spaces); bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index 64fdbaa89..4adaca4e7 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -77,7 +77,7 @@ static void pim_msdp_pkt_sa_dump_one(struct stream *s) sg.grp.s_addr = stream_get_ipv4(s); sg.src.s_addr = stream_get_ipv4(s); - zlog_debug(" sg %s", pim_str_sg_dump(&sg)); + zlog_debug(" sg %pSG", &sg); } static void pim_msdp_pkt_sa_dump(struct stream *s) @@ -182,7 +182,7 @@ static void pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp) } } -int pim_msdp_write(struct thread *thread) +void pim_msdp_write(struct thread *thread) { struct pim_msdp_peer *mp; struct stream *s; @@ -199,23 +199,21 @@ int pim_msdp_write(struct thread *thread) zlog_debug("MSDP peer %s pim_msdp_write", mp->key_str); } if (mp->fd < 0) { - return -1; + return; } /* check if TCP connection is established */ if (mp->state != PIM_MSDP_ESTABLISHED) { pim_msdp_connect_check(mp); - return 0; + return; } s = stream_fifo_head(mp->obuf); if (!s) { pim_msdp_write_proceed_actions(mp); - return 0; + return; } - sockopt_cork(mp->fd, 1); - /* Nonblocking write until TCP output buffer is full */ do { int writenum; @@ -237,7 +235,7 @@ int pim_msdp_write(struct thread *thread) } pim_msdp_peer_reset_tcp_conn(mp, "pkt-tx-failed"); - return 0; + return; } if (num != writenum) { @@ -280,14 +278,10 @@ int pim_msdp_write(struct thread *thread) } while ((s = stream_fifo_head(mp->obuf)) != NULL); pim_msdp_write_proceed_actions(mp); - sockopt_cork(mp->fd, 0); - if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets", mp->key_str, work_cnt); } - - return 0; } static void pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s) @@ -513,7 +507,7 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) return; } if (PIM_DEBUG_MSDP_PACKETS) { - zlog_debug(" sg %s", pim_str_sg_dump(&sg)); + zlog_debug(" sg %pSG", &sg); } pim_msdp_sa_ref(mp->pim, mp, &sg, rp); @@ -674,7 +668,7 @@ static int pim_msdp_read_packet(struct pim_msdp_peer *mp) return 0; } -int pim_msdp_read(struct thread *thread) +void pim_msdp_read(struct thread *thread) { struct pim_msdp_peer *mp; int rc; @@ -688,13 +682,13 @@ int pim_msdp_read(struct thread *thread) } if (mp->fd < 0) { - return -1; + return; } /* check if TCP connection is established */ if (mp->state != PIM_MSDP_ESTABLISHED) { pim_msdp_connect_check(mp); - return 0; + return; } PIM_MSDP_PEER_READ_ON(mp); @@ -706,32 +700,27 @@ int pim_msdp_read(struct thread *thread) if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) { /* start by reading the TLV header */ rc = pim_msdp_read_packet(mp); - if (rc < 0) { - goto pim_msdp_read_end; - } + if (rc < 0) + return; /* Find TLV type and len */ stream_getc(mp->ibuf); len = stream_getw(mp->ibuf); if (len < PIM_MSDP_HEADER_SIZE) { pim_msdp_pkt_rxed_with_fatal_error(mp); - goto pim_msdp_read_end; + return; } /* read complete TLV */ mp->packet_size = len; } rc = pim_msdp_read_packet(mp); - if (rc < 0) { - goto pim_msdp_read_end; - } + if (rc < 0) + return; pim_msdp_pkt_rx(mp); /* reset input buffers and get ready for the next packet */ mp->packet_size = 0; stream_reset(mp->ibuf); - -pim_msdp_read_end: - return 0; } diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index e2c4b0e6b..00324a291 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -64,7 +64,7 @@ #define PIM_MSDP_PKT_TYPE_STRLEN 16 void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp); -int pim_msdp_read(struct thread *thread); +void pim_msdp_read(struct thread *thread); void pim_msdp_pkt_sa_tx(struct pim_instance *pim); void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa); void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp); diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index 5fff9fca0..facb771c2 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -62,7 +62,7 @@ static void pim_msdp_update_sock_send_buffer_size(int fd) } /* passive peer socket accept */ -static int pim_msdp_sock_accept(struct thread *thread) +static void pim_msdp_sock_accept(struct thread *thread) { union sockunion su; struct pim_instance *pim = THREAD_ARG(thread); @@ -77,7 +77,7 @@ static int pim_msdp_sock_accept(struct thread *thread) if (accept_sock < 0) { flog_err(EC_LIB_DEVELOPMENT, "accept_sock is negative value %d", accept_sock); - return -1; + return; } pim->msdp.listener.thread = NULL; thread_add_read(router->master, pim_msdp_sock_accept, pim, accept_sock, @@ -88,7 +88,7 @@ static int pim_msdp_sock_accept(struct thread *thread) if (msdp_sock < 0) { flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)", safe_strerror(errno)); - return -1; + return; } /* see if have peer config for this */ @@ -100,7 +100,7 @@ static int pim_msdp_sock_accept(struct thread *thread) "msdp peer connection refused from %pSU", &su); } close(msdp_sock); - return -1; + return; } if (PIM_DEBUG_MSDP_INTERNAL) { @@ -122,7 +122,6 @@ static int pim_msdp_sock_accept(struct thread *thread) set_nonblocking(mp->fd); pim_msdp_update_sock_send_buffer_size(mp->fd); pim_msdp_peer_established(mp); - return 0; } /* global listener for the MSDP well know TCP port */ diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 65b6405c8..a0653e1a5 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -97,6 +97,68 @@ uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, struct in_addr addr, return buf + PIM_ENCODED_IPV4_SOURCE_SIZE; } +uint8_t *pim_msg_addr_encode_ipv6_source(uint8_t *buf, struct in6_addr addr, + uint8_t bits) +{ + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */ + buf[1] = '\0'; /* native encoding */ + buf[2] = bits; + buf[3] = 128; /* mask len */ + buf += 4; + + memcpy(buf, &addr, sizeof(addr)); + buf += sizeof(addr); + + return buf; +} + +uint8_t *pim_msg_addr_encode_ipv6_ucast(uint8_t *buf, struct in6_addr addr) +{ + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */ + buf[1] = '\0'; /* native encoding */ + buf += 2; + + memcpy(buf, &addr, sizeof(addr)); + buf += sizeof(addr); + + return buf; +} + +uint8_t *pim_msg_addr_encode_ipv6_group(uint8_t *buf, struct in6_addr addr) +{ + buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */ + buf[1] = '\0'; /* native encoding */ + buf[2] = '\0'; /* reserved */ + buf[3] = 128; /* mask len */ + buf += 4; + + memcpy(buf, &addr, sizeof(addr)); + buf += sizeof(addr); + + return buf; +} + +#if PIM_IPV == 4 +#define pim_msg_addr_encode(what) pim_msg_addr_encode_ipv4_##what +#else +#define pim_msg_addr_encode(what) pim_msg_addr_encode_ipv6_##what +#endif + +uint8_t *pim_msg_addr_encode_ucast(uint8_t *buf, pim_addr addr) +{ + return pim_msg_addr_encode(ucast)(buf, addr); +} + +uint8_t *pim_msg_addr_encode_group(uint8_t *buf, pim_addr addr) +{ + return pim_msg_addr_encode(group)(buf, addr); +} + +uint8_t *pim_msg_addr_encode_source(uint8_t *buf, pim_addr addr, uint8_t bits) +{ + return pim_msg_addr_encode(source)(buf, addr, bits); +} + /* * For the given 'struct pim_jp_sources' list * determine the size_t it would take up. @@ -109,13 +171,13 @@ size_t pim_msg_get_jp_group_size(struct list *sources) if (!sources) return 0; - size += sizeof(struct pim_encoded_group_ipv4); + size += sizeof(pim_encoded_group); size += 4; // Joined sources (2) + Pruned Sources (2) - size += sizeof(struct pim_encoded_source_ipv4) * sources->count; + size += sizeof(pim_encoded_source) * sources->count; js = listgetdata(listhead(sources)); - if (js && js->up->sg.src.s_addr == INADDR_ANY && js->is_join) { + if (js && pim_addr_is_any(js->up->sg.src) && js->is_join) { struct pim_upstream *child, *up; struct listnode *up_node; @@ -137,8 +199,7 @@ size_t pim_msg_get_jp_group_size(struct list *sources) if (child->rpf.source_nexthop.interface && !pim_rpf_is_same(&up->rpf, &child->rpf)) { - size += sizeof( - struct pim_encoded_source_ipv4); + size += sizeof(pim_encoded_source); PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( child->flags); if (PIM_DEBUG_PIM_PACKETS) @@ -156,8 +217,7 @@ size_t pim_msg_get_jp_group_size(struct list *sources) * but it's inherited OIL is empty. So just * prune it off. */ - size += sizeof( - struct pim_encoded_source_ipv4); + size += sizeof(pim_encoded_source); PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( child->flags); if (PIM_DEBUG_PIM_PACKETS) @@ -179,12 +239,12 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, struct listnode *node, *nnode; struct pim_jp_sources *source; struct pim_upstream *up = NULL; - struct in_addr stosend; + pim_addr stosend; uint8_t bits; uint8_t tgroups = 0; memset(grp, 0, size); - pim_msg_addr_encode_ipv4_group((uint8_t *)&grp->g, sgs->group); + pim_msg_addr_encode_group((uint8_t *)&grp->g, sgs->group); for (ALL_LIST_ELEMENTS(sgs->sources, node, nnode, source)) { /* number of joined/pruned sources */ @@ -193,12 +253,12 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, else grp->prunes++; - if (source->up->sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(source->up->sg.src)) { struct pim_instance *pim = source->up->channel_oil->pim; struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp); bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT; - stosend = rpf->rpf_addr.u.prefix4; + stosend = pim_addr_from_prefix(&rpf->rpf_addr); /* Only Send SGRpt in case of *,G Join */ if (source->is_join) up = source->up; @@ -207,8 +267,8 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, stosend = source->up->sg.src; } - pim_msg_addr_encode_ipv4_source((uint8_t *)&grp->s[tgroups], - stosend, bits); + pim_msg_addr_encode_source((uint8_t *)&grp->s[tgroups], stosend, + bits); tgroups++; } @@ -218,11 +278,11 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, for (ALL_LIST_ELEMENTS(up->sources, node, nnode, child)) { if (PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE( child->flags)) { - pim_msg_addr_encode_ipv4_source( + pim_msg_addr_encode_source( (uint8_t *)&grp->s[tgroups], child->sg.src, - PIM_ENCODE_SPARSE_BIT - | PIM_ENCODE_RPT_BIT); + PIM_ENCODE_SPARSE_BIT | + PIM_ENCODE_RPT_BIT); tgroups++; PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE( child->flags); diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index 2d69a4b03..456c356d9 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -21,6 +21,9 @@ #define PIM_MSG_H #include +#if PIM_IPV == 6 +#include +#endif #include "pim_jp_agg.h" @@ -75,6 +78,12 @@ struct pim_encoded_ipv4_unicast { struct in_addr addr; } __attribute__((packed)); +struct pim_encoded_ipv6_unicast { + uint8_t family; + uint8_t reserved; + struct in6_addr addr; +} __attribute__((packed)); + /* * Encoded Group format. RFC 4601 Sec 4.9.1 * 0 1 2 3 @@ -103,6 +112,23 @@ struct pim_encoded_group_ipv4 { struct in_addr addr; } __attribute__((packed)); +struct pim_encoded_group_ipv6 { + uint8_t family; + uint8_t ne; +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint8_t sz : 1; /* scope zone bit */ + uint8_t reserved : 6; /* Reserved */ + uint8_t bidir : 1; /* Bidir bit */ +#elif (BYTE_ORDER == BIG_ENDIAN) + uint8_t bidir : 1; /* Bidir bit */ + uint8_t reserved : 6; /* Reserved */ + uint8_t sz : 1; /* scope zone bit */ +#else +#error "Please set byte order" +#endif + uint8_t mask; + struct in6_addr addr; +} __attribute__((packed)); /* * Encoded Source format. RFC 4601 Sec 4.9.1 @@ -122,22 +148,66 @@ struct pim_encoded_source_ipv4 { struct in_addr addr; } __attribute__((packed)); +struct pim_encoded_source_ipv6 { + uint8_t family; + uint8_t ne; + uint8_t bits; + uint8_t mask; + struct in6_addr addr; +} __attribute__((packed)); + +/* clang-format off */ +#if PIM_IPV == 4 +typedef struct pim_encoded_ipv4_unicast pim_encoded_unicast; +typedef struct pim_encoded_group_ipv4 pim_encoded_group; +typedef struct pim_encoded_source_ipv4 pim_encoded_source; +#else +typedef struct pim_encoded_ipv6_unicast pim_encoded_unicast; +typedef struct pim_encoded_group_ipv6 pim_encoded_group; +typedef struct pim_encoded_source_ipv6 pim_encoded_source; +#endif +/* clang-format on */ + struct pim_jp_groups { - struct pim_encoded_group_ipv4 g; + pim_encoded_group g; uint16_t joins; uint16_t prunes; - struct pim_encoded_source_ipv4 s[1]; + pim_encoded_source s[1]; } __attribute__((packed)); struct pim_jp { struct pim_msg_header header; - struct pim_encoded_ipv4_unicast addr; + pim_encoded_unicast addr; uint8_t reserved; uint8_t num_groups; uint16_t holdtime; struct pim_jp_groups groups[1]; } __attribute__((packed)); +#if PIM_IPV == 4 +static inline pim_sgaddr pim_sgaddr_from_iphdr(const void *iphdr) +{ + const struct ip *ipv4_hdr = iphdr; + pim_sgaddr sg; + + sg.src = ipv4_hdr->ip_src; + sg.grp = ipv4_hdr->ip_dst; + + return sg; +} +#else +static inline pim_sgaddr pim_sgaddr_from_iphdr(const void *iphdr) +{ + const struct ip6_hdr *ipv6_hdr = iphdr; + pim_sgaddr sg; + + sg.src = ipv6_hdr->ip6_src; + sg.grp = ipv6_hdr->ip6_dst; + + return sg; +} +#endif + void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size, uint8_t pim_msg_type, bool no_fwd); uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr); @@ -149,6 +219,14 @@ uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr); uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, struct in_addr addr, uint8_t bits); +uint8_t *pim_msg_addr_encode_ipv6_ucast(uint8_t *buf, struct in6_addr addr); +uint8_t *pim_msg_addr_encode_ipv6_group(uint8_t *buf, struct in6_addr addr); +uint8_t *pim_msg_addr_encode_ipv6_source(uint8_t *buf, struct in6_addr addr, + uint8_t bits); + +uint8_t *pim_msg_addr_encode_ucast(uint8_t *buf, pim_addr addr); +uint8_t *pim_msg_addr_encode_group(uint8_t *buf, pim_addr addr); +uint8_t *pim_msg_addr_encode_source(uint8_t *buf, pim_addr addr, uint8_t bits); size_t pim_msg_get_jp_group_size(struct list *sources); size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 72c96d7d7..273c7e8a6 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -198,6 +198,12 @@ int lib_interface_gmp_address_family_static_group_destroy( int routing_control_plane_protocols_name_validate( struct nb_cb_create_args *args); +#if PIM_IPV == 4 +#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv4" +#else +#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv6" +#endif + #define FRR_PIM_VRF_XPATH \ "/frr-routing:routing/control-plane-protocols/" \ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 376615729..21f57e2d1 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -31,8 +31,10 @@ #include "pim_ssm.h" #include "pim_ssmpingd.h" #include "pim_vxlan.h" +#include "pim_util.h" #include "log.h" #include "lib_errors.h" +#include "pim_util.h" #if PIM_IPV == 6 #define pim6_msdp_err(funcname, argtype) \ @@ -45,9 +47,13 @@ int funcname(struct argtype *args) \ } \ MACRO_REQUIRE_SEMICOLON() +#define yang_dnode_get_pimaddr yang_dnode_get_ipv6 + #else /* PIM_IPV != 6 */ #define pim6_msdp_err(funcname, argtype) \ MACRO_REQUIRE_SEMICOLON() + +#define yang_dnode_get_pimaddr yang_dnode_get_ipv4 #endif /* PIM_IPV != 6 */ static void pim_if_membership_clear(struct interface *ifp) @@ -172,8 +178,7 @@ static int pim_cmd_interface_delete(struct interface *ifp) } static int interface_pim_use_src_cmd_worker(struct interface *ifp, - struct in_addr source_addr, - char *errmsg, size_t errmsg_len) + pim_addr source_addr, char *errmsg, size_t errmsg_len) { int result; int ret = NB_OK; @@ -252,21 +257,17 @@ static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist, return ret; } -static int pim_rp_cmd_worker(struct pim_instance *pim, - struct in_addr rp_addr, - struct prefix group, const char *plist, - char *errmsg, size_t errmsg_len) +static int pim_rp_cmd_worker(struct pim_instance *pim, pim_addr rp_addr, + struct prefix group, const char *plist, + char *errmsg, size_t errmsg_len) { - char rp_str[INET_ADDRSTRLEN]; int result; - inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)); - result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC); if (result == PIM_RP_NO_PATH) { - snprintf(errmsg, errmsg_len, - "No Path to RP address specified: %s", rp_str); + snprintfrr(errmsg, errmsg_len, + "No Path to RP address specified: %pPA", &rp_addr); return NB_ERR_INCONSISTENCY; } @@ -291,16 +292,13 @@ static int pim_rp_cmd_worker(struct pim_instance *pim, return NB_OK; } -static int pim_no_rp_cmd_worker(struct pim_instance *pim, - struct in_addr rp_addr, struct prefix group, - const char *plist, +static int pim_no_rp_cmd_worker(struct pim_instance *pim, pim_addr rp_addr, + struct prefix group, const char *plist, char *errmsg, size_t errmsg_len) { - char rp_str[INET_ADDRSTRLEN]; char group_str[PREFIX2STR_BUFFER]; int result; - inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)); prefix2str(&group, group_str, sizeof(group_str)); result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC); @@ -312,8 +310,8 @@ static int pim_no_rp_cmd_worker(struct pim_instance *pim, } if (result == PIM_RP_BAD_ADDRESS) { - snprintf(errmsg, errmsg_len, - "Bad RP address specified: %s", rp_str); + snprintfrr(errmsg, errmsg_len, "Bad RP address specified: %pPA", + &rp_addr); return NB_ERR_INCONSISTENCY; } @@ -396,15 +394,10 @@ static void igmp_sock_query_interval_reconfig(struct gm_sock *igmp) ifp = igmp->interface; pim_ifp = ifp->info; - if (PIM_DEBUG_IGMP_TRACE) { - char ifaddr_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("", igmp->ifaddr, ifaddr_str, - sizeof(ifaddr_str)); - zlog_debug("%s: Querier %s on %s reconfig query_interval=%d", - __func__, ifaddr_str, ifp->name, + if (PIM_DEBUG_IGMP_TRACE) + zlog_debug("%s: Querier %pPAs on %s reconfig query_interval=%d", + __func__, &igmp->ifaddr, ifp->name, pim_ifp->gm_default_query_interval); - } /* * igmp_startup_mode_on() will reset QQI: @@ -2015,7 +2008,7 @@ int lib_interface_pim_address_family_use_source_modify( struct nb_cb_modify_args *args) { struct interface *ifp; - struct ipaddr source_addr; + pim_addr source_addr; int result; const struct lyd_node *if_dnode; @@ -2033,10 +2026,14 @@ int lib_interface_pim_address_family_use_source_modify( break; case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - yang_dnode_get_ip(&source_addr, args->dnode, NULL); +#if PIM_IPV == 4 + yang_dnode_get_ipv4(&source_addr, args->dnode, NULL); +#else + yang_dnode_get_ipv6(&source_addr, args->dnode, NULL); +#endif result = interface_pim_use_src_cmd_worker( - ifp, source_addr.ip._v4_addr, + ifp, source_addr, args->errmsg, args->errmsg_len); if (result != PIM_SUCCESS) @@ -2052,7 +2049,6 @@ int lib_interface_pim_address_family_use_source_destroy( struct nb_cb_destroy_args *args) { struct interface *ifp; - struct in_addr source_addr = {INADDR_ANY}; int result; const struct lyd_node *if_dnode; @@ -2071,7 +2067,7 @@ int lib_interface_pim_address_family_use_source_destroy( case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - result = interface_pim_use_src_cmd_worker(ifp, source_addr, + result = interface_pim_use_src_cmd_worker(ifp, PIMADDR_ANY, args->errmsg, args->errmsg_len); @@ -2179,8 +2175,8 @@ int lib_interface_pim_address_family_mroute_destroy( struct interface *iif; struct interface *oif; const char *oifname; - struct ipaddr source_addr; - struct ipaddr group_addr; + pim_addr source_addr; + pim_addr group_addr; const struct lyd_node *if_dnode; switch (args->event) { @@ -2210,11 +2206,10 @@ int lib_interface_pim_address_family_mroute_destroy( return NB_ERR_INCONSISTENCY; } - yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr"); - yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr"); + yang_dnode_get_pimaddr(&source_addr, args->dnode, "./source-addr"); + yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr"); - if (pim_static_del(pim, iif, oif, group_addr.ip._v4_addr, - source_addr.ip._v4_addr)) { + if (pim_static_del(pim, iif, oif, group_addr, source_addr)) { snprintf(args->errmsg, args->errmsg_len, "Failed to remove static mroute"); return NB_ERR_INCONSISTENCY; @@ -2237,8 +2232,8 @@ int lib_interface_pim_address_family_mroute_oif_modify( struct interface *iif; struct interface *oif; const char *oifname; - struct ipaddr source_addr; - struct ipaddr group_addr; + pim_addr source_addr; + pim_addr group_addr; const struct lyd_node *if_dnode; switch (args->event) { @@ -2287,11 +2282,10 @@ int lib_interface_pim_address_family_mroute_oif_modify( return NB_ERR_INCONSISTENCY; } - yang_dnode_get_ip(&source_addr, args->dnode, "../source-addr"); - yang_dnode_get_ip(&group_addr, args->dnode, "../group-addr"); + yang_dnode_get_pimaddr(&source_addr, args->dnode, "../source-addr"); + yang_dnode_get_pimaddr(&group_addr, args->dnode, "../group-addr"); - if (pim_static_add(pim, iif, oif, group_addr.ip._v4_addr, - source_addr.ip._v4_addr)) { + if (pim_static_add(pim, iif, oif, group_addr, source_addr)) { snprintf(args->errmsg, args->errmsg_len, "Failed to add static mroute"); return NB_ERR_INCONSISTENCY; @@ -2340,7 +2334,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; const char *plist; int result = 0; @@ -2352,31 +2346,30 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&rp_addr, args->dnode, "./rp-address"); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "./rp-address"); if (yang_dnode_get(args->dnode, "./group-list")) { - yang_dnode_get_ipv4p(&group, args->dnode, - "./group-list"); - apply_mask_ipv4((struct prefix_ipv4 *)&group); - result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, - group, NULL, args->errmsg, - args->errmsg_len); + yang_dnode_get_prefix(&group, args->dnode, + "./group-list"); + apply_mask(&group); + result = pim_no_rp_cmd_worker(pim, rp_addr, group, NULL, + args->errmsg, + args->errmsg_len); } else if (yang_dnode_get(args->dnode, "./prefix-list")) { plist = yang_dnode_get_string(args->dnode, "./prefix-list"); - if (!str2prefix("224.0.0.0/4", &group)) { + if (!pim_get_all_mcast_group(&group)) { flog_err( EC_LIB_DEVELOPMENT, "Unable to convert 224.0.0.0/4 to prefix"); return NB_ERR_INCONSISTENCY; } - result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, - group, plist, - args->errmsg, - args->errmsg_len); + result = pim_no_rp_cmd_worker(pim, rp_addr, group, + plist, args->errmsg, + args->errmsg_len); } if (result) @@ -2396,7 +2389,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; switch (args->event) { case NB_EV_VALIDATE: @@ -2406,12 +2399,11 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); - yang_dnode_get_ipv4p(&group, args->dnode, NULL); - apply_mask_ipv4((struct prefix_ipv4 *)&group); - - return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, - NULL, args->errmsg, args->errmsg_len); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_prefix(&group, args->dnode, NULL); + apply_mask(&group); + return pim_rp_cmd_worker(pim, rp_addr, group, NULL, + args->errmsg, args->errmsg_len); } return NB_OK; @@ -2423,7 +2415,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; switch (args->event) { case NB_EV_VALIDATE: @@ -2433,13 +2425,12 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); - yang_dnode_get_ipv4p(&group, args->dnode, NULL); - apply_mask_ipv4((struct prefix_ipv4 *)&group); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_prefix(&group, args->dnode, NULL); + apply_mask(&group); - return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, - NULL, args->errmsg, - args->errmsg_len); + return pim_no_rp_cmd_worker(pim, rp_addr, group, NULL, + args->errmsg, args->errmsg_len); } return NB_OK; @@ -2454,7 +2445,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; const char *plist; switch (args->event) { @@ -2466,14 +2457,14 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; plist = yang_dnode_get_string(args->dnode, NULL); - yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); - if (!str2prefix("224.0.0.0/4", &group)) { + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + if (!pim_get_all_mcast_group(&group)) { flog_err(EC_LIB_DEVELOPMENT, "Unable to convert 224.0.0.0/4 to prefix"); return NB_ERR_INCONSISTENCY; } - return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, - plist, args->errmsg, args->errmsg_len); + return pim_rp_cmd_worker(pim, rp_addr, group, plist, + args->errmsg, args->errmsg_len); } return NB_OK; @@ -2485,7 +2476,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct vrf *vrf; struct pim_instance *pim; struct prefix group; - struct ipaddr rp_addr; + pim_addr rp_addr; const char *plist; switch (args->event) { @@ -2496,16 +2487,15 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); plist = yang_dnode_get_string(args->dnode, NULL); - if (!str2prefix("224.0.0.0/4", &group)) { + if (!pim_get_all_mcast_group(&group)) { flog_err(EC_LIB_DEVELOPMENT, "Unable to convert 224.0.0.0/4 to prefix"); return NB_ERR_INCONSISTENCY; } - return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group, - plist, args->errmsg, - args->errmsg_len); + return pim_no_rp_cmd_worker(pim, rp_addr, group, plist, + args->errmsg, args->errmsg_len); break; } @@ -2833,6 +2823,14 @@ int lib_interface_gmp_address_family_static_group_create( ifp_name); return NB_ERR_VALIDATION; } + + yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr"); + if (pim_is_group_224_0_0_0_24(group_addr.ip._v4_addr)) { + snprintf( + args->errmsg, args->errmsg_len, + "Groups within 224.0.0.0/24 are reserved and cannot be joined"); + return NB_ERR_VALIDATION; + } break; case NB_EV_PREPARE: case NB_EV_ABORT: diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 530c2e429..84b532d34 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -58,10 +58,8 @@ static void dr_election_by_addr(struct interface *ifp) } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { - if (ntohl(neigh->source_addr.s_addr) - > ntohl(pim_ifp->pim_dr_addr.s_addr)) { + if (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) > 0) pim_ifp->pim_dr_addr = neigh->source_addr; - } } } @@ -85,15 +83,14 @@ static void dr_election_by_pri(struct interface *ifp) for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (PIM_DEBUG_PIM_TRACE) { - zlog_info("%s: neigh pri %u addr %x if dr addr %x", + zlog_info("%s: neigh pri %u addr %pPA if dr addr %pPA", __func__, neigh->dr_priority, - ntohl(neigh->source_addr.s_addr), - ntohl(pim_ifp->pim_dr_addr.s_addr)); + &neigh->source_addr, &pim_ifp->pim_dr_addr); } - if ((neigh->dr_priority > dr_pri) - || ((neigh->dr_priority == dr_pri) - && (ntohl(neigh->source_addr.s_addr) - > ntohl(pim_ifp->pim_dr_addr.s_addr)))) { + if ((neigh->dr_priority > dr_pri) || + ((neigh->dr_priority == dr_pri) && + (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) > + 0))) { pim_ifp->pim_dr_addr = neigh->source_addr; dr_pri = neigh->dr_priority; } @@ -110,7 +107,7 @@ static void dr_election_by_pri(struct interface *ifp) int pim_if_dr_election(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; - struct in_addr old_dr_addr; + pim_addr old_dr_addr; ++pim_ifp->pim_dr_election_count; @@ -123,18 +120,13 @@ int pim_if_dr_election(struct interface *ifp) } /* DR changed ? */ - if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { - - if (PIM_DEBUG_PIM_EVENTS) { - char dr_old_str[INET_ADDRSTRLEN]; - char dr_new_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", old_dr_addr, dr_old_str, - sizeof(dr_old_str)); - pim_inet4_dump("", pim_ifp->pim_dr_addr, - dr_new_str, sizeof(dr_new_str)); - zlog_debug("%s: DR was %s now is %s on interface %s", - __func__, dr_old_str, dr_new_str, ifp->name); - } + if (pim_addr_cmp(old_dr_addr, pim_ifp->pim_dr_addr)) { + + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug( + "%s: DR was %pPA now is %pPA on interface %s", + __func__, &old_dr_addr, &pim_ifp->pim_dr_addr, + ifp->name); pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ @@ -208,7 +200,7 @@ static void update_dr_priority(struct pim_neighbor *neigh, } } -static int on_neighbor_timer(struct thread *t) +static void on_neighbor_timer(struct thread *t) { struct pim_neighbor *neigh; struct interface *ifp; @@ -218,14 +210,10 @@ static int on_neighbor_timer(struct thread *t) ifp = neigh->interface; - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", neigh->source_addr, src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "Expired %d sec holdtime for neighbor %s on interface %s", - neigh->holdtime, src_str, ifp->name); - } + "Expired %d sec holdtime for neighbor %pPA on interface %s", + neigh->holdtime, &neigh->source_addr, ifp->name); snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime); pim_neighbor_delete(ifp, neigh, msg); @@ -238,8 +226,6 @@ static int on_neighbor_timer(struct thread *t) router's own DR Priority changes. */ pim_if_dr_election(ifp); // neighbor times out - - return 0; } void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime) @@ -255,41 +241,32 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime) return; } - if (PIM_DEBUG_PIM_TRACE_DETAIL) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", neigh->source_addr, src_str, - sizeof(src_str)); - zlog_debug("%s: starting %u sec timer for neighbor %s on %s", - __func__, neigh->holdtime, src_str, + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_debug("%s: starting %u sec timer for neighbor %pPA on %s", + __func__, neigh->holdtime, &neigh->source_addr, neigh->interface->name); - } thread_add_timer(router->master, on_neighbor_timer, neigh, neigh->holdtime, &neigh->t_expire_timer); } -static int on_neighbor_jp_timer(struct thread *t) +static void on_neighbor_jp_timer(struct thread *t) { struct pim_neighbor *neigh = THREAD_ARG(t); struct pim_rpf rpf; - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", neigh->source_addr, src_str, - sizeof(src_str)); - zlog_debug("%s:Sending JP Agg to %s on %s with %d groups", - __func__, src_str, neigh->interface->name, + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s:Sending JP Agg to %pPA on %s with %d groups", + __func__, &neigh->source_addr, + neigh->interface->name, neigh->upstream_jp_agg->count); - } rpf.source_nexthop.interface = neigh->interface; - rpf.rpf_addr.u.prefix4 = neigh->source_addr; + pim_addr_to_prefix(&rpf.rpf_addr, neigh->source_addr); pim_joinprune_send(&rpf, neigh->upstream_jp_agg); thread_add_timer(router->master, on_neighbor_jp_timer, neigh, router->t_periodic, &neigh->jp_timer); - - return 0; } static void pim_neighbor_start_jp_timer(struct pim_neighbor *neigh) @@ -300,7 +277,7 @@ static void pim_neighbor_start_jp_timer(struct pim_neighbor *neigh) } static struct pim_neighbor * -pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, +pim_neighbor_new(struct interface *ifp, pim_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, @@ -308,7 +285,6 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; - char src_str[INET_ADDRSTRLEN]; assert(ifp); pim_ifp = ifp->info; @@ -343,15 +319,12 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, */ PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags); - pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); - - if (PIM_DEBUG_PIM_EVENTS) { - zlog_debug("%s: creating PIM neighbor %s on interface %s", - __func__, src_str, ifp->name); - } + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: creating PIM neighbor %pPA on interface %s", + __func__, &source_addr, ifp->name); - zlog_notice("PIM NEIGHBOR UP: neighbor %s on interface %s", src_str, - ifp->name); + zlog_notice("PIM NEIGHBOR UP: neighbor %pPA on interface %s", + &source_addr, ifp->name); if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) { @@ -448,7 +421,7 @@ struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, } struct pim_neighbor *pim_neighbor_find(struct interface *ifp, - struct in_addr source_addr) + pim_addr source_addr) { struct pim_interface *pim_ifp; struct listnode *node; @@ -462,7 +435,7 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp, return NULL; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { - if (source_addr.s_addr == neigh->source_addr.s_addr) { + if (!pim_addr_cmp(source_addr, neigh->source_addr)) { return neigh; } } @@ -470,6 +443,15 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp, return NULL; } +struct pim_neighbor *pim_neighbor_find_prefix(struct interface *ifp, + const struct prefix *src_prefix) +{ + pim_addr addr; + + addr = pim_addr_from_prefix(src_prefix); + return pim_neighbor_find(ifp, addr); +} + /* * Find the *one* interface out * this interface. If more than @@ -486,7 +468,7 @@ struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp) } struct pim_neighbor * -pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, +pim_neighbor_add(struct interface *ifp, pim_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, @@ -507,11 +489,8 @@ pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, listnode_add(pim_ifp->pim_neighbor_list, neigh); - if (PIM_DEBUG_PIM_TRACE_DETAIL) { - char str[INET_ADDRSTRLEN]; - pim_inet4_dump("", source_addr, str, sizeof(str)); - zlog_debug("%s: neighbor %s added ", __func__, str); - } + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_debug("%s: neighbor %pPA added ", __func__, &source_addr); /* RFC 4601: 4.3.2. DR Election @@ -610,14 +589,12 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, const char *delete_message) { struct pim_interface *pim_ifp; - char src_str[INET_ADDRSTRLEN]; pim_ifp = ifp->info; assert(pim_ifp); - pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); - zlog_notice("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", - src_str, ifp->name, delete_message); + zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s", + &neigh->source_addr, ifp->name, delete_message); THREAD_OFF(neigh->t_expire_timer); @@ -664,8 +641,8 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, } if (PIM_DEBUG_PIM_TRACE) { - zlog_debug("%s: deleting PIM neighbor %s on interface %s", - __func__, src_str, ifp->name); + zlog_debug("%s: deleting PIM neighbor %pPA on interface %s", + __func__, &neigh->source_addr, ifp->name); } listnode_delete(pim_ifp->pim_neighbor_list, neigh); @@ -720,8 +697,7 @@ struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, administrator in a rate-limited manner. */ static void delete_from_neigh_addr(struct interface *ifp, - struct list *addr_list, - struct in_addr neigh_addr) + struct list *addr_list, pim_addr neigh_addr) { struct listnode *addr_node; struct prefix *addr; @@ -752,24 +728,15 @@ static void delete_from_neigh_addr(struct interface *ifp, neigh, addr); if (p) { char addr_str[INET_ADDRSTRLEN]; - char this_neigh_str[INET_ADDRSTRLEN]; - char other_neigh_str[INET_ADDRSTRLEN]; pim_inet4_dump( "", addr->u.prefix4, addr_str, sizeof(addr_str)); - pim_inet4_dump("", neigh_addr, - this_neigh_str, - sizeof(this_neigh_str)); - pim_inet4_dump("", - neigh->source_addr, - other_neigh_str, - sizeof(other_neigh_str)); zlog_info( - "secondary addr %s recvd from neigh %s deleted from neigh %s on %s", - addr_str, this_neigh_str, - other_neigh_str, ifp->name); + "secondary addr %s recvd from neigh %pPA deleted from neigh %pPA on %s", + addr_str, &neigh_addr, + &neigh->source_addr, ifp->name); listnode_delete(neigh->prefix_list, p); prefix_free(&p); diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h index 12c469ae2..2673d2248 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -51,7 +51,9 @@ struct pim_neighbor { void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); void pim_neighbor_free(struct pim_neighbor *neigh); struct pim_neighbor *pim_neighbor_find(struct interface *ifp, - struct in_addr source_addr); + pim_addr source_addr); +struct pim_neighbor *pim_neighbor_find_prefix(struct interface *ifp, + const struct prefix *src_prefix); struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, struct prefix *src); struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp); @@ -60,7 +62,7 @@ struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp); #define PIM_NEIGHBOR_SEND_DELAY 0 #define PIM_NEIGHBOR_SEND_NOW 1 struct pim_neighbor * -pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, +pim_neighbor_add(struct interface *ifp, pim_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index cd6f4c45f..4e7aad99f 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -42,6 +42,7 @@ #include "pim_zebra.h" #include "pim_zlookup.h" #include "pim_rp.h" +#include "pim_addr.h" /** * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister @@ -75,10 +76,7 @@ struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim, struct pim_nexthop_cache *pnc = NULL; struct pim_nexthop_cache lookup; - lookup.rpf.rpf_addr.family = rpf->rpf_addr.family; - lookup.rpf.rpf_addr.prefixlen = rpf->rpf_addr.prefixlen; - lookup.rpf.rpf_addr.u.prefix4.s_addr = rpf->rpf_addr.u.prefix4.s_addr; - + lookup.rpf.rpf_addr = rpf->rpf_addr; pnc = hash_lookup(pim->rpf_hash, &lookup); return pnc; @@ -92,10 +90,7 @@ static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim, pnc = XCALLOC(MTYPE_PIM_NEXTHOP_CACHE, sizeof(struct pim_nexthop_cache)); - pnc->rpf.rpf_addr.family = rpf_addr->rpf_addr.family; - pnc->rpf.rpf_addr.prefixlen = rpf_addr->rpf_addr.prefixlen; - pnc->rpf.rpf_addr.u.prefix4.s_addr = - rpf_addr->rpf_addr.u.prefix4.s_addr; + pnc->rpf.rpf_addr = rpf_addr->rpf_addr; pnc = hash_get(pim->rpf_hash, pnc, hash_alloc_intern); @@ -119,9 +114,7 @@ static struct pim_nexthop_cache *pim_nht_get(struct pim_instance *pim, zclient = pim_zebra_zclient_get(); memset(&rpf, 0, sizeof(struct pim_rpf)); - rpf.rpf_addr.family = addr->family; - rpf.rpf_addr.prefixlen = addr->prefixlen; - rpf.rpf_addr.u.prefix4 = addr->u.prefix4; + rpf.rpf_addr = *addr; pnc = pim_nexthop_cache_find(pim, &rpf); if (!pnc) { @@ -169,6 +162,7 @@ int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, return 0; } +#if PIM_IPV == 4 void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr) { struct pim_nexthop_cache *pnc; @@ -182,6 +176,7 @@ void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr) pnc->bsr_count++; } +#endif /* PIM_IPV == 4 */ static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc) @@ -234,13 +229,10 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, struct prefix grp; struct rp_info *trp_info; - if (upstream->sg.src.s_addr != INADDR_ANY) + if (!pim_addr_is_any(upstream->sg.src)) continue; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = upstream->sg.grp; - + pim_addr_to_prefix(&grp, upstream->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); if (trp_info == rp) hash_release(pnc->upstream_hash, upstream); @@ -254,11 +246,20 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, pim_nht_drop_maybe(pim, pnc); } +#if PIM_IPV == 4 void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr) { struct pim_nexthop_cache *pnc = NULL; struct pim_nexthop_cache lookup; + /* + * Nothing to do here if the address to unregister + * is 0.0.0.0 as that the BSR has not been registered + * for tracking yet. + */ + if (addr.s_addr == INADDR_ANY) + return; + lookup.rpf.rpf_addr.family = AF_INET; lookup.rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN; lookup.rpf.rpf_addr.u.prefix4 = addr; @@ -330,8 +331,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, if (if_is_loopback(ifp) && if_is_loopback(src_ifp)) return true; - nbr = pim_neighbor_find(ifp, - znh->nexthop_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(ifp, &znh->nexthop_addr); if (!nbr) continue; @@ -354,9 +354,10 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, */ for (nh = pnc->nexthop; nh; nh = nh->next) { - struct in_addr nhaddr; + pim_addr nhaddr; switch (nh->type) { +#if PIM_IPV == 4 case NEXTHOP_TYPE_IPV4: if (nh->ifindex == IFINDEX_INTERNAL) continue; @@ -365,7 +366,16 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, case NEXTHOP_TYPE_IPV4_IFINDEX: nhaddr = nh->gate.ipv4; break; +#else + case NEXTHOP_TYPE_IPV6: + if (nh->ifindex == IFINDEX_INTERNAL) + continue; + /* fallthru */ + case NEXTHOP_TYPE_IPV6_IFINDEX: + nhaddr = nh->gate.ipv6; + break; +#endif case NEXTHOP_TYPE_IFINDEX: nhaddr = bsr_addr; break; @@ -391,12 +401,13 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, } return false; } +#endif /* PIM_IPV == 4 */ void pim_rp_nexthop_del(struct rp_info *rp_info) { rp_info->rp.source_nexthop.interface = NULL; - rp_info->rp.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = - PIM_NET_INADDR_ANY; + pim_addr_to_prefix(&rp_info->rp.source_nexthop.mrib_nexthop_addr, + PIMADDR_ANY); rp_info->rp.source_nexthop.mrib_metric_preference = router->infinite_assert_metric.metric_preference; rp_info->rp.source_nexthop.mrib_route_metric = @@ -412,7 +423,7 @@ static void pim_update_rp_nh(struct pim_instance *pim, /*Traverse RP list and update each RP Nexthop info */ for (ALL_LIST_ELEMENTS_RO(pnc->rp_list, node, rp_info)) { - if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; // Compute PIM RPF using cached nexthop @@ -475,23 +486,13 @@ static int pim_update_upstream_nh(struct pim_instance *pim, uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp) { uint32_t hash_val; - uint32_t s = 0, g = 0; - if ((!src)) + if (!src) return 0; - switch (src->family) { - case AF_INET: { - s = src->u.prefix4.s_addr; - s = s == 0 ? 1 : s; - if (grp) - g = grp->u.prefix4.s_addr; - } break; - default: - break; - } - - hash_val = jhash_2words(g, s, 101); + hash_val = prefix_hash_key(src); + if (grp) + hash_val ^= prefix_hash_key(grp); return hash_val; } @@ -509,6 +510,9 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, uint32_t hash_val = 0, mod_val = 0; uint8_t nh_iter = 0, found = 0; uint32_t i, num_nbrs = 0; + pim_addr nh_addr = pim_addr_from_prefix(&(nexthop->mrib_nexthop_addr)); + pim_addr src_addr = pim_addr_from_prefix(src); + pim_addr grp_addr = pim_addr_from_prefix(grp); if (!pnc || !pnc->nexthop_num || !nexthop) return 0; @@ -516,10 +520,10 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, memset(&nbrs, 0, sizeof(nbrs)); memset(&ifps, 0, sizeof(ifps)); + // Current Nexthop is VALID, check to stay on the current path. - if (nexthop->interface && nexthop->interface->info - && nexthop->mrib_nexthop_addr.u.prefix4.s_addr - != PIM_NET_INADDR_ANY) { + if (nexthop->interface && nexthop->interface->info && + (!pim_addr_is_any(nh_addr))) { /* User configured knob to explicitly switch to new path is disabled or current path metric is less than nexthop update. @@ -539,12 +543,12 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, break; } - if (curr_route_valid - && !pim_if_connected_to_source(nexthop->interface, - src->u.prefix4)) { - nbr = pim_neighbor_find( + if (curr_route_valid && + !pim_if_connected_to_source(nexthop->interface, + src_addr)) { + nbr = pim_neighbor_find_prefix( nexthop->interface, - nexthop->mrib_nexthop_addr.u.prefix4); + &nexthop->mrib_nexthop_addr); if (!nbr && !if_is_loopback(nexthop->interface)) { if (PIM_DEBUG_PIM_NHT) @@ -559,23 +563,13 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, pnc->distance; nexthop->mrib_route_metric = pnc->metric; - if (PIM_DEBUG_PIM_NHT) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - src->u.prefix4, - src_str, - sizeof(src_str)); - char grp_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - grp->u.prefix4, - grp_str, - sizeof(grp_str)); + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection", - __func__, src_str, - grp_str, pim->vrf->name, + "%s: (%pPA,%pPA)(%s) current nexthop %s is valid, skipping new path selection", + __func__, &src_addr, + &grp_addr, + pim->vrf->name, nexthop->interface->name); - } return 1; } } @@ -591,11 +585,14 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, ifps[i] = if_lookup_by_index(nh_node->ifindex, pim->vrf->vrf_id); if (ifps[i]) { - nbrs[i] = pim_neighbor_find(ifps[i], - nh_node->gate.ipv4); - if (nbrs[i] || pim_if_connected_to_source(ifps[i], - - src->u.prefix4)) +#if PIM_IPV == 4 + pim_addr nhaddr = nh_node->gate.ipv4; +#else + pim_addr nhaddr = nh_node->gate.ipv6; +#endif + nbrs[i] = pim_neighbor_find(ifps[i], nhaddr); + if (nbrs[i] || + pim_if_connected_to_source(ifps[i], src_addr)) num_nbrs++; } } @@ -618,38 +615,30 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, first_ifindex = nh_node->ifindex; ifp = ifps[nh_iter]; if (!ifp) { - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src->u.prefix4, - addr_str, sizeof(addr_str)); + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s %s: could not find interface for ifindex %d (address %s(%s))", + "%s %s: could not find interface for ifindex %d (address %pPA(%s))", __FILE__, __func__, first_ifindex, - addr_str, pim->vrf->name); - } + &src_addr, pim->vrf->name); if (nh_iter == mod_val) mod_val++; // Select nexthpath nh_iter++; continue; } if (!ifp->info) { - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src->u.prefix4, - addr_str, sizeof(addr_str)); + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)", + "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)", __func__, ifp->name, pim->vrf->name, - first_ifindex, addr_str); - } + first_ifindex, &src_addr); if (nh_iter == mod_val) mod_val++; // Select nexthpath nh_iter++; continue; } - if (neighbor_needed - && !pim_if_connected_to_source(ifp, src->u.prefix4)) { + if (neighbor_needed && + !pim_if_connected_to_source(ifp, src_addr)) { nbr = nbrs[nh_iter]; if (!nbr && !if_is_loopback(ifp)) { if (PIM_DEBUG_PIM_NHT) @@ -666,34 +655,27 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, if (nh_iter == mod_val) { nexthop->interface = ifp; - nexthop->mrib_nexthop_addr.family = AF_INET; - nexthop->mrib_nexthop_addr.prefixlen = IPV4_MAX_BITLEN; + nexthop->mrib_nexthop_addr.family = PIM_AF; + nexthop->mrib_nexthop_addr.prefixlen = PIM_MAX_BITLEN; +#if PIM_IPV == 4 nexthop->mrib_nexthop_addr.u.prefix4 = nh_node->gate.ipv4; +#else + nexthop->mrib_nexthop_addr.u.prefix6 = + nh_node->gate.ipv6; +#endif nexthop->mrib_metric_preference = pnc->distance; nexthop->mrib_route_metric = pnc->metric; - nexthop->last_lookup = src->u.prefix4; + nexthop->last_lookup = src_addr; nexthop->last_lookup_time = pim_time_monotonic_usec(); nexthop->nbr = nbr; found = 1; - if (PIM_DEBUG_PIM_NHT) { - char buf[INET_ADDRSTRLEN]; - char buf2[INET_ADDRSTRLEN]; - char buf3[INET_ADDRSTRLEN]; - pim_inet4_dump("", src->u.prefix4, buf2, - sizeof(buf2)); - pim_inet4_dump("", grp->u.prefix4, buf3, - sizeof(buf3)); - pim_inet4_dump( - "", - nexthop->mrib_nexthop_addr.u.prefix4, - buf, sizeof(buf)); + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d", - __func__, buf2, buf3, pim->vrf->name, - ifp->name, buf, mod_val, nh_iter, - pim->ecmp_enable); - } + "%s: (%pPA,%pPA)(%s) selected nhop interface %s addr %pPAs mod_val %u iter %d ecmp %d", + __func__, &src_addr, &grp_addr, + pim->vrf->name, ifp->name, &nh_addr, + mod_val, nh_iter, pim->ecmp_enable); } nh_iter++; } @@ -720,19 +702,20 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct pim_instance *pim; struct zapi_route nhr; + struct prefix match; if (!vrf) return 0; pim = vrf->info; - if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) { zlog_err("%s: Decode of nexthop update from zebra failed", __func__); return 0; } if (cmd == ZEBRA_NEXTHOP_UPDATE) { - prefix_copy(&rpf.rpf_addr, &nhr.prefix); + prefix_copy(&rpf.rpf_addr, &match); pnc = pim_nexthop_cache_find(pim, &rpf); if (!pnc) { if (PIM_DEBUG_PIM_NHT) @@ -767,9 +750,15 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) * RPF address from nexthop cache (i.e. * destination) as PIM nexthop. */ +#if PIM_IPV == 4 nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; nexthop->gate.ipv4 = pnc->rpf.rpf_addr.u.prefix4; +#else + nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + nexthop->gate.ipv6 = + pnc->rpf.rpf_addr.u.prefix6; +#endif break; case NEXTHOP_TYPE_IPV6_IFINDEX: ifp1 = if_lookup_by_index(nexthop->ifindex, @@ -781,12 +770,19 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) nbr = pim_neighbor_find_if(ifp1); /* Overwrite with Nbr address as NH addr */ if (nbr) +#if PIM_IPV == 4 nexthop->gate.ipv4 = nbr->source_addr; +#else + nexthop->gate.ipv6 = nbr->source_addr; +#endif else { // Mark nexthop address to 0 until PIM // Nbr is resolved. - nexthop->gate.ipv4.s_addr = - PIM_NET_INADDR_ANY; +#if PIM_IPV == 4 + nexthop->gate.ipv4 = PIMADDR_ANY; +#else + nexthop->gate.ipv6 = PIMADDR_ANY; +#endif } break; @@ -811,9 +807,9 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) if (PIM_DEBUG_PIM_NHT) zlog_debug( "%s: NHT addr %pFX(%s) %d-nhop via %pI4(%s) type %d distance:%u metric:%u ", - __func__, &nhr.prefix, pim->vrf->name, - i + 1, &nexthop->gate.ipv4, - ifp->name, nexthop->type, nhr.distance, + __func__, &match, pim->vrf->name, i + 1, + &nexthop->gate.ipv4, ifp->name, + nexthop->type, nhr.distance, nhr.metric); if (!ifp->info) { @@ -867,7 +863,7 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) if (PIM_DEBUG_PIM_NHT) zlog_debug( "%s: NHT Update for %pFX(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d", - __func__, &nhr.prefix, pim->vrf->name, nhr.nexthop_num, + __func__, &match, pim->vrf->name, nhr.nexthop_num, pnc->nexthop_num, vrf_id, pnc->upstream_hash->count, listcount(pnc->rp_list)); @@ -896,20 +892,14 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, uint8_t i = 0; uint32_t hash_val = 0, mod_val = 0; uint32_t num_nbrs = 0; - char addr_str[PREFIX_STRLEN]; + pim_addr src_addr = pim_addr_from_prefix(src); - if (PIM_DEBUG_PIM_NHT) { - pim_inet4_dump("", src->u.prefix4, addr_str, - sizeof(addr_str)); - zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld", - __func__, addr_str, pim->vrf->name, + if (PIM_DEBUG_PIM_NHT) + zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld", + __func__, &src_addr, pim->vrf->name, nexthop->last_lookup_time); - } - memset(&rpf, 0, sizeof(struct pim_rpf)); - rpf.rpf_addr.family = AF_INET; - rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN; - rpf.rpf_addr.u.prefix4 = src->u.prefix4; + rpf.rpf_addr = *src; pnc = pim_nexthop_cache_find(pim, &rpf); if (pnc) { @@ -920,14 +910,13 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, memset(nexthop_tab, 0, sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM); - num_ifindex = - zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, - src->u.prefix4, PIM_NEXTHOP_LOOKUP_MAX); + num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, + src_addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { if (PIM_DEBUG_PIM_NHT) zlog_warn( - "%s: could not find nexthop ifindex for address %s(%s)", - __func__, addr_str, pim->vrf->name); + "%s: could not find nexthop ifindex for address %pPA(%s)", + __func__, &src_addr, pim->vrf->name); return 0; } @@ -942,11 +931,10 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, ifps[i] = if_lookup_by_index(nexthop_tab[i].ifindex, pim->vrf->vrf_id); if (ifps[i]) { - nbrs[i] = pim_neighbor_find( - ifps[i], nexthop_tab[i].nexthop_addr.u.prefix4); - if (nbrs[i] - || pim_if_connected_to_source(ifps[i], - src->u.prefix4)) + nbrs[i] = pim_neighbor_find_prefix( + ifps[i], &nexthop_tab[i].nexthop_addr); + if (nbrs[i] || + pim_if_connected_to_source(ifps[i], src_addr)) num_nbrs++; } } @@ -976,9 +964,9 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, if (!ifp) { if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s %s: could not find interface for ifindex %d (address %s(%s))", + "%s %s: could not find interface for ifindex %d (address %pPA(%s))", __FILE__, __func__, first_ifindex, - addr_str, pim->vrf->name); + &src_addr, pim->vrf->name); if (i == mod_val) mod_val++; i++; @@ -988,16 +976,16 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, if (!ifp->info) { if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)", + "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)", __func__, ifp->name, pim->vrf->name, - first_ifindex, addr_str); + first_ifindex, &src_addr); if (i == mod_val) mod_val++; i++; continue; } - if (neighbor_needed - && !pim_if_connected_to_source(ifp, src->u.prefix4)) { + if (neighbor_needed && + !pim_if_connected_to_source(ifp, src_addr)) { nbr = nbrs[i]; if (PIM_DEBUG_PIM_NHT_DETAIL) zlog_debug("ifp name: %s(%s), pim nbr: %p", @@ -1008,9 +996,9 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, i++; if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: NBR not found on input interface %s(%s) (RPF for source %s)", + "%s: NBR not found on input interface %s(%s) (RPF for source %pPA)", __func__, ifp->name, - pim->vrf->name, addr_str); + pim->vrf->name, &src_addr); continue; } } @@ -1023,8 +1011,8 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, &nexthop_tab[i].nexthop_addr, nexthop_str, sizeof(nexthop_str)); zlog_debug( - "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d", - __func__, nexthop_str, addr_str, + "%s: found nhop %s for addr %pPA interface %s(%s) metric %d dist %d", + __func__, nexthop_str, &src_addr, ifp->name, pim->vrf->name, nexthop_tab[i].route_metric, nexthop_tab[i].protocol_distance); @@ -1037,7 +1025,7 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, nexthop_tab[i].protocol_distance; nexthop->mrib_route_metric = nexthop_tab[i].route_metric; - nexthop->last_lookup = src->u.prefix4; + nexthop->last_lookup = src_addr; nexthop->last_lookup_time = pim_time_monotonic_usec(); nexthop->nbr = nbr; found = 1; @@ -1057,36 +1045,36 @@ int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, struct pim_nexthop nhop; int vif_index; ifindex_t ifindex; - char addr_str[PREFIX_STRLEN]; + pim_addr src_addr; - if (PIM_DEBUG_PIM_NHT) - pim_inet4_dump("", src->u.prefix4, addr_str, - sizeof(addr_str)); + if (PIM_DEBUG_PIM_NHT) { + src_addr = pim_addr_from_prefix(src); + } memset(&nhop, 0, sizeof(nhop)); if (!pim_ecmp_nexthop_lookup(pim, &nhop, src, grp, 1)) { if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: could not find nexthop ifindex for address %s(%s)", - __func__, addr_str, pim->vrf->name); + "%s: could not find nexthop ifindex for address %pPA(%s)", + __func__, &src_addr, pim->vrf->name); return -1; } ifindex = nhop.interface->ifindex; if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s", + "%s: found nexthop ifindex=%d (interface %s(%s)) for address %pPA", __func__, ifindex, ifindex2ifname(ifindex, pim->vrf->vrf_id), - pim->vrf->name, addr_str); + pim->vrf->name, &src_addr); vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex); if (vif_index < 0) { if (PIM_DEBUG_PIM_NHT) { zlog_debug( - "%s: low vif_index=%d(%s) < 1 nexthop for address %s", - __func__, vif_index, pim->vrf->name, addr_str); + "%s: low vif_index=%d(%s) < 1 nexthop for address %pPA", + __func__, vif_index, pim->vrf->name, &src_addr); } return -2; } diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index c094e99a7..d5e459b44 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -42,15 +42,15 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size) pim_sgaddr sg; int i; - sg.src = c_oil->oil.mfcc_origin; - sg.grp = c_oil->oil.mfcc_mcastgrp; - ifp = pim_if_find_by_vif_index(c_oil->pim, c_oil->oil.mfcc_parent); - snprintf(buf, size, "%s IIF: %s, OIFS: ", pim_str_sg_dump(&sg), - ifp ? ifp->name : "(?)"); + sg.src = *oil_origin(c_oil); + sg.grp = *oil_mcastgrp(c_oil); + ifp = pim_if_find_by_vif_index(c_oil->pim, *oil_parent(c_oil)); + snprintfrr(buf, size, "%pSG IIF: %s, OIFS: ", &sg, + ifp ? ifp->name : "(?)"); out = buf + strlen(buf); for (i = 0; i < MAXVIFS; i++) { - if (c_oil->oil.mfcc_ttls[i] != 0) { + if (oil_if_has(c_oil, i) != 0) { ifp = pim_if_find_by_vif_index(c_oil->pim, i); snprintf(out, buf + size - out, "%s ", ifp ? ifp->name : "(?)"); @@ -61,25 +61,19 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size) return buf; } -int pim_channel_oil_compare(const struct channel_oil *c1, - const struct channel_oil *c2) +int pim_channel_oil_compare(const struct channel_oil *cc1, + const struct channel_oil *cc2) { - if (ntohl(c1->oil.mfcc_mcastgrp.s_addr) - < ntohl(c2->oil.mfcc_mcastgrp.s_addr)) - return -1; - - if (ntohl(c1->oil.mfcc_mcastgrp.s_addr) - > ntohl(c2->oil.mfcc_mcastgrp.s_addr)) - return 1; - - if (ntohl(c1->oil.mfcc_origin.s_addr) - < ntohl(c2->oil.mfcc_origin.s_addr)) - return -1; - - if (ntohl(c1->oil.mfcc_origin.s_addr) - > ntohl(c2->oil.mfcc_origin.s_addr)) - return 1; - + struct channel_oil *c1 = (struct channel_oil *)cc1; + struct channel_oil *c2 = (struct channel_oil *)cc2; + int rv; + + rv = pim_addr_cmp(*oil_mcastgrp(c1), *oil_mcastgrp(c2)); + if (rv) + return rv; + rv = pim_addr_cmp(*oil_origin(c1), *oil_origin(c2)); + if (rv) + return rv; return 0; } @@ -109,8 +103,8 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, struct channel_oil *c_oil = NULL; struct channel_oil lookup; - lookup.oil.mfcc_mcastgrp = sg->grp; - lookup.oil.mfcc_origin = sg->src; + *oil_mcastgrp(&lookup) = sg->grp; + *oil_origin(&lookup) = sg->src; c_oil = rb_pim_oil_find(&pim->channel_oil_head, &lookup); @@ -151,10 +145,10 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); - c_oil->oil.mfcc_mcastgrp = sg->grp; - c_oil->oil.mfcc_origin = sg->src; + *oil_mcastgrp(c_oil) = sg->grp; + *oil_origin(c_oil) = sg->src; - c_oil->oil.mfcc_parent = MAXVIFS; + *oil_parent(c_oil) = MAXVIFS; c_oil->oil_ref_count = 1; c_oil->installed = 0; c_oil->up = pim_upstream_find(pim, sg); @@ -163,8 +157,7 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, rb_pim_oil_add(&pim->channel_oil_head, c_oil); if (PIM_DEBUG_MROUTE) - zlog_debug("%s(%s): c_oil %s add", - __func__, name, pim_str_sg_dump(sg)); + zlog_debug("%s(%s): c_oil %pSG add", __func__, name, sg); return c_oil; } @@ -173,8 +166,8 @@ struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil, const char *name) { if (PIM_DEBUG_MROUTE) { - pim_sgaddr sg = {.src = c_oil->oil.mfcc_mcastgrp, - .grp = c_oil->oil.mfcc_origin}; + pim_sgaddr sg = {.src = *oil_mcastgrp(c_oil), + .grp = *oil_origin(c_oil)}; zlog_debug( "%s(%s): Del oil for %pSG, Ref Count: %d (Predecrement)", @@ -223,29 +216,25 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif, pim_ifp = oif->info; + assertf(pim_ifp->mroute_vif_index >= 0, + "trying to del OIF %s with VIF (%d)", oif->name, + pim_ifp->mroute_vif_index); + /* * Don't do anything if we've been asked to remove a source * that is not actually on it. */ if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) { if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); zlog_debug( - "%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", + "%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)", __FILE__, __func__, proto_mask, channel_oil ->oif_flags[pim_ifp->mroute_vif_index], oif->name, pim_ifp->mroute_vif_index, - channel_oil->oil - .mfcc_ttls[pim_ifp->mroute_vif_index], - source_str, group_str); + oil_if_has(channel_oil, pim_ifp->mroute_vif_index), + oil_origin(channel_oil), + oil_mcastgrp(channel_oil)); } return 0; } @@ -255,44 +244,29 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif, if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); zlog_debug( - "%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", + "%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)", __FILE__, __func__, oif->name, pim_ifp->mroute_vif_index, - channel_oil->oil - .mfcc_ttls[pim_ifp->mroute_vif_index], - source_str, group_str); + oil_if_has(channel_oil, pim_ifp->mroute_vif_index), + oil_origin(channel_oil), + oil_mcastgrp(channel_oil)); } return 0; } - channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0; + oil_if_set(channel_oil, pim_ifp->mroute_vif_index, false); /* clear mute; will be re-evaluated when the OIF becomes valid again */ channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~PIM_OIF_FLAG_MUTE; if (pim_upstream_mroute_add(channel_oil, __func__)) { if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); zlog_debug( - "%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", + "%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%pPAs,%pPAs)", __FILE__, __func__, oif->name, - pim_ifp->mroute_vif_index, source_str, - group_str); + pim_ifp->mroute_vif_index, + oil_origin(channel_oil), + oil_mcastgrp(channel_oil)); } return -1; } @@ -300,16 +274,12 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif, --channel_oil->oil_size; if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", channel_oil->oil.mfcc_origin, - source_str, sizeof(source_str)); zlog_debug( - "%s(%s): (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d", - __func__, caller, source_str, group_str, proto_mask, - channel_oil->oil.mfcc_parent, oif->name, + "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u IIF:%d OIF=%s vif_index=%d", + __func__, caller, oil_origin(channel_oil), + oil_mcastgrp(channel_oil), + proto_mask, + *oil_parent(channel_oil), oif->name, pim_ifp->mroute_vif_index); } @@ -327,8 +297,8 @@ void pim_channel_del_inherited_oif(struct channel_oil *c_oil, /* if an inherited OIF is being removed join-desired can change * if the inherited OIL is now empty and KAT is running */ - if (up && up->sg.src.s_addr != INADDR_ANY && - pim_upstream_empty_inherited_olist(up)) + if (up && !pim_addr_is_any(up->sg.src) && + pim_upstream_empty_inherited_olist(up)) pim_upstream_update_join_desired(up->pim, up); } @@ -398,7 +368,7 @@ void pim_channel_update_oif_mute(struct channel_oil *c_oil, bool new_mute; /* If pim_ifp is not a part of the OIL there is nothing to do */ - if (!c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]) + if (!oil_if_has(c_oil, pim_ifp->mroute_vif_index)) return; old_mute = !!(c_oil->oif_flags[pim_ifp->mroute_vif_index] & @@ -452,25 +422,21 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, pim_ifp = oif->info; + assertf(pim_ifp->mroute_vif_index >= 0, + "trying to add OIF %s with VIF (%d)", oif->name, + pim_ifp->mroute_vif_index); + /* Prevent single protocol from subscribing same interface to channel (S,G) multiple times */ if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) { if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); zlog_debug( - "%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", + "%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)", __FILE__, __func__, proto_mask, oif->name, pim_ifp->mroute_vif_index, - channel_oil->oil - .mfcc_ttls[pim_ifp->mroute_vif_index], - source_str, group_str); + oil_if_has(channel_oil, pim_ifp->mroute_vif_index), + oil_origin(channel_oil), + oil_mcastgrp(channel_oil)); } return -3; } @@ -488,36 +454,21 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; /* Check the OIF really exists before returning, and only log warning otherwise */ - if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); + if (oil_if_has(channel_oil, pim_ifp->mroute_vif_index) < 1) { zlog_warn( - "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", + "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)", __FILE__, __func__, proto_mask, oif->name, pim_ifp->mroute_vif_index, - channel_oil->oil - .mfcc_ttls[pim_ifp->mroute_vif_index], - source_str, group_str); + oil_if_has(channel_oil, pim_ifp->mroute_vif_index), + oil_origin(channel_oil), + oil_mcastgrp(channel_oil)); } if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); zlog_debug( - "%s(%s): (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d added to 0x%x", - __func__, caller, source_str, group_str, + "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u OIF=%s vif_index=%d added to 0x%x", + __func__, caller, oil_origin(channel_oil), + oil_mcastgrp(channel_oil), proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil @@ -526,29 +477,21 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, return 0; } - old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]; + old_ttl = oil_if_has(channel_oil, pim_ifp->mroute_vif_index); if (old_ttl > 0) { if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); zlog_debug( - "%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)", + "%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%pPAs,%pPAs)", __FILE__, __func__, oif->name, - pim_ifp->mroute_vif_index, source_str, - group_str); + pim_ifp->mroute_vif_index, + oil_origin(channel_oil), + oil_mcastgrp(channel_oil)); } return -4; } - channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = - PIM_MROUTE_MIN_TTL; + oil_if_set(channel_oil, pim_ifp->mroute_vif_index, PIM_MROUTE_MIN_TTL); /* Some OIFs are held in a muted state i.e. the PIM state machine * decided to include the OIF but additional status check such as @@ -565,26 +508,19 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not * valid to get installed in kernel. */ - if (channel_oil->oil.mfcc_parent != MAXVIFS) { + if (*oil_parent(channel_oil) != MAXVIFS) { if (pim_upstream_mroute_add(channel_oil, __func__)) { if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); zlog_debug( - "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", + "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%pPAs,%pPAs)", __FILE__, __func__, oif->name, - pim_ifp->mroute_vif_index, source_str, - group_str); + pim_ifp->mroute_vif_index, + oil_origin(channel_oil), + oil_mcastgrp(channel_oil)); } - channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] - = old_ttl; + oil_if_set(channel_oil, pim_ifp->mroute_vif_index, + old_ttl); return -5; } } @@ -595,15 +531,11 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", channel_oil->oil.mfcc_origin, - source_str, sizeof(source_str)); zlog_debug( - "%s(%s): (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", - __func__, caller, source_str, group_str, proto_mask, + "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u OIF=%s vif_index=%d: DONE", + __func__, caller, oil_origin(channel_oil), + oil_mcastgrp(channel_oil), + proto_mask, oif->name, pim_ifp->mroute_vif_index); } @@ -612,8 +544,6 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, int pim_channel_oil_empty(struct channel_oil *c_oil) { - static struct mfcctl null_oil; - if (!c_oil) return 1; @@ -621,6 +551,13 @@ int pim_channel_oil_empty(struct channel_oil *c_oil) * non-NULL. * pimreg device (in all vrfs) uses a vifi of * 0 (PIM_OIF_PIM_REGISTER_VIF) so we simply mfcc_ttls[0] */ +#if PIM_IPV == 4 + static pim_mfcctl null_oil; + return !memcmp(&c_oil->oil.mfcc_ttls[1], &null_oil.mfcc_ttls[1], sizeof(null_oil.mfcc_ttls) - sizeof(null_oil.mfcc_ttls[0])); +#else + CPP_NOTICE("FIXME STUB"); + return false; +#endif } diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index 696ef7064..a52e23351 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -98,7 +98,7 @@ struct channel_oil { struct rb_pim_oil_item oil_rb; - struct mfcctl oil; + pim_mfcctl oil; int installed; int oil_inherited_rescan; int oil_size; @@ -110,6 +110,61 @@ struct channel_oil { time_t mroute_creation; }; +#if PIM_IPV == 4 +static inline pim_addr *oil_origin(struct channel_oil *c_oil) +{ + return &c_oil->oil.mfcc_origin; +} + +static inline pim_addr *oil_mcastgrp(struct channel_oil *c_oil) +{ + return &c_oil->oil.mfcc_mcastgrp; +} + +static inline vifi_t *oil_parent(struct channel_oil *c_oil) +{ + return &c_oil->oil.mfcc_parent; +} + +static inline uint8_t oil_if_has(struct channel_oil *c_oil, vifi_t ifi) +{ + return c_oil->oil.mfcc_ttls[ifi]; +} + +static inline void oil_if_set(struct channel_oil *c_oil, vifi_t ifi, uint8_t set) +{ + c_oil->oil.mfcc_ttls[ifi] = set; +} +#else +static inline pim_addr *oil_origin(struct channel_oil *c_oil) +{ + return &c_oil->oil.mf6cc_origin.sin6_addr; +} + +static inline pim_addr *oil_mcastgrp(struct channel_oil *c_oil) +{ + return &c_oil->oil.mf6cc_mcastgrp.sin6_addr; +} + +static inline mifi_t *oil_parent(struct channel_oil *c_oil) +{ + return &c_oil->oil.mf6cc_parent; +} + +static inline bool oil_if_has(struct channel_oil *c_oil, mifi_t ifi) +{ + return !!IF_ISSET(ifi, &c_oil->oil.mf6cc_ifset); +} + +static inline void oil_if_set(struct channel_oil *c_oil, mifi_t ifi, bool set) +{ + if (set) + IF_SET(ifi, &c_oil->oil.mf6cc_ifset); + else + IF_CLR(ifi, &c_oil->oil.mf6cc_ifset); +} +#endif + extern int pim_channel_oil_compare(const struct channel_oil *c1, const struct channel_oil *c2); DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb, diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 2142d9010..3980e4828 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -42,7 +42,7 @@ #include "pim_errors.h" #include "pim_bsm.h" -static int on_pim_hello_send(struct thread *t); +static void on_pim_hello_send(struct thread *t); static const char *pim_pim_msgtype2str(enum pim_msg_type type) { @@ -326,13 +326,13 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) static void pim_sock_read_on(struct interface *ifp); -static int pim_sock_read(struct thread *t) +static void pim_sock_read(struct thread *t) { struct interface *ifp, *orig_ifp; struct pim_interface *pim_ifp; int fd; - struct sockaddr_in from; - struct sockaddr_in to; + struct sockaddr_storage from; + struct sockaddr_storage to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); uint8_t buf[PIM_PIM_BUFSIZE_READ]; @@ -398,8 +398,6 @@ done: if (result) { ++pim_ifp->pim_ifstat_hello_recvfail; } - - return result; } static void pim_sock_read_on(struct interface *ifp) @@ -430,7 +428,7 @@ static int pim_sock_open(struct interface *ifp) return -1; if (pim_socket_join(fd, qpim_all_pim_routers_addr, - pim_ifp->primary_address, ifp->ifindex)) { + pim_ifp->primary_address, ifp->ifindex, pim_ifp)) { close(fd); return -2; } @@ -469,6 +467,8 @@ void pim_ifstat_reset(struct interface *ifp) pim_ifp->pim_ifstat_bsm_cfg_miss = 0; pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0; pim_ifp->pim_ifstat_bsm_invalid_sz = 0; + pim_ifp->igmp_ifstat_joins_sent = 0; + pim_ifp->igmp_ifstat_joins_failed = 0; } void pim_sock_reset(struct interface *ifp) @@ -570,7 +570,7 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len, return 0; } -int pim_msg_send(int fd, pim_addr src, struct in_addr dst, uint8_t *pim_msg, +int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, const char *ifname) { struct sockaddr_in to; @@ -745,7 +745,7 @@ static void hello_resched(struct interface *ifp) /* Periodic hello timer */ -static int on_pim_hello_send(struct thread *t) +static void on_pim_hello_send(struct thread *t) { struct pim_interface *pim_ifp; struct interface *ifp; @@ -761,7 +761,7 @@ static int on_pim_hello_send(struct thread *t) /* * Send hello */ - return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); + pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); } /* diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h index b9fdb14dc..1931e8cee 100644 --- a/pimd/pim_pim.h +++ b/pimd/pim_pim.h @@ -56,8 +56,8 @@ void pim_hello_restart_triggered(struct interface *ifp); int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len); -int pim_msg_send(int fd, struct in_addr src, struct in_addr dst, - uint8_t *pim_msg, int pim_msg_size, const char *ifname); +int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, + int pim_msg_size, const char *ifname); int pim_hello_send(struct interface *ifp, uint16_t holdtime); #endif /* PIM_PIM_H */ diff --git a/pimd/pim_register.c b/pimd/pim_register.c index e7bbeb4f6..8313c8d4f 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -72,12 +72,10 @@ void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, unsigned int b1length = 0; unsigned int length; uint8_t *b1; - struct prefix p; if (PIM_DEBUG_PIM_REG) { - zlog_debug("Sending Register stop for %s to %pI4 on %s", - pim_str_sg_dump(sg), &originator, - ifp->name); + zlog_debug("Sending Register stop for %pSG to %pI4 on %s", sg, + &originator, ifp->name); } memset(buffer, 0, 10000); @@ -87,10 +85,7 @@ void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, b1length += length; b1 += length; - p.family = AF_INET; - p.u.prefix4 = sg->src; - p.prefixlen = IPV4_MAX_BITLEN; - length = pim_encode_addr_ucast(b1, &p); + length = pim_encode_addr_ucast(b1, sg->src); b1length += length; pim_msg_build_header(buffer, b1length + PIM_MSG_REGISTER_STOP_LEN, @@ -118,8 +113,8 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size) struct pim_interface *pim_ifp = ifp->info; struct pim_instance *pim = pim_ifp->pim; struct pim_upstream *upstream = NULL; - struct prefix source; pim_sgaddr sg; + bool wrong_af = false; int l; ++pim_ifp->pim_ifstat_reg_stop_recv; @@ -128,8 +123,12 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size) l = pim_parse_addr_group(&sg, buf, buf_size); buf += l; buf_size -= l; - pim_parse_addr_ucast(&source, buf, buf_size); - sg.src = source.u.prefix4; + pim_parse_addr_ucast(&sg.src, buf, buf_size, &wrong_af); + + if (wrong_af) { + zlog_err("invalid AF in Register-Stop on %s", ifp->name); + return 0; + } upstream = pim_upstream_find(pim, &sg); if (!upstream) { @@ -312,30 +311,26 @@ void pim_null_register_send(struct pim_upstream *up) * } * } */ -int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, - struct in_addr src_addr, uint8_t *tlv_buf, - int tlv_buf_size) +int pim_register_recv(struct interface *ifp, pim_addr dest_addr, + pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) { int sentRegisterStop = 0; - struct ip *ip_hdr; + const void *ip_hdr; pim_sgaddr sg; uint32_t *bits; int i_am_rp = 0; struct pim_interface *pim_ifp = ifp->info; struct pim_instance *pim = pim_ifp->pim; + pim_addr rp_addr; #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 - ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); - - if (!if_address_is_local(&dest_addr, AF_INET, pim->vrf->vrf_id)) { - if (PIM_DEBUG_PIM_REG) { - char dest[INET_ADDRSTRLEN]; + ip_hdr = (tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); - pim_inet4_dump("", dest_addr, dest, sizeof(dest)); + if (!if_address_is_local(&dest_addr, PIM_AF, pim->vrf->vrf_id)) { + if (PIM_DEBUG_PIM_REG) zlog_debug( - "%s: Received Register message for destination address: %s that I do not own", - __func__, dest); - } + "%s: Received Register message for destination address: %pPA that I do not own", + __func__, &dest_addr); return 0; } @@ -368,72 +363,60 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, * start of the actual Encapsulated data. */ memset(&sg, 0, sizeof(sg)); - sg.src = ip_hdr->ip_src; - sg.grp = ip_hdr->ip_dst; + sg = pim_sgaddr_from_iphdr(ip_hdr); i_am_rp = I_am_RP(pim, sg.grp); - if (PIM_DEBUG_PIM_REG) { - char src_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); - zlog_debug("Received Register message%s from %s on %s, rp: %d", - pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp); - } + if (PIM_DEBUG_PIM_REG) + zlog_debug( + "Received Register message%pSG from %pPA on %s, rp: %d", + &sg, &src_addr, ifp->name, i_am_rp); if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) { - if (sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(sg.src)) { zlog_warn( - "%s: Received Register message for Group(%pI4) is now in SSM, dropping the packet", + "%s: Received Register message for Group(%pPA) is now in SSM, dropping the packet", __func__, &sg.grp); /* Drop Packet Silently */ return 0; } } - if (i_am_rp - && (dest_addr.s_addr - == ((RP(pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) { + rp_addr = pim_addr_from_prefix(&(RP(pim, sg.grp))->rpf_addr); + if (i_am_rp && (!pim_addr_cmp(dest_addr, rp_addr))) { sentRegisterStop = 0; if (pim->register_plist) { struct prefix_list *plist; struct prefix src; - plist = prefix_list_lookup(AFI_IP, pim->register_plist); + plist = prefix_list_lookup(PIM_AFI, + pim->register_plist); - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = sg.src; + pim_addr_to_prefix(&src, sg.src); if (prefix_list_apply(plist, &src) == PREFIX_DENY) { pim_register_stop_send(ifp, &sg, dest_addr, src_addr); - if (PIM_DEBUG_PIM_PACKETS) { - char src_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("", src_addr, - src_str, - sizeof(src_str)); + if (PIM_DEBUG_PIM_PACKETS) zlog_debug( - "%s: Sending register-stop to %s for %pSG due to prefix-list denial, dropping packet", - __func__, src_str, &sg); - } + "%s: Sending register-stop to %pPA for %pSG due to prefix-list denial, dropping packet", + __func__, &src_addr, &sg); return 0; } } if (*bits & PIM_REGISTER_BORDER_BIT) { - struct in_addr pimbr = pim_br_get_pmbr(&sg); + pim_addr pimbr = pim_br_get_pmbr(&sg); if (PIM_DEBUG_PIM_PACKETS) zlog_debug( "%s: Received Register message with Border bit set", __func__); - if (pimbr.s_addr == pim_br_unknown.s_addr) + if (pim_addr_is_any(pimbr)) pim_br_set_pmbr(&sg, src_addr); - else if (src_addr.s_addr != pimbr.s_addr) { + else if (pim_addr_cmp(src_addr, pimbr)) { pim_register_stop_send(ifp, &sg, dest_addr, src_addr); if (PIM_DEBUG_PIM_PACKETS) @@ -515,13 +498,11 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, } else { if (PIM_DEBUG_PIM_REG) { if (!i_am_rp) - zlog_debug( - "Received Register packet for %s, Rejecting packet because I am not the RP configured for group", - pim_str_sg_dump(&sg)); + zlog_debug("Received Register packet for %pSG, Rejecting packet because I am not the RP configured for group", + &sg); else - zlog_debug( - "Received Register packet for %s, Rejecting packet because the dst ip address is not the actual RP", - pim_str_sg_dump(&sg)); + zlog_debug("Received Register packet for %pSG, Rejecting packet because the dst ip address is not the actual RP", + &sg); } pim_register_stop_send(ifp, &sg, dest_addr, src_addr); } diff --git a/pimd/pim_register.h b/pimd/pim_register.h index fd4284b80..0ebef40c5 100644 --- a/pimd/pim_register.h +++ b/pimd/pim_register.h @@ -32,9 +32,8 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size); -int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, - struct in_addr src_addr, uint8_t *tlv_buf, - int tlv_buf_size); +int pim_register_recv(struct interface *ifp, pim_addr dest_addr, + pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src, struct pim_rpf *rpg, int null_register, diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index d356aff9f..99727cf83 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -48,6 +48,8 @@ #include "pim_oil.h" #include "pim_zebra.h" #include "pim_bsm.h" +#include "pim_util.h" +#include "pim_ssm.h" /* Cleanup pim->rpf_hash each node data */ void pim_rp_list_hash_clean(void *data) @@ -76,26 +78,21 @@ int pim_rp_list_cmp(void *v1, void *v2) { struct rp_info *rp1 = (struct rp_info *)v1; struct rp_info *rp2 = (struct rp_info *)v2; + int ret; /* * Sort by RP IP address */ - if (rp1->rp.rpf_addr.u.prefix4.s_addr - < rp2->rp.rpf_addr.u.prefix4.s_addr) - return -1; - - if (rp1->rp.rpf_addr.u.prefix4.s_addr - > rp2->rp.rpf_addr.u.prefix4.s_addr) - return 1; + ret = prefix_cmp(&rp1->rp.rpf_addr, &rp2->rp.rpf_addr); + if (ret) + return ret; /* * Sort by group IP address */ - if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr) - return -1; - - if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr) - return 1; + ret = prefix_cmp(&rp1->group, &rp2->group); + if (ret) + return ret; return 0; } @@ -113,27 +110,24 @@ void pim_rp_init(struct pim_instance *pim) rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); - if (!str2prefix("224.0.0.0/4", &rp_info->group)) { + if (!pim_get_all_mcast_group(&rp_info->group)) { flog_err(EC_LIB_DEVELOPMENT, - "Unable to convert 224.0.0.0/4 to prefix"); + "Unable to convert all-multicast prefix"); list_delete(&pim->rp_list); route_table_finish(pim->rp_table); XFREE(MTYPE_PIM_RP, rp_info); return; } - rp_info->group.family = AF_INET; - rp_info->rp.rpf_addr.family = AF_INET; - rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_BITLEN; - rp_info->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; + pim_addr_to_prefix(&rp_info->rp.rpf_addr, PIMADDR_ANY); listnode_add(pim->rp_list, rp_info); rn = route_node_get(pim->rp_table, &rp_info->group); rn->info = rp_info; if (PIM_DEBUG_PIM_TRACE) - zlog_debug( - "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d", - rn, rp_info, route_node_get_lock_count(rn)); + zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn, + rp_info, &rp_info->group, + route_node_get_lock_count(rn)); } void pim_rp_free(struct pim_instance *pim) @@ -150,15 +144,17 @@ void pim_rp_free(struct pim_instance *pim) * Given an RP's prefix-list, return the RP's rp_info for that prefix-list */ static struct rp_info *pim_rp_find_prefix_list(struct pim_instance *pim, - struct in_addr rp, - const char *plist) + pim_addr rp, const char *plist) { struct listnode *node; struct rp_info *rp_info; + struct prefix rp_prefix; + + pim_addr_to_prefix(&rp_prefix, rp); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr - && rp_info->plist && strcmp(rp_info->plist, plist) == 0) { + if (prefix_same(&rp_prefix, &rp_info->rp.rpf_addr) && + rp_info->plist && strcmp(rp_info->plist, plist) == 0) { return rp_info; } } @@ -187,16 +183,17 @@ static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist) * Given an RP's address, return the RP's rp_info that is an exact match for * 'group' */ -static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, - struct in_addr rp, +static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, pim_addr rp, const struct prefix *group) { struct listnode *node; struct rp_info *rp_info; + struct prefix rp_prefix; + pim_addr_to_prefix(&rp_prefix, rp); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr - && prefix_same(&rp_info->group, group)) + if (prefix_same(&rp_prefix, &rp_info->rp.rpf_addr) && + prefix_same(&rp_info->group, group)) return rp_info; } @@ -240,7 +237,7 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, bp = NULL; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp_info->plist) { - plist = prefix_list_lookup(AFI_IP, rp_info->plist); + plist = prefix_list_lookup(PIM_AFI, rp_info->plist); if (prefix_list_apply_ext(plist, &entry, group, true) == PREFIX_DENY || !entry) @@ -322,9 +319,11 @@ static int pim_rp_check_interface_addrs(struct rp_info *rp_info, { struct listnode *node; struct pim_secondary_addr *sec_addr; + pim_addr rpf_addr; - if (pim_ifp->primary_address.s_addr - == rp_info->rp.rpf_addr.u.prefix4.s_addr) + rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + + if (!pim_addr_cmp(pim_ifp->primary_address, rpf_addr)) return 1; if (!pim_ifp->sec_addr_list) { @@ -362,8 +361,8 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) { struct pim_rpf old_rpf; enum pim_rpf_result rpf_result; - struct in_addr old_upstream_addr; - struct in_addr new_upstream_addr; + pim_addr old_upstream_addr; + pim_addr new_upstream_addr; struct prefix nht_p; old_upstream_addr = up->upstream_addr; @@ -371,10 +370,10 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) up->sg.grp); if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: pim upstream update for old upstream %pI4", + zlog_debug("%s: pim upstream update for old upstream %pPA", __func__, &old_upstream_addr); - if (old_upstream_addr.s_addr == new_upstream_addr.s_addr) + if (!pim_addr_cmp(old_upstream_addr, new_upstream_addr)) return; /* Lets consider a case, where a PIM upstream has a better RP as a @@ -382,11 +381,9 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) * This upstream has to be added to the upstream hash of new RP's * NHT(pnc) and has to be removed from old RP's NHT upstream hash */ - if (old_upstream_addr.s_addr != INADDR_ANY) { + if (!pim_addr_is_any(old_upstream_addr)) { /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = old_upstream_addr; + pim_addr_to_prefix(&nht_p, old_upstream_addr); if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Deregister upstream %s addr %pFX with Zebra NHT", @@ -414,12 +411,10 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) } -int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, - struct prefix group, const char *plist, - enum rp_source rp_src_flag) +int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, + const char *plist, enum rp_source rp_src_flag) { int result = 0; - char rp[INET_ADDRSTRLEN]; struct rp_info *rp_info; struct rp_info *rp_all; struct prefix group_all; @@ -431,26 +426,20 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, struct pim_upstream *up; bool upstream_updated = false; - if (rp_addr.s_addr == INADDR_ANY || - rp_addr.s_addr == INADDR_NONE) + if (pim_addr_is_any(rp_addr)) return PIM_RP_BAD_ADDRESS; rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); - rp_info->rp.rpf_addr.family = AF_INET; - rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_BITLEN; - rp_info->rp.rpf_addr.u.prefix4 = rp_addr; + pim_addr_to_prefix(&rp_info->rp.rpf_addr, rp_addr); prefix_copy(&rp_info->group, &group); rp_info->rp_src = rp_src_flag; - inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp, sizeof(rp)); - if (plist) { /* * Return if the prefix-list is already configured for this RP */ - if (pim_rp_find_prefix_list(pim, rp_info->rp.rpf_addr.u.prefix4, - plist)) { + if (pim_rp_find_prefix_list(pim, rp_addr, plist)) { XFREE(MTYPE_PIM_RP, rp_info); return PIM_SUCCESS; } @@ -468,14 +457,14 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, */ for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode, tmp_rp_info)) { - if (rp_info->rp.rpf_addr.u.prefix4.s_addr - == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr) { + if (prefix_same(&rp_info->rp.rpf_addr, + &tmp_rp_info->rp.rpf_addr)) { if (tmp_rp_info->plist) - pim_rp_del_config(pim, rp, NULL, + pim_rp_del_config(pim, rp_addr, NULL, tmp_rp_info->plist); else pim_rp_del_config( - pim, rp, + pim, rp_addr, prefix2str(&tmp_rp_info->group, buffer, BUFSIZ), NULL); @@ -485,7 +474,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist); } else { - if (!str2prefix("224.0.0.0/4", &group_all)) { + if (!pim_get_all_mcast_group(&group_all)) { XFREE(MTYPE_PIM_RP, rp_info); return PIM_GROUP_BAD_ADDRESS; } @@ -504,29 +493,25 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, */ for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode, tmp_rp_info)) { - if (tmp_rp_info->plist - && rp_info->rp.rpf_addr.u.prefix4.s_addr - == tmp_rp_info->rp.rpf_addr.u.prefix4 - .s_addr) { - pim_rp_del_config(pim, rp, NULL, + if (tmp_rp_info->plist && + prefix_same(&rp_info->rp.rpf_addr, + &tmp_rp_info->rp.rpf_addr)) { + pim_rp_del_config(pim, rp_addr, NULL, tmp_rp_info->plist); } } /* - * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE + * Take over the 224.0.0.0/4 group if the rp is INADDR_ANY */ - if (prefix_same(&rp_all->group, &rp_info->group) - && pim_rpf_addr_is_inaddr_none(&rp_all->rp)) { + if (prefix_same(&rp_all->group, &rp_info->group) && + pim_rpf_addr_is_inaddr_any(&rp_all->rp)) { rp_all->rp.rpf_addr = rp_info->rp.rpf_addr; rp_all->rp_src = rp_src_flag; XFREE(MTYPE_PIM_RP, rp_info); /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = - rp_all->rp.rpf_addr.u.prefix4; // RP address + nht_p = rp_all->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug( "%s: NHT Register rp_all addr %pFX grp %pFX ", @@ -536,14 +521,12 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, /* Find (*, G) upstream whose RP is not * configured yet */ - if ((up->upstream_addr.s_addr == INADDR_ANY) - && (up->sg.src.s_addr == INADDR_ANY)) { + if (pim_addr_is_any(up->upstream_addr) && + pim_addr_is_any(up->sg.src)) { struct prefix grp; struct rp_info *trp_info; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group( pim, &grp); if (trp_info == rp_all) { @@ -570,8 +553,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, /* * Return if the group is already configured for this RP */ - tmp_rp_info = pim_rp_find_exact( - pim, rp_info->rp.rpf_addr.u.prefix4, &rp_info->group); + tmp_rp_info = pim_rp_find_exact(pim, rp_addr, &rp_info->group); if (tmp_rp_info) { if ((tmp_rp_info->rp_src != rp_src_flag) && (rp_src_flag == RP_SRC_STATIC)) @@ -607,8 +589,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, } result = pim_rp_change( - pim, - rp_info->rp.rpf_addr.u.prefix4, + pim, rp_addr, tmp_rp_info->group, rp_src_flag); XFREE(MTYPE_PIM_RP, rp_info); @@ -628,13 +609,11 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, route_node_get_lock_count(rn)); frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (up->sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->sg.src)) { struct prefix grp; struct rp_info *trp_info; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); if (trp_info == rp_info) { @@ -651,9 +630,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, pim_rp_refresh_group_to_rp_mapping(pim); /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ", __func__, &nht_p, &rp_info->group); @@ -665,32 +642,30 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, return PIM_SUCCESS; } -int pim_rp_del_config(struct pim_instance *pim, const char *rp, - const char *group_range, const char *plist) +void pim_rp_del_config(struct pim_instance *pim, pim_addr rp_addr, + const char *group_range, const char *plist) { struct prefix group; - struct in_addr rp_addr; int result; if (group_range == NULL) - result = str2prefix("224.0.0.0/4", &group); + result = pim_get_all_mcast_group(&group); else result = str2prefix(group_range, &group); - if (!result) - return PIM_GROUP_BAD_ADDRESS; - - result = inet_pton(AF_INET, rp, &rp_addr); - if (result <= 0) - return PIM_RP_BAD_ADDRESS; + if (!result) { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug( + "%s: String to prefix failed for %pPAs group", + __func__, &rp_addr); + return; + } - result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC); - return result; + pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC); } -int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, - struct prefix group, const char *plist, - enum rp_source rp_src_flag) +int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, + const char *plist, enum rp_source rp_src_flag) { struct prefix g_all; struct rp_info *rp_info; @@ -702,12 +677,8 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, struct pim_upstream *up; struct bsgrp_node *bsgrp = NULL; struct bsm_rpinfo *bsrp = NULL; - char rp_str[INET_ADDRSTRLEN]; bool upstream_updated = false; - if (!inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str))) - snprintf(rp_str, sizeof(rp_str), ""); - if (plist) rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist); else @@ -722,8 +693,8 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, } if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: Delete RP %s for the group %pFX", __func__, - rp_str, &group); + zlog_debug("%s: Delete RP %pPA for the group %pFX", __func__, + &rp_addr, &group); /* While static RP is getting deleted, we need to check if dynamic RP * present for the same group in BSM RP table, then install the dynamic @@ -735,19 +706,11 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, if (bsgrp) { bsrp = bsm_rpinfos_first(bsgrp->bsrp_list); if (bsrp) { - if (PIM_DEBUG_PIM_TRACE) { - char bsrp_str[INET_ADDRSTRLEN]; - - if (!inet_ntop(AF_INET, bsrp, bsrp_str, - sizeof(bsrp_str))) - snprintf(bsrp_str, - sizeof(bsrp_str), - ""); - + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: BSM RP %s found for the group %pFX", - __func__, bsrp_str, &group); - } + "%s: BSM RP %pPA found for the group %pFX", + __func__, &bsrp->rp_address, + &group); return pim_rp_change(pim, bsrp->rp_address, group, RP_SRC_BSR); } @@ -760,15 +723,13 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, } /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__, &nht_p); pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); - if (!str2prefix("224.0.0.0/4", &g_all)) + if (!pim_get_all_mcast_group(&g_all)) return PIM_RP_BAD_ADDRESS; rp_all = pim_rp_find_match_group(pim, &g_all); @@ -778,22 +739,22 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, /* Find the upstream (*, G) whose upstream address is * same as the deleted RP */ - if ((up->upstream_addr.s_addr - == rp_info->rp.rpf_addr.u.prefix4.s_addr) - && (up->sg.src.s_addr == INADDR_ANY)) { + pim_addr rpf_addr; + + rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + if (!pim_addr_cmp(up->upstream_addr, rpf_addr) && + pim_addr_is_any(up->sg.src)) { struct prefix grp; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); if (trp_info == rp_all) { pim_upstream_rpf_clear(pim, up); - up->upstream_addr.s_addr = INADDR_ANY; + up->upstream_addr = PIMADDR_ANY; } } } - rp_all->rp.rpf_addr.family = AF_INET; - rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; + pim_addr_to_prefix(&rp_all->rp.rpf_addr, PIMADDR_ANY); rp_all->i_am_rp = 0; return PIM_SUCCESS; } @@ -826,19 +787,18 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, /* Find the upstream (*, G) whose upstream address is same as * the deleted RP */ - if ((up->upstream_addr.s_addr - == rp_info->rp.rpf_addr.u.prefix4.s_addr) - && (up->sg.src.s_addr == INADDR_ANY)) { - struct prefix grp; + pim_addr rpf_addr; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + if (!pim_addr_cmp(up->upstream_addr, rpf_addr) && + pim_addr_is_any(up->sg.src)) { + struct prefix grp; + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); /* RP not found for the group grp */ - if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { + if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) { pim_upstream_rpf_clear(pim, up); pim_rp_set_upstream_addr( pim, &up->upstream_addr, up->sg.src, @@ -860,7 +820,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, return PIM_SUCCESS; } -int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, +int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, struct prefix group, enum rp_source rp_src_flag) { struct prefix nht_p; @@ -869,6 +829,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, struct rp_info *rp_info = NULL; struct pim_upstream *up; bool upstream_updated = false; + pim_addr old_rp_addr; rn = route_node_lookup(pim->rp_table, &group); if (!rn) { @@ -884,7 +845,8 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, return result; } - if (rp_info->rp.rpf_addr.u.prefix4.s_addr == new_rp_addr.s_addr) { + old_rp_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + if (!pim_addr_cmp(new_rp_addr, old_rp_addr)) { if (rp_info->rp_src != rp_src_flag) { rp_info->rp_src = rp_src_flag; route_unlock_node(rn); @@ -892,12 +854,13 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, } } - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.family = PIM_AF; + nht_p.prefixlen = PIM_MAX_BITLEN; /* Deregister old RP addr with Zebra NHT */ - if (rp_info->rp.rpf_addr.u.prefix4.s_addr != INADDR_ANY) { - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + + if (!pim_addr_is_any(old_rp_addr)) { + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__, &nht_p); @@ -907,20 +870,19 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, pim_rp_nexthop_del(rp_info); listnode_delete(pim->rp_list, rp_info); /* Update the new RP address*/ - rp_info->rp.rpf_addr.u.prefix4 = new_rp_addr; + + pim_addr_to_prefix(&rp_info->rp.rpf_addr, new_rp_addr); rp_info->rp_src = rp_src_flag; rp_info->i_am_rp = 0; listnode_add_sort(pim->rp_list, rp_info); frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (up->sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->sg.src)) { struct prefix grp; struct rp_info *trp_info; - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&grp, up->sg.grp); trp_info = pim_rp_find_match_group(pim, &grp); if (trp_info == rp_info) { @@ -934,7 +896,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, pim_zebra_update_all_interfaces(pim); /* Register new RP addr with Zebra NHT */ - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ", __func__, &nht_p, &rp_info->group); @@ -962,12 +924,10 @@ void pim_rp_setup(struct pim_instance *pim) struct prefix nht_p; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL); if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, @@ -993,7 +953,7 @@ void pim_rp_check_on_if_add(struct pim_interface *pim_ifp) return; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; /* if i_am_rp is already set nothing to be done (adding new @@ -1035,7 +995,7 @@ void pim_i_am_rp_re_evaluate(struct pim_instance *pim) return; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; old_i_am_rp = rp_info->i_am_rp; @@ -1070,21 +1030,17 @@ void pim_i_am_rp_re_evaluate(struct pim_instance *pim) * * Since we only have static RP, all groups are part of this RP */ -int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group) +int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group) { struct prefix g; struct rp_info *rp_info; memset(&g, 0, sizeof(g)); - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; - g.u.prefix4 = group; - + pim_addr_to_prefix(&g, group); rp_info = pim_rp_find_match_group(pim, &g); if (rp_info) return rp_info->i_am_rp; - return 0; } @@ -1093,15 +1049,13 @@ int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group) * * Return the RP that the Group belongs too. */ -struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) +struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group) { struct prefix g; struct rp_info *rp_info; memset(&g, 0, sizeof(g)); - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; - g.u.prefix4 = group; + pim_addr_to_prefix(&g, group); rp_info = pim_rp_find_match_group(pim, &g); @@ -1109,9 +1063,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) struct prefix nht_p; /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug( "%s: NHT Register RP addr %pFX grp %pFX with Zebra", @@ -1135,30 +1087,31 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) * then set the upstream addr as INADDR_ANY and return failure. * */ -int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, - struct in_addr source, struct in_addr group) +int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, + pim_addr source, pim_addr group) { struct rp_info *rp_info; struct prefix g; memset(&g, 0, sizeof(g)); - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; - g.u.prefix4 = group; + + pim_addr_to_prefix(&g, group); rp_info = pim_rp_find_match_group(pim, &g); - if (!rp_info || ((pim_rpf_addr_is_inaddr_none(&rp_info->rp)) - && (source.s_addr == INADDR_ANY))) { + if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) && + (pim_addr_is_any(source)))) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __func__); - up->s_addr = INADDR_ANY; + *up = PIMADDR_ANY; return 0; } - *up = (source.s_addr == INADDR_ANY) ? rp_info->rp.rpf_addr.u.prefix4 - : source; + if (pim_addr_is_any(source)) + *up = pim_addr_from_prefix(&rp_info->rp.rpf_addr); + else + *up = source; return 1; } @@ -1168,41 +1121,38 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, { struct listnode *node; struct rp_info *rp_info; - char rp_buffer[32]; int count = 0; + pim_addr rp_addr; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; if (rp_info->rp_src == RP_SRC_BSR) continue; + rp_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr); if (rp_info->plist) - vty_out(vty, "%sip pim rp %s prefix-list %s\n", spaces, - inet_ntop(AF_INET, - &rp_info->rp.rpf_addr.u.prefix4, - rp_buffer, 32), - rp_info->plist); + vty_out(vty, + "%s" PIM_AF_NAME + " pim rp %pPA prefix-list %s\n", + spaces, &rp_addr, rp_info->plist); else - vty_out(vty, "%sip pim rp %s %pFX\n", spaces, - inet_ntop(AF_INET, - &rp_info->rp.rpf_addr.u.prefix4, - rp_buffer, 32), - &rp_info->group); + vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n", + spaces, &rp_addr, &rp_info->group); count++; } return count; } -void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) +void pim_rp_show_information(struct pim_instance *pim, struct prefix *range, + struct vty *vty, bool uj) { struct rp_info *rp_info; struct rp_info *prev_rp_info = NULL; struct listnode *node; char source[7]; - char buf[PREFIX_STRLEN]; json_object *json = NULL; json_object *json_rp_rows = NULL; @@ -1212,112 +1162,105 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) json = json_object_new_object(); else vty_out(vty, - "RP address group/prefix-list OIF I am RP Source\n"); + "RP address group/prefix-list OIF I am RP Source Group-Type\n"); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) { - char buf[48]; + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) + continue; - if (rp_info->rp_src == RP_SRC_STATIC) - strlcpy(source, "Static", sizeof(source)); - else if (rp_info->rp_src == RP_SRC_BSR) - strlcpy(source, "BSR", sizeof(source)); - else - strlcpy(source, "None", sizeof(source)); - if (uj) { - /* - * If we have moved on to a new RP then add the - * entry for the previous RP - */ - if (prev_rp_info - && prev_rp_info->rp.rpf_addr.u.prefix4 - .s_addr - != rp_info->rp.rpf_addr.u.prefix4 - .s_addr) { - json_object_object_add( - json, - inet_ntop(AF_INET, - &prev_rp_info->rp - .rpf_addr.u - .prefix4, - buf, sizeof(buf)), - json_rp_rows); - json_rp_rows = NULL; - } +#if PIM_IPV == 4 + pim_addr group = rp_info->group.u.prefix4; +#else + pim_addr group = rp_info->group.u.prefix6; +#endif + const char *group_type = + pim_is_grp_ssm(pim, group) ? "SSM" : "ASM"; - if (!json_rp_rows) - json_rp_rows = json_object_new_array(); - - json_row = json_object_new_object(); - json_object_string_addf( - json_row, "rpAddress", "%pI4", - &rp_info->rp.rpf_addr.u.prefix4); - if (rp_info->rp.source_nexthop.interface) - json_object_string_add( - json_row, "outboundInterface", - rp_info->rp.source_nexthop - .interface->name); - else - json_object_string_add( - json_row, "outboundInterface", - "Unknown"); - if (rp_info->i_am_rp) - json_object_boolean_true_add(json_row, - "iAmRP"); - else - json_object_boolean_false_add(json_row, - "iAmRP"); + if (range && !prefix_same(&rp_info->group, range)) + continue; - if (rp_info->plist) - json_object_string_add(json_row, - "prefixList", - rp_info->plist); - else - json_object_string_addf( - json_row, "group", "%pFX", - &rp_info->group); - json_object_string_add(json_row, "source", - source); + if (rp_info->rp_src == RP_SRC_STATIC) + strlcpy(source, "Static", sizeof(source)); + else if (rp_info->rp_src == RP_SRC_BSR) + strlcpy(source, "BSR", sizeof(source)); + else + strlcpy(source, "None", sizeof(source)); + if (uj) { + /* + * If we have moved on to a new RP then add the + * entry for the previous RP + */ + if (prev_rp_info && + prefix_cmp(&prev_rp_info->rp.rpf_addr, + &rp_info->rp.rpf_addr)) { + json_object_object_addf( + json, json_rp_rows, "%pFXh", + &prev_rp_info->rp.rpf_addr); + json_rp_rows = NULL; + } - json_object_array_add(json_rp_rows, json_row); - } else { - vty_out(vty, "%-15s ", - inet_ntop(AF_INET, - &rp_info->rp.rpf_addr.u - .prefix4, - buf, sizeof(buf))); - - if (rp_info->plist) - vty_out(vty, "%-18s ", rp_info->plist); - else - vty_out(vty, "%-18pFX ", - &rp_info->group); + if (!json_rp_rows) + json_rp_rows = json_object_new_array(); + + json_row = json_object_new_object(); + json_object_string_addf(json_row, "rpAddress", "%pFXh", + &rp_info->rp.rpf_addr); + if (rp_info->rp.source_nexthop.interface) + json_object_string_add( + json_row, "outboundInterface", + rp_info->rp.source_nexthop + .interface->name); + else + json_object_string_add(json_row, + "outboundInterface", + "Unknown"); + if (rp_info->i_am_rp) + json_object_boolean_true_add(json_row, "iAmRP"); + else + json_object_boolean_false_add(json_row, + "iAmRP"); - if (rp_info->rp.source_nexthop.interface) - vty_out(vty, "%-16s ", - rp_info->rp.source_nexthop - .interface->name); - else - vty_out(vty, "%-16s ", "(Unknown)"); + if (rp_info->plist) + json_object_string_add(json_row, "prefixList", + rp_info->plist); + else + json_object_string_addf(json_row, "group", + "%pFX", + &rp_info->group); + json_object_string_add(json_row, "source", source); + json_object_string_add(json_row, "groupType", + group_type); + + json_object_array_add(json_rp_rows, json_row); + } else { + vty_out(vty, "%-15pFXh ", &rp_info->rp.rpf_addr); - if (rp_info->i_am_rp) - vty_out(vty, "yes"); - else - vty_out(vty, "no"); + if (rp_info->plist) + vty_out(vty, "%-18s ", rp_info->plist); + else + vty_out(vty, "%-18pFX ", &rp_info->group); - vty_out(vty, "%14s\n", source); - } - prev_rp_info = rp_info; + if (rp_info->rp.source_nexthop.interface) + vty_out(vty, "%-16s ", + rp_info->rp.source_nexthop + .interface->name); + else + vty_out(vty, "%-16s ", "(Unknown)"); + + if (rp_info->i_am_rp) + vty_out(vty, "yes"); + else + vty_out(vty, "no"); + + vty_out(vty, "%14s", source); + vty_out(vty, "%6s\n", group_type); } + prev_rp_info = rp_info; } if (uj) { if (prev_rp_info && json_rp_rows) - json_object_object_add( - json, - inet_ntop(AF_INET, - &prev_rp_info->rp.rpf_addr.u.prefix4, - buf, sizeof(buf)), - json_rp_rows); + json_object_object_addf(json, json_rp_rows, "%pFXh", + &prev_rp_info->rp.rpf_addr); vty_json(vty, json); } @@ -1332,20 +1275,23 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr) struct pim_nexthop_cache pnc; for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { - if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) + if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + nht_p = rp_info->rp.rpf_addr; memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc)) continue; for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) { - if (nh_node->gate.ipv4.s_addr != INADDR_ANY) +#if PIM_IPV == 4 + if (!pim_addr_is_any(nh_node->gate.ipv4)) + continue; +#else + if (!pim_addr_is_any(nh_node->gate.ipv6)) continue; +#endif struct interface *ifp1 = if_lookup_by_index( nh_node->ifindex, pim->vrf->vrf_id); @@ -1353,18 +1299,16 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr) if (nbr->interface != ifp1) continue; +#if PIM_IPV == 4 nh_node->gate.ipv4 = nbr->source_addr; - if (PIM_DEBUG_PIM_NHT_RP) { - char str[PREFIX_STRLEN]; - char str1[INET_ADDRSTRLEN]; - pim_inet4_dump("", nbr->source_addr, - str1, sizeof(str1)); - pim_addr_dump("", &nht_p, str, - sizeof(str)); +#else + nh_node->gate.ipv6 = nbr->source_addr; +#endif + if (PIM_DEBUG_PIM_NHT_RP) zlog_debug( - "%s: addr %s new nexthop addr %s interface %s", - __func__, str, str1, ifp1->name); - } + "%s: addr %pFXh new nexthop addr %pPAs interface %s", + __func__, &nht_p, &nbr->source_addr, + ifp1->name); } } } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 595025e5c..04faeb5f2 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -47,15 +47,13 @@ void pim_rp_free(struct pim_instance *pim); void pim_rp_list_hash_clean(void *data); -int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, - struct prefix group, const char *plist, - enum rp_source rp_src_flag); -int pim_rp_del_config(struct pim_instance *pim, const char *rp, - const char *group, const char *plist); -int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, - struct prefix group, const char *plist, - enum rp_source rp_src_flag); -int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, +int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, + const char *plist, enum rp_source rp_src_flag); +void pim_rp_del_config(struct pim_instance *pim, pim_addr rp_addr, + const char *group, const char *plist); +int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, + const char *plist, enum rp_source rp_src_flag); +int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, struct prefix group, enum rp_source rp_src_flag); void pim_rp_prefix_list_update(struct pim_instance *pim, struct prefix_list *plist); @@ -65,23 +63,23 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, void pim_rp_setup(struct pim_instance *pim); -int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group); +int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group); void pim_rp_check_on_if_add(struct pim_interface *pim_ifp); void pim_i_am_rp_re_evaluate(struct pim_instance *pim); bool pim_rp_check_is_my_ip_address(struct pim_instance *pim, struct in_addr dest_addr); -int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, - struct in_addr source, struct in_addr group); +int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, + pim_addr source, pim_addr group); -struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group); +struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group); #define I_am_RP(P, G) pim_rp_i_am_rp ((P), (G)) #define RP(P, G) pim_rp_g ((P), (G)) -void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, - bool uj); +void pim_rp_show_information(struct pim_instance *pim, struct prefix *range, + struct vty *vty, bool uj); void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr); int pim_rp_list_cmp(void *v1, void *v2); struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index aa89431d3..cee542aa1 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -39,7 +39,7 @@ #include "pim_oil.h" #include "pim_mlag.h" -static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); +static pim_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); void pim_rpf_set_refresh_time(struct pim_instance *pim) { @@ -51,7 +51,7 @@ void pim_rpf_set_refresh_time(struct pim_instance *pim) } bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, - struct in_addr addr, int neighbor_needed) + pim_addr addr, int neighbor_needed) { struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; struct pim_neighbor *nbr = NULL; @@ -61,40 +61,33 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, int found = 0; int i = 0; +#if PIM_IPV == 4 /* * We should not attempt to lookup a * 255.255.255.255 address, since * it will never work */ - if (addr.s_addr == INADDR_NONE) + if (pim_addr_is_any(addr)) return false; +#endif - if ((nexthop->last_lookup.s_addr == addr.s_addr) - && (nexthop->last_lookup_time > pim->last_route_change_time)) { - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, addr_str, - sizeof(addr_str)); - char nexthop_str[PREFIX_STRLEN]; - pim_addr_dump("", &nexthop->mrib_nexthop_addr, - nexthop_str, sizeof(nexthop_str)); + if ((!pim_addr_cmp(nexthop->last_lookup, addr)) && + (nexthop->last_lookup_time > pim->last_route_change_time)) { + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: Using last lookup for %s at %lld, %" PRId64" addr %s", - __func__, addr_str, nexthop->last_lookup_time, - pim->last_route_change_time, nexthop_str); - } + "%s: Using last lookup for %pPAs at %lld, %" PRId64 + " addr %pFX", + __func__, &addr, nexthop->last_lookup_time, + pim->last_route_change_time, + &nexthop->mrib_nexthop_addr); pim->nexthop_lookups_avoided++; return true; } else { - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, addr_str, - sizeof(addr_str)); + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: Looking up: %s, last lookup time: %lld, %" PRId64, - __func__, addr_str, nexthop->last_lookup_time, + "%s: Looking up: %pPAs, last lookup time: %lld, %" PRId64, + __func__, &addr, nexthop->last_lookup_time, pim->last_route_change_time); - } } memset(nexthop_tab, 0, @@ -102,11 +95,9 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn( - "%s %s: could not find nexthop ifindex for address %s", - __FILE__, __func__, addr_str); + "%s %s: could not find nexthop ifindex for address %pPAs", + __FILE__, __func__, &addr); return false; } @@ -115,34 +106,26 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id); if (!ifp) { - if (PIM_DEBUG_ZEBRA) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, addr_str, - sizeof(addr_str)); + if (PIM_DEBUG_ZEBRA) zlog_debug( - "%s %s: could not find interface for ifindex %d (address %s)", + "%s %s: could not find interface for ifindex %d (address %pPAs)", __FILE__, __func__, first_ifindex, - addr_str); - } + &addr); i++; continue; } if (!ifp->info) { - if (PIM_DEBUG_ZEBRA) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, addr_str, - sizeof(addr_str)); + if (PIM_DEBUG_ZEBRA) zlog_debug( - "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", + "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %pPAs)", __func__, ifp->name, first_ifindex, - addr_str); - } + &addr); i++; } else if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) { - nbr = pim_neighbor_find( - ifp, nexthop_tab[i].nexthop_addr.u.prefix4); + nbr = pim_neighbor_find_prefix( + ifp, &nexthop_tab[i].nexthop_addr); if (PIM_DEBUG_PIM_TRACE_DETAIL) zlog_debug("ifp name: %s, pim nbr: %p", ifp->name, nbr); @@ -155,21 +138,13 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, } if (found) { - if (PIM_DEBUG_ZEBRA) { - char nexthop_str[PREFIX_STRLEN]; - char addr_str[INET_ADDRSTRLEN]; - pim_addr_dump("", - &nexthop_tab[i].nexthop_addr, nexthop_str, - sizeof(nexthop_str)); - pim_inet4_dump("", addr, addr_str, - sizeof(addr_str)); + if (PIM_DEBUG_ZEBRA) zlog_debug( - "%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d", - __FILE__, __func__, nexthop_str, addr_str, - ifp->name, first_ifindex, - nexthop_tab[i].route_metric, + "%s %s: found nexthop %pFX for address %pPAs: interface %s ifindex=%d metric=%d pref=%d", + __FILE__, __func__, + &nexthop_tab[i].nexthop_addr, &addr, ifp->name, + first_ifindex, nexthop_tab[i].route_metric, nexthop_tab[i].protocol_distance); - } /* update nexthop data */ nexthop->interface = ifp; nexthop->mrib_nexthop_addr = nexthop_tab[i].nexthop_addr; @@ -187,11 +162,13 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, static int nexthop_mismatch(const struct pim_nexthop *nh1, const struct pim_nexthop *nh2) { - return (nh1->interface != nh2->interface) - || (nh1->mrib_nexthop_addr.u.prefix4.s_addr - != nh2->mrib_nexthop_addr.u.prefix4.s_addr) - || (nh1->mrib_metric_preference != nh2->mrib_metric_preference) - || (nh1->mrib_route_metric != nh2->mrib_route_metric); + pim_addr nh_addr1 = pim_addr_from_prefix(&nh1->mrib_nexthop_addr); + pim_addr nh_addr2 = pim_addr_from_prefix(&nh2->mrib_nexthop_addr); + + return (nh1->interface != nh2->interface) || + (pim_addr_cmp(nh_addr1, nh_addr2)) || + (nh1->mrib_metric_preference != nh2->mrib_metric_preference) || + (nh1->mrib_route_metric != nh2->mrib_route_metric); } static void pim_rpf_cost_change(struct pim_instance *pim, @@ -230,11 +207,12 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct prefix src, grp; bool neigh_needed = true; uint32_t saved_mrib_route_metric; + pim_addr rpf_addr; if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) return PIM_RPF_OK; - if (up->upstream_addr.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->upstream_addr)) { zlog_debug("%s(%s): RP is not configured yet for %s", __func__, caller, up->sg_str); return PIM_RPF_OK; @@ -248,18 +226,12 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, old->rpf_addr = saved.rpf_addr; } - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; + pim_addr_to_prefix(&nht_p, up->upstream_addr); - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = up->upstream_addr; // RP or Src address - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&src, up->upstream_addr); // RP or Src address + pim_addr_to_prefix(&grp, up->sg.grp); - if ((up->sg.src.s_addr == INADDR_ANY && I_am_RP(pim, up->sg.grp)) || + if ((pim_addr_is_any(up->sg.src) && I_am_RP(pim, up->sg.grp)) || PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) neigh_needed = false; pim_find_or_track_nexthop(pim, &nht_p, up, NULL, NULL); @@ -271,8 +243,9 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, return PIM_RPF_FAILURE; } - rpf->rpf_addr.family = AF_INET; - rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up); + rpf_addr = pim_rpf_find_rpf_addr(up); + pim_addr_to_prefix(&rpf->rpf_addr, rpf_addr); + if (pim_rpf_addr_is_inaddr_any(rpf) && PIM_DEBUG_ZEBRA) { /* RPF'(S,G) not found */ zlog_debug("%s(%s): RPF'%s not found: won't send join upstream", @@ -283,19 +256,14 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, /* detect change in pim_nexthop */ if (nexthop_mismatch(&rpf->source_nexthop, &saved.source_nexthop)) { - if (PIM_DEBUG_ZEBRA) { - char nhaddr_str[PREFIX_STRLEN]; - pim_addr_dump("", - &rpf->source_nexthop.mrib_nexthop_addr, - nhaddr_str, sizeof(nhaddr_str)); - zlog_debug("%s(%s): (S,G)=%s source nexthop now is: interface=%s address=%s pref=%d metric=%d", + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s(%s): (S,G)=%s source nexthop now is: interface=%s address=%pFX pref=%d metric=%d", __func__, caller, up->sg_str, rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "", - nhaddr_str, + &rpf->source_nexthop.mrib_nexthop_addr, rpf->source_nexthop.mrib_metric_preference, rpf->source_nexthop.mrib_route_metric); - } pim_upstream_update_join_desired(pim, up); pim_upstream_update_could_assert(up); @@ -319,9 +287,8 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, } /* detect change in RPF'(S,G) */ - if (saved.rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr - || saved.source_nexthop - .interface != rpf->source_nexthop.interface) { + if (!prefix_same(&saved.rpf_addr, &rpf->rpf_addr) || + saved.source_nexthop.interface != rpf->source_nexthop.interface) { pim_rpf_cost_change(pim, up, saved_mrib_route_metric); return PIM_RPF_CHANGED; } @@ -349,13 +316,13 @@ void pim_upstream_rpf_clear(struct pim_instance *pim, if (up->rpf.source_nexthop.interface) { pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED); up->rpf.source_nexthop.interface = NULL; - up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = - PIM_NET_INADDR_ANY; + pim_addr_to_prefix(&up->rpf.source_nexthop.mrib_nexthop_addr, + PIMADDR_ANY); up->rpf.source_nexthop.mrib_metric_preference = router->infinite_assert_metric.metric_preference; up->rpf.source_nexthop.mrib_route_metric = router->infinite_assert_metric.route_metric; - up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY; + pim_addr_to_prefix(&up->rpf.rpf_addr, PIMADDR_ANY); pim_upstream_mroute_iif_update(up->channel_oil, __func__); } } @@ -375,18 +342,17 @@ void pim_upstream_rpf_clear(struct pim_instance *pim, packets should be coming and to which joins should be sent on the RP tree and SPT, respectively. */ -static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up) +static pim_addr pim_rpf_find_rpf_addr(struct pim_upstream *up) { struct pim_ifchannel *rpf_ch; struct pim_neighbor *neigh; - struct in_addr rpf_addr; + pim_addr rpf_addr; if (!up->rpf.source_nexthop.interface) { zlog_warn("%s: missing RPF interface for upstream (S,G)=%s", __func__, up->sg_str); - rpf_addr.s_addr = PIM_NET_INADDR_ANY; - return rpf_addr; + return PIMADDR_ANY; } rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface, &up->sg); @@ -398,38 +364,27 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up) /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */ - neigh = pim_if_find_neighbor( - up->rpf.source_nexthop.interface, - up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4); + pim_addr nhaddr; + + nhaddr = + pim_addr_from_prefix(&up->rpf.source_nexthop.mrib_nexthop_addr); + neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface, nhaddr); if (neigh) rpf_addr = neigh->source_addr; else - rpf_addr.s_addr = PIM_NET_INADDR_ANY; + rpf_addr = PIMADDR_ANY; return rpf_addr; } -int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf) -{ - switch (rpf->rpf_addr.family) { - case AF_INET: - return rpf->rpf_addr.u.prefix4.s_addr == INADDR_NONE; - case AF_INET6: - zlog_warn("%s: v6 Unimplmeneted", __func__); - return 1; - default: - return 0; - } -} - int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf) { + pim_addr rpf_addr = pim_addr_from_prefix(&rpf->rpf_addr); + switch (rpf->rpf_addr.family) { case AF_INET: - return rpf->rpf_addr.u.prefix4.s_addr == INADDR_ANY; case AF_INET6: - zlog_warn("%s: v6 Unimplmented", __func__); - return 1; + return pim_addr_is_any(rpf_addr); default: return 0; } @@ -447,7 +402,12 @@ unsigned int pim_rpf_hash_key(const void *arg) { const struct pim_nexthop_cache *r = arg; +#if PIM_IPV == 4 return jhash_1word(r->rpf.rpf_addr.u.prefix4.s_addr, 0); +#else + return jhash2(r->rpf.rpf_addr.u.prefix6.s6_addr32, + array_size(r->rpf.rpf_addr.u.prefix6.s6_addr32), 0); +#endif } bool pim_rpf_equal(const void *arg1, const void *arg2) diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index d6a8880ff..74aca43d5 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -58,13 +58,12 @@ unsigned int pim_rpf_hash_key(const void *arg); bool pim_rpf_equal(const void *arg1, const void *arg2); bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, - struct in_addr addr, int neighbor_needed); + pim_addr addr, int neighbor_needed); enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old, const char *caller); void pim_upstream_rpf_clear(struct pim_instance *pim, struct pim_upstream *up); -int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf); int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf); int pim_rpf_is_same(struct pim_rpf *rpf1, struct pim_rpf *rpf2); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 05b0f92a4..8619cc3f8 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -34,22 +34,28 @@ #include "vrf.h" #include "sockopt.h" #include "lib_errors.h" +#include "network.h" #include "pimd.h" #include "pim_mroute.h" +#include "pim_iface.h" #include "pim_sock.h" #include "pim_str.h" -/* GLOBAL VARS */ +#if PIM_IPV == 4 +#define setsockopt_iptos setsockopt_ipv4_tos +#define setsockopt_multicast_loop setsockopt_ipv4_multicast_loop +#else +#define setsockopt_iptos setsockopt_ipv6_tclass +#define setsockopt_multicast_loop setsockopt_ipv6_multicast_loop +#endif int pim_socket_raw(int protocol) { int fd; frr_with_privs(&pimd_privs) { - - fd = socket(AF_INET, SOCK_RAW, protocol); - + fd = socket(PIM_AF, SOCK_RAW, protocol); } if (fd < 0) { @@ -66,10 +72,16 @@ void pim_socket_ip_hdr(int fd) const int on = 1; frr_with_privs(&pimd_privs) { - +#if PIM_IPV == 4 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))) - zlog_err("%s: Could not turn on IP_HDRINCL option: %s", - __func__, safe_strerror(errno)); + zlog_err("%s: Could not turn on IP_HDRINCL option: %m", + __func__); +#else + if (setsockopt(fd, IPPROTO_IPV6, IPV6_HDRINCL, &on, sizeof(on))) + zlog_err( + "%s: Could not turn on IPV6_HDRINCL option: %m", + __func__); +#endif } } @@ -80,248 +92,256 @@ void pim_socket_ip_hdr(int fd) int pim_socket_bind(int fd, struct interface *ifp) { int ret = 0; -#ifdef SO_BINDTODEVICE +#ifdef SO_BINDTODEVICE frr_with_privs(&pimd_privs) { - ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifp->name, strlen(ifp->name)); - } - #endif return ret; } -int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, - uint8_t loop) +#if PIM_IPV == 4 +static inline int pim_setsockopt(int protocol, int fd, struct interface *ifp) { - int rcvbuf = 1024 * 1024 * 8; -#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX - struct ip_mreqn mreq; -#else - struct ip_mreq mreq; -#endif - int fd; - - fd = pim_socket_raw(protocol); - if (fd < 0) { - zlog_warn("Could not create multicast socket: errno=%d: %s", - errno, safe_strerror(errno)); - return PIM_SOCK_ERR_SOCKET; - } - -#ifdef SO_BINDTODEVICE - int ret; - - ret = pim_socket_bind(fd, ifp); - if (ret) { - close(fd); - zlog_warn( - "Could not set fd: %d for interface: %s to device", - fd, ifp->name); - return PIM_SOCK_ERR_BIND; - } -#else -/* XXX: use IP_PKTINFO / IP_RECVIF to emulate behaviour? Or change to - * only use 1 socket for all interfaces? */ -#endif + int one = 1; + int ttl = 1; - /* Needed to obtain destination address from recvmsg() */ - { #if defined(HAVE_IP_PKTINFO) - /* Linux and Solaris IP_PKTINFO */ - int opt = 1; - if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) { - zlog_warn( - "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); - } + /* Linux and Solaris IP_PKTINFO */ + if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one))) + zlog_warn("Could not set PKTINFO on socket fd=%d: %m", fd); #elif defined(HAVE_IP_RECVDSTADDR) - /* BSD IP_RECVDSTADDR */ - int opt = 1; - if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, - sizeof(opt))) { - zlog_warn( - "Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); - } + /* BSD IP_RECVDSTADDR */ + if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(one))) + zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: %m", + fd); #else - flog_err( - EC_LIB_DEVELOPMENT, - "%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", - __FILE__, __func__); - close(fd); - return PIM_SOCK_ERR_DSTADDR; + flog_err( + EC_LIB_DEVELOPMENT, + "Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()"); + close(fd); + return PIM_SOCK_ERR_DSTADDR; #endif - } - - /* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4. - * Message Formats)*/ + /* Set router alert (RFC 2113) for all IGMP messages (RFC + * 3376 4. Message Formats)*/ if (protocol == IPPROTO_IGMP) { uint8_t ra[4]; + ra[0] = 148; ra[1] = 4; ra[2] = 0; ra[3] = 0; if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) { zlog_warn( - "Could not set Router Alert Option on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); + "Could not set Router Alert Option on socket fd=%d: %m", + fd); close(fd); return PIM_SOCK_ERR_RA; } } - { - int reuse = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, - sizeof(reuse))) { - zlog_warn( - "Could not set Reuse Address Option on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); - close(fd); - return PIM_SOCK_ERR_REUSE; - } - } - - { - const int MTTL = 1; - int ttl = MTTL; - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, - sizeof(ttl))) { - zlog_warn( - "Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", - MTTL, fd, errno, safe_strerror(errno)); - close(fd); - return PIM_SOCK_ERR_TTL; - } + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))) { + zlog_warn("Could not set multicast TTL=%d on socket fd=%d: %m", + ttl, fd); + close(fd); + return PIM_SOCK_ERR_TTL; } - if (setsockopt_ipv4_multicast_loop(fd, loop)) { + if (setsockopt_ipv4_multicast_if(fd, PIMADDR_ANY, ifp->ifindex)) { zlog_warn( - "Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", - loop ? "enable" : "disable", fd, errno, - safe_strerror(errno)); + "Could not set Outgoing Interface Option on socket fd=%d: %m", + fd); close(fd); - return PIM_SOCK_ERR_LOOP; + return PIM_SOCK_ERR_IFACE; } - memset(&mreq, 0, sizeof(mreq)); -#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX - mreq.imr_ifindex = ifp->ifindex; -#else -/* - * I am not sure what to do here yet for *BSD - */ -// mreq.imr_interface = ifindex; -#endif + return 0; +} +#else /* PIM_IPV != 4 */ +static inline int pim_setsockopt(int protocol, int fd, struct interface *ifp) +{ + int ttl = 1; + struct ipv6_mreq mreq = {}; - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreq, + setsockopt_ipv6_pktinfo(fd, 1); + setsockopt_ipv6_multicast_hops(fd, ttl); + + mreq.ipv6mr_interface = ifp->ifindex; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &mreq, sizeof(mreq))) { zlog_warn( - "Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); + "Could not set Outgoing Interface Option on socket fd=%d: %m", + fd); close(fd); return PIM_SOCK_ERR_IFACE; } - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) - zlog_warn("%s: Failure to set buffer size to %d", __func__, - rcvbuf); + return 0; +} +#endif - { - long flags; +int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp, + uint8_t loop) +{ + int fd; + int ret; - flags = fcntl(fd, F_GETFL, 0); - if (flags < 0) { - zlog_warn( - "Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); - close(fd); - return PIM_SOCK_ERR_NONBLOCK_GETFL; - } + fd = pim_socket_raw(protocol); + if (fd < 0) { + zlog_warn("Could not create multicast socket: errno=%d: %s", + errno, safe_strerror(errno)); + return PIM_SOCK_ERR_SOCKET; + } - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { - zlog_warn( - "Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); - close(fd); - return PIM_SOCK_ERR_NONBLOCK_SETFL; - } + /* XXX: if SO_BINDTODEVICE isn't available, use IP_PKTINFO / IP_RECVIF + * to emulate behaviour? Or change to only use 1 socket for all + * interfaces? */ + ret = pim_socket_bind(fd, ifp); + if (ret) { + close(fd); + zlog_warn("Could not set fd: %d for interface: %s to device", + fd, ifp->name); + return PIM_SOCK_ERR_BIND; } - /* Set Tx socket DSCP byte */ - if (setsockopt_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL)) { - zlog_warn("can't set sockopt IP_TOS to PIM/IGMP socket %d: %s", - fd, safe_strerror(errno)); + set_nonblocking(fd); + sockopt_reuseaddr(fd); + setsockopt_so_recvbuf(fd, 8 * 1024 * 1024); + + ret = pim_setsockopt(protocol, fd, ifp); + if (ret) { + zlog_warn("pim_setsockopt failed for interface: %s to device ", + ifp->name); + return ret; + } + + /* leftover common sockopts */ + if (setsockopt_multicast_loop(fd, loop)) { + zlog_warn( + "Could not %s Multicast Loopback Option on socket fd=%d: %m", + loop ? "enable" : "disable", fd); + close(fd); + return PIM_SOCK_ERR_LOOP; } + /* Set Tx socket DSCP byte */ + if (setsockopt_iptos(fd, IPTOS_PREC_INTERNETCONTROL)) + zlog_warn("can't set sockopt IP[V6]_TOS to socket %d: %m", fd); + return fd; } -int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, - ifindex_t ifindex) +int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex, + struct pim_interface *pim_ifp) { int ret; -#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX - struct ip_mreqn opt; +#if PIM_IPV == 4 + ret = setsockopt_ipv4_multicast(fd, IP_ADD_MEMBERSHIP, ifaddr, + group.s_addr, ifindex); #else - struct ip_mreq opt; -#endif + struct ipv6_mreq opt; - opt.imr_multiaddr = group; - -#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX - opt.imr_address = ifaddr; - opt.imr_ifindex = ifindex; -#else - opt.imr_interface = ifaddr; + memcpy(&opt.ipv6mr_multiaddr, &group, 16); + opt.ipv6mr_interface = ifindex; + ret = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &opt, sizeof(opt)); #endif - ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt)); - if (ret) { - char group_str[INET_ADDRSTRLEN]; - char ifaddr_str[INET_ADDRSTRLEN]; - if (!inet_ntop(AF_INET, &group, group_str, sizeof(group_str))) - snprintf(group_str, sizeof(group_str), ""); - if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str, - sizeof(ifaddr_str))) - snprintf(ifaddr_str, sizeof(ifaddr_str), ""); + pim_ifp->igmp_ifstat_joins_sent++; + if (ret) { flog_err( EC_LIB_SOCKET, - "Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s", - fd, group_str, ifaddr_str, errno, safe_strerror(errno)); + "Failure socket joining fd=%d group %pPAs on interface address %pPAs: %m", + fd, &group, &ifaddr); + pim_ifp->igmp_ifstat_joins_failed++; return ret; } - if (PIM_DEBUG_TRACE) { - char group_str[INET_ADDRSTRLEN]; - char ifaddr_str[INET_ADDRSTRLEN]; - if (!inet_ntop(AF_INET, &group, group_str, sizeof(group_str))) - snprintf(group_str, sizeof(group_str), ""); - if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str, - sizeof(ifaddr_str))) - snprintf(ifaddr_str, sizeof(ifaddr_str), ""); - + if (PIM_DEBUG_TRACE) zlog_debug( - "Socket fd=%d joined group %s on interface address %s", - fd, group_str, ifaddr_str); + "Socket fd=%d joined group %pPAs on interface address %pPAs", + fd, &group, &ifaddr); + return ret; +} + +#if PIM_IPV == 4 +static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst, + ifindex_t *ifindex) +{ + struct cmsghdr *cmsg; + struct sockaddr_in *dst4 = (struct sockaddr_in *)dst; + + for (cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; + cmsg = CMSG_NXTHDR(mh, cmsg)) { +#ifdef HAVE_IP_PKTINFO + if ((cmsg->cmsg_level == IPPROTO_IP) && + (cmsg->cmsg_type == IP_PKTINFO)) { + struct in_pktinfo *i; + + i = (struct in_pktinfo *)CMSG_DATA(cmsg); + if (dst4) + dst4->sin_addr = i->ipi_addr; + if (ifindex) + *ifindex = i->ipi_ifindex; + + break; + } +#endif + +#ifdef HAVE_IP_RECVDSTADDR + if ((cmsg->cmsg_level == IPPROTO_IP) && + (cmsg->cmsg_type == IP_RECVDSTADDR)) { + struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg); + + if (dst4) + dst4->sin_addr = *i; + + break; + } +#endif + +#if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX) + if (cmsg->cmsg_type == IP_RECVIF) + if (ifindex) + *ifindex = CMSG_IFINDEX(cmsg); +#endif } +} +#else /* PIM_IPV != 4 */ +static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst, + ifindex_t *ifindex) +{ + struct cmsghdr *cmsg; + struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst; - return ret; + for (cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; + cmsg = CMSG_NXTHDR(mh, cmsg)) { + if ((cmsg->cmsg_level == IPPROTO_IPV6) && + (cmsg->cmsg_type == IPV6_PKTINFO)) { + struct in6_pktinfo *i; + + i = (struct in6_pktinfo *)CMSG_DATA(cmsg); + + if (dst6) + dst6->sin6_addr = i->ipi6_addr; + if (ifindex) + *ifindex = i->ipi6_ifindex; + break; + } + } } +#endif /* PIM_IPV != 4 */ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, - struct sockaddr_in *from, socklen_t *fromlen, - struct sockaddr_in *to, socklen_t *tolen, + struct sockaddr_storage *from, socklen_t *fromlen, + struct sockaddr_storage *to, socklen_t *tolen, ifindex_t *ifindex) { struct msghdr msgh; - struct cmsghdr *cmsg; struct iovec iov; char cbuf[1000]; int err; @@ -331,19 +351,12 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, * Use getsockname() to get sin_port. */ if (to) { - struct sockaddr_in si; - socklen_t si_len = sizeof(si); - - memset(&si, 0, sizeof(si)); - to->sin_family = AF_INET; - - pim_socket_getsockname(fd, (struct sockaddr *)&si, &si_len); + socklen_t to_len = sizeof(*to); - to->sin_port = si.sin_port; - to->sin_addr = si.sin_addr; + pim_socket_getsockname(fd, (struct sockaddr *)to, &to_len); if (tolen) - *tolen = sizeof(si); + *tolen = sizeof(*to); } memset(&msgh, 0, sizeof(struct msghdr)); @@ -364,66 +377,11 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, if (fromlen) *fromlen = msgh.msg_namelen; - for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msgh, cmsg)) { - -#ifdef HAVE_IP_PKTINFO - if ((cmsg->cmsg_level == IPPROTO_IP) - && (cmsg->cmsg_type == IP_PKTINFO)) { - struct in_pktinfo *i = - (struct in_pktinfo *)CMSG_DATA(cmsg); - if (to) - to->sin_addr = i->ipi_addr; - if (tolen) - *tolen = sizeof(struct sockaddr_in); - if (ifindex) - *ifindex = i->ipi_ifindex; - - break; - } -#endif - -#ifdef HAVE_IP_RECVDSTADDR - if ((cmsg->cmsg_level == IPPROTO_IP) - && (cmsg->cmsg_type == IP_RECVDSTADDR)) { - struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg); - if (to) - to->sin_addr = *i; - if (tolen) - *tolen = sizeof(struct sockaddr_in); - - break; - } -#endif - -#if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX) - if (cmsg->cmsg_type == IP_RECVIF) - if (ifindex) - *ifindex = CMSG_IFINDEX(cmsg); -#endif - - } /* for (cmsg) */ + cmsg_getdstaddr(&msgh, to, ifindex); return err; /* len */ } -int pim_socket_mcastloop_get(int fd) -{ - int loop; - socklen_t loop_len = sizeof(loop); - - if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &loop_len)) { - int e = errno; - zlog_warn( - "Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s", - fd, errno, safe_strerror(errno)); - errno = e; - return PIM_SOCK_ERR_LOOP; - } - - return loop; -} - int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen) { if (getsockname(fd, name, namelen)) { diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index 08b009932..2e9c043e8 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -38,17 +38,15 @@ int pim_socket_bind(int fd, struct interface *ifp); void pim_socket_ip_hdr(int fd); int pim_socket_raw(int protocol); -int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, +int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp, uint8_t loop); -int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, - ifindex_t ifindex); +int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex, + struct pim_interface *pim_ifp); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, - struct sockaddr_in *from, socklen_t *fromlen, - struct sockaddr_in *to, socklen_t *tolen, + struct sockaddr_storage *from, socklen_t *fromlen, + struct sockaddr_storage *to, socklen_t *tolen, ifindex_t *ifindex); -int pim_socket_mcastloop_get(int fd); - int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen); #endif /* PIM_SOCK_H */ diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c index 6c5883aeb..74310474d 100644 --- a/pimd/pim_ssm.c +++ b/pimd/pim_ssm.c @@ -28,10 +28,11 @@ #include "pimd.h" #include "pim_ssm.h" -#include "pim_zebra.h" +#include "pim_igmp.h" static void pim_ssm_range_reevaluate(struct pim_instance *pim) { +#if PIM_IPV == 4 /* 1. Setup register state for (S,G) entries if G has changed from SSM * to * ASM. @@ -50,6 +51,7 @@ static void pim_ssm_range_reevaluate(struct pim_instance *pim) */ pim_upstream_register_reevaluate(pim); igmp_source_forward_reevaluate_all(pim); +#endif } void pim_ssm_prefix_list_update(struct pim_instance *pim, @@ -83,23 +85,20 @@ static int pim_is_grp_standard_ssm(struct prefix *group) return prefix_match(&group_ssm, group); } -int pim_is_grp_ssm(struct pim_instance *pim, struct in_addr group_addr) +int pim_is_grp_ssm(struct pim_instance *pim, pim_addr group_addr) { struct pim_ssm *ssm; struct prefix group; struct prefix_list *plist; - memset(&group, 0, sizeof(group)); - group.family = AF_INET; - group.u.prefix4 = group_addr; - group.prefixlen = 32; + pim_addr_to_prefix(&group, group_addr); ssm = pim->ssm_info; if (!ssm->plist_name) { return pim_is_grp_standard_ssm(&group); } - plist = prefix_list_lookup(AFI_IP, ssm->plist_name); + plist = prefix_list_lookup(PIM_AFI, ssm->plist_name); if (!plist) return 0; diff --git a/pimd/pim_ssm.h b/pimd/pim_ssm.h index 7235ade8d..c6b697821 100644 --- a/pimd/pim_ssm.h +++ b/pimd/pim_ssm.h @@ -34,7 +34,7 @@ struct pim_ssm { void pim_ssm_prefix_list_update(struct pim_instance *pim, struct prefix_list *plist); -int pim_is_grp_ssm(struct pim_instance *pim, struct in_addr group_addr); +extern int pim_is_grp_ssm(struct pim_instance *pim, pim_addr group_addr); int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id, const char *plist_name); void *pim_ssm_init(void); diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index abd95e648..e43b46604 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -244,8 +244,8 @@ static void ssmpingd_sendto(struct ssmpingd_sock *ss, const uint8_t *buf, static int ssmpingd_read_msg(struct ssmpingd_sock *ss) { struct interface *ifp; - struct sockaddr_in from; - struct sockaddr_in to; + struct sockaddr_storage from; + struct sockaddr_storage to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); ifindex_t ifindex = -1; @@ -256,13 +256,11 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), &from, &fromlen, &to, &tolen, &ifindex); + if (len < 0) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", ss->source_addr, source_str, - sizeof(source_str)); zlog_warn( - "%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s", - __func__, source_str, ss->sock_fd, errno, + "%s: failure receiving ssmping for source %pI4 on fd=%d: errno=%d: %s", + __func__, &ss->source_addr, ss->sock_fd, errno, safe_strerror(errno)); return -1; } @@ -270,64 +268,45 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) ifp = if_lookup_by_index(ifindex, ss->pim->vrf->vrf_id); if (buf[0] != PIM_SSMPINGD_REQUEST) { - char source_str[INET_ADDRSTRLEN]; - char from_str[INET_ADDRSTRLEN]; - char to_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", ss->source_addr, source_str, - sizeof(source_str)); - pim_inet4_dump("", from.sin_addr, from_str, - sizeof(from_str)); - pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); zlog_warn( - "%s: bad ssmping type=%d from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", - __func__, buf[0], from_str, ntohs(from.sin_port), - to_str, ntohs(to.sin_port), + "%s: bad ssmping type=%d from %pSUp to %pSUp on interface %s ifindex=%d fd=%d src=%pI4", + __func__, buf[0], &from, &to, ifp ? ifp->name : "", ifindex, ss->sock_fd, - source_str); + &ss->source_addr); return 0; } if (PIM_DEBUG_SSMPINGD) { - char source_str[INET_ADDRSTRLEN]; - char from_str[INET_ADDRSTRLEN]; - char to_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", ss->source_addr, source_str, - sizeof(source_str)); - pim_inet4_dump("", from.sin_addr, from_str, - sizeof(from_str)); - pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); zlog_debug( - "%s: recv ssmping from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", - __func__, from_str, ntohs(from.sin_port), to_str, - ntohs(to.sin_port), ifp ? ifp->name : "", - ifindex, ss->sock_fd, source_str); + "%s: recv ssmping from %pSUp, to %pSUp, on interface %s ifindex=%d fd=%d src=%pI4", + __func__, &from, &to, ifp ? ifp->name : "", + ifindex, ss->sock_fd, &ss->source_addr); } buf[0] = PIM_SSMPINGD_REPLY; + struct sockaddr_in *from_addr = (struct sockaddr_in *)&from; + /* unicast reply */ - ssmpingd_sendto(ss, buf, len, from); + ssmpingd_sendto(ss, buf, len, *from_addr); /* multicast reply */ - from.sin_addr = ss->pim->ssmpingd_group_addr; - ssmpingd_sendto(ss, buf, len, from); + from_addr->sin_addr = ss->pim->ssmpingd_group_addr; + ssmpingd_sendto(ss, buf, len, *from_addr); return 0; } -static int ssmpingd_sock_read(struct thread *t) +static void ssmpingd_sock_read(struct thread *t) { struct ssmpingd_sock *ss; - int result; ss = THREAD_ARG(t); - result = ssmpingd_read_msg(ss); + ssmpingd_read_msg(ss); /* Keep reading */ ssmpingd_read_on(ss); - - return result; } static void ssmpingd_read_on(struct ssmpingd_sock *ss) diff --git a/pimd/pim_static.c b/pimd/pim_static.c index be06a25be..d3b31771a 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -43,8 +43,8 @@ static struct static_route *static_route_alloc(void) } static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif, - struct in_addr group, - struct in_addr source) + pim_addr group, + pim_addr source) { struct static_route *s_route; s_route = static_route_alloc(); @@ -54,10 +54,10 @@ static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif, s_route->iif = iif; s_route->oif_ttls[oif] = 1; s_route->c_oil.oil_ref_count = 1; - s_route->c_oil.oil.mfcc_origin = source; - s_route->c_oil.oil.mfcc_mcastgrp = group; - s_route->c_oil.oil.mfcc_parent = iif; - s_route->c_oil.oil.mfcc_ttls[oif] = 1; + *oil_origin(&s_route->c_oil) = source; + *oil_mcastgrp(&s_route->c_oil) = group; + *oil_parent(&s_route->c_oil) = iif; + oil_if_set(&s_route->c_oil, oif, 1); s_route->c_oil.oif_creation[oif] = pim_time_monotonic_sec(); return s_route; @@ -65,8 +65,7 @@ static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif, int pim_static_add(struct pim_instance *pim, struct interface *iif, - struct interface *oif, struct in_addr group, - struct in_addr source) + struct interface *oif, pim_addr group, pim_addr source) { struct listnode *node = NULL; struct static_route *s_route = NULL; @@ -97,20 +96,14 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, } for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) { - if (s_route->group.s_addr == group.s_addr - && s_route->source.s_addr == source.s_addr) { + if (!pim_addr_cmp(s_route->group, group) + && !pim_addr_cmp(s_route->source, source)) { if (s_route->iif == iif_index && s_route->oif_ttls[oif_index]) { - char gifaddr_str[INET_ADDRSTRLEN]; - char sifaddr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", group, gifaddr_str, - sizeof(gifaddr_str)); - pim_inet4_dump("", source, sifaddr_str, - sizeof(sifaddr_str)); zlog_warn( - "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)", + "%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%pPAs,source=%pPAs)", __FILE__, __func__, iif_index, - oif_index, gifaddr_str, sifaddr_str); + oif_index, &group, &source); return -3; } @@ -130,7 +123,7 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, * adding a new output interface */ if (s_route->iif == iif_index) { s_route->oif_ttls[oif_index] = 1; - s_route->c_oil.oil.mfcc_ttls[oif_index] = 1; + oil_if_set(&s_route->c_oil, oif_index, 1); s_route->c_oil.oif_creation[oif_index] = pim_time_monotonic_sec(); ++s_route->c_oil.oil_ref_count; @@ -147,8 +140,8 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, s_route->oif_ttls[iif_index] = 0; s_route->c_oil.oif_creation[iif_index] = 0; - s_route->c_oil.oil - .mfcc_ttls[iif_index] = 0; + oil_if_set(&s_route->c_oil, iif_index, + 0); --s_route->c_oil.oil_ref_count; } #endif @@ -158,8 +151,8 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, s_route->oif_ttls[oif_index] = 1; s_route->c_oil.oif_creation[oif_index] = pim_time_monotonic_sec(); - s_route->c_oil.oil - .mfcc_ttls[oif_index] = 1; + oil_if_set(&s_route->c_oil, oif_index, + 1); ++s_route->c_oil.oil_ref_count; } } @@ -178,16 +171,10 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, s_route->c_oil.pim = pim; if (pim_static_mroute_add(&s_route->c_oil, __func__)) { - char gifaddr_str[INET_ADDRSTRLEN]; - char sifaddr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", group, gifaddr_str, - sizeof(gifaddr_str)); - pim_inet4_dump("", source, sifaddr_str, - sizeof(sifaddr_str)); zlog_warn( - "%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)", - __FILE__, __func__, iif_index, oif_index, gifaddr_str, - sifaddr_str); + "%s %s: Unable to add static route(iif=%d,oif=%d,group=%pPAs,source=%pPAs)", + __FILE__, __func__, iif_index, oif_index, &group, + &source); /* Need to put s_route back to the way it was */ if (original_s_route) { @@ -213,24 +200,17 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, } if (PIM_DEBUG_STATIC) { - char gifaddr_str[INET_ADDRSTRLEN]; - char sifaddr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", group, gifaddr_str, - sizeof(gifaddr_str)); - pim_inet4_dump("", source, sifaddr_str, - sizeof(sifaddr_str)); zlog_debug( - "%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)", - __func__, iif_index, oif_index, gifaddr_str, - sifaddr_str); + "%s: Static route added(iif=%d,oif=%d,group=%pPAs,source=%pPAs)", + __func__, iif_index, oif_index, &group, + &source); } return 0; } int pim_static_del(struct pim_instance *pim, struct interface *iif, - struct interface *oif, struct in_addr group, - struct in_addr source) + struct interface *oif, pim_addr group, pim_addr source) { struct listnode *node = NULL; struct listnode *nextnode = NULL; @@ -249,11 +229,11 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif, for (ALL_LIST_ELEMENTS(pim->static_routes, node, nextnode, s_route)) { if (s_route->iif == iif_index - && s_route->group.s_addr == group.s_addr - && s_route->source.s_addr == source.s_addr + && !pim_addr_cmp(s_route->group, group) + && !pim_addr_cmp(s_route->source, source) && s_route->oif_ttls[oif_index]) { s_route->oif_ttls[oif_index] = 0; - s_route->c_oil.oil.mfcc_ttls[oif_index] = 0; + oil_if_set(&s_route->c_oil, oif_index, 0); --s_route->c_oil.oil_ref_count; /* If there are no more outputs then delete the whole @@ -263,19 +243,13 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif, ? pim_mroute_del(&s_route->c_oil, __func__) : pim_static_mroute_add(&s_route->c_oil, __func__)) { - char gifaddr_str[INET_ADDRSTRLEN]; - char sifaddr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", group, gifaddr_str, - sizeof(gifaddr_str)); - pim_inet4_dump("", source, sifaddr_str, - sizeof(sifaddr_str)); zlog_warn( - "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)", + "%s %s: Unable to remove static route(iif=%d,oif=%d,group=%pPAs,source=%pPAs)", __FILE__, __func__, iif_index, - oif_index, gifaddr_str, sifaddr_str); + oif_index, &group, &source); s_route->oif_ttls[oif_index] = 1; - s_route->c_oil.oil.mfcc_ttls[oif_index] = 1; + oil_if_set(&s_route->c_oil, oif_index, 1); ++s_route->c_oil.oil_ref_count; return -1; @@ -289,16 +263,10 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif, } if (PIM_DEBUG_STATIC) { - char gifaddr_str[INET_ADDRSTRLEN]; - char sifaddr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", group, gifaddr_str, - sizeof(gifaddr_str)); - pim_inet4_dump("", source, sifaddr_str, - sizeof(sifaddr_str)); zlog_debug( - "%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)", + "%s: Static route removed(iif=%d,oif=%d,group=%pPAs,source=%pPAs)", __func__, iif_index, oif_index, - gifaddr_str, sifaddr_str); + &group, &source); } break; @@ -306,16 +274,10 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif, } if (!node) { - char gifaddr_str[INET_ADDRSTRLEN]; - char sifaddr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", group, gifaddr_str, - sizeof(gifaddr_str)); - pim_inet4_dump("", source, sifaddr_str, - sizeof(sifaddr_str)); zlog_warn( - "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)", - __FILE__, __func__, iif_index, oif_index, gifaddr_str, - sifaddr_str); + "%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%pPAs,source=%pPAs)", + __FILE__, __func__, iif_index, oif_index, &group, + &source); return -3; } @@ -329,15 +291,11 @@ int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty, struct listnode *node; struct static_route *sroute; int count = 0; - char sbuf[INET_ADDRSTRLEN]; - char gbuf[INET_ADDRSTRLEN]; if (!pim_ifp) return 0; for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sroute)) { - pim_inet4_dump("", sroute->group, gbuf, sizeof(gbuf)); - pim_inet4_dump("", sroute->source, sbuf, sizeof(sbuf)); if (sroute->iif == pim_ifp->mroute_vif_index) { int i; for (i = 0; i < MAXVIFS; i++) @@ -345,14 +303,15 @@ int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty, struct interface *oifp = pim_if_find_by_vif_index(pim, i); - if (sroute->source.s_addr == INADDR_ANY) + if (pim_addr_is_any(sroute->source)) vty_out(vty, - " ip mroute %s %s\n", - oifp->name, gbuf); + " " PIM_AF_NAME " mroute %s %pPA\n", + oifp->name, &sroute->group); else vty_out(vty, - " ip mroute %s %s %s\n", - oifp->name, gbuf, sbuf); + " " PIM_AF_NAME " mroute %s %pPA %pPA\n", + oifp->name, &sroute->group, + &sroute->source); count++; } } diff --git a/pimd/pim_static.h b/pimd/pim_static.h index 953ec0a70..56bfbd4e4 100644 --- a/pimd/pim_static.h +++ b/pimd/pim_static.h @@ -26,8 +26,8 @@ struct static_route { /* Each static route is unique by these pair of addresses */ - struct in_addr group; - struct in_addr source; + pim_addr group; + pim_addr source; struct channel_oil c_oil; ifindex_t iif; @@ -37,11 +37,9 @@ struct static_route { void pim_static_route_free(struct static_route *s_route); int pim_static_add(struct pim_instance *pim, struct interface *iif, - struct interface *oif, struct in_addr group, - struct in_addr source); + struct interface *oif, pim_addr group, pim_addr source); int pim_static_del(struct pim_instance *pim, struct interface *iif, - struct interface *oif, struct in_addr group, - struct in_addr source); + struct interface *oif, pim_addr group, pim_addr source); int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty, struct interface *ifp); diff --git a/pimd/pim_str.c b/pimd/pim_str.c index 180ed69fd..8744d62d1 100644 --- a/pimd/pim_str.c +++ b/pimd/pim_str.c @@ -41,13 +41,3 @@ void pim_addr_dump(const char *onfail, struct prefix *p, char *buf, errno = save_errno; } - -char *pim_str_sg_dump(const pim_sgaddr *sg) -{ - static char sg_str[PIM_SG_LEN]; - - pim_str_sg_set(sg, sg_str); - - return sg_str; -} - diff --git a/pimd/pim_str.h b/pimd/pim_str.h index f6d209b79..be8b6a9f4 100644 --- a/pimd/pim_str.h +++ b/pimd/pim_str.h @@ -39,31 +39,9 @@ #define PIM_SG_LEN PREFIX_SG_STR_LEN #define pim_inet4_dump prefix_mcast_inet4_dump -static inline const char *pim_str_sg_set(const pim_sgaddr *sg, char *str) -{ - snprintfrr(str, PREFIX_SG_STR_LEN, "%pSG", sg); - return str; -} - -static inline void pim_addr_copy(pim_addr *dest, pim_addr *source) -{ - dest->s_addr = source->s_addr; -} - -static inline int pim_is_addr_any(pim_addr addr) -{ - return (addr.s_addr == INADDR_ANY); -} - -static inline int pim_addr_cmp(pim_addr addr1, pim_addr addr2) -{ - return IPV4_ADDR_CMP(&addr1, &addr2); -} - void pim_addr_dump(const char *onfail, struct prefix *p, char *buf, int buf_size); void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size); -char *pim_str_sg_dump(const pim_sgaddr *sg); #endif diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c new file mode 100644 index 000000000..838f11211 --- /dev/null +++ b/pimd/pim_tib.c @@ -0,0 +1,178 @@ +/* + * TIB (Tree Information Base) - just PIM <> IGMP/MLD glue for now + * Copyright (C) 2022 David Lamparter for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "pim_tib.h" + +#include "pimd.h" +#include "pim_iface.h" +#include "pim_upstream.h" +#include "pim_oil.h" +#include "pim_nht.h" + +static struct channel_oil * +tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif) +{ + struct pim_interface *pim_oif = oif->info; + int input_iface_vif_index = 0; + pim_addr vif_source; + struct prefix src, grp; + struct pim_nexthop nexthop; + struct pim_upstream *up = NULL; + + if (!pim_rp_set_upstream_addr(pim, &vif_source, sg.src, sg.grp)) { + /* no PIM RP - create a dummy channel oil */ + return pim_channel_oil_add(pim, &sg, __func__); + } + + pim_addr_to_prefix(&src, vif_source); // RP or Src addr + pim_addr_to_prefix(&grp, sg.grp); + + up = pim_upstream_find(pim, &sg); + if (up) { + memcpy(&nexthop, &up->rpf.source_nexthop, + sizeof(struct pim_nexthop)); + pim_ecmp_nexthop_lookup(pim, &nexthop, &src, &grp, 0); + if (nexthop.interface) + input_iface_vif_index = pim_if_find_vifindex_by_ifindex( + pim, nexthop.interface->ifindex); + } else + input_iface_vif_index = + pim_ecmp_fib_lookup_if_vif_index(pim, &src, &grp); + + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s: NHT %pSG vif_source %pPAs vif_index:%d", + __func__, &sg, &vif_source, input_iface_vif_index); + + if (input_iface_vif_index < 1) { + if (PIM_DEBUG_IGMP_TRACE) + zlog_debug( + "%s %s: could not find input interface for %pSG", + __FILE__, __func__, &sg); + + return pim_channel_oil_add(pim, &sg, __func__); + } + + /* + * Protect IGMP against adding looped MFC entries created by both + * source and receiver attached to the same interface. See TODO T22. + * Block only when the intf is non DR DR must create upstream. + */ + if ((input_iface_vif_index == pim_oif->mroute_vif_index) && + !(PIM_I_am_DR(pim_oif))) { + /* ignore request for looped MFC entry */ + if (PIM_DEBUG_IGMP_TRACE) + zlog_debug( + "%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d", + __func__, &sg, oif->name, + input_iface_vif_index); + + return NULL; + } + + return pim_channel_oil_add(pim, &sg, __func__); +} + +bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, + struct interface *oif, struct channel_oil **oilp) +{ + struct pim_interface *pim_oif = oif->info; + + if (!pim_oif) { + if (PIM_DEBUG_IGMP_TRACE) + zlog_debug("%s: multicast not enabled on oif=%s?", + __func__, oif->name); + return false; + } + + if (!*oilp) + *oilp = tib_sg_oil_setup(pim, sg, oif); + if (!*oilp) + return false; + + if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) { + int result; + + result = pim_channel_add_oif(*oilp, oif, + PIM_OIF_FLAG_PROTO_IGMP, __func__); + if (result) { + if (PIM_DEBUG_MROUTE) + zlog_warn("%s: add_oif() failed with return=%d", + __func__, result); + return false; + } + } else { + if (PIM_DEBUG_IGMP_TRACE) + zlog_debug( + "%s: %pSG was received on %s interface but we are not DR for that interface", + __func__, &sg, oif->name); + + return false; + } + /* + Feed IGMPv3-gathered local membership information into PIM + per-interface (S,G) state. + */ + if (!pim_ifchannel_local_membership_add(oif, &sg, false /*is_vxlan*/)) { + if (PIM_DEBUG_MROUTE) + zlog_warn( + "%s: Failure to add local membership for %pSG", + __func__, &sg); + + pim_channel_del_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_IGMP, + __func__); + return false; + } + + return true; +} + +void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg, + struct interface *oif, struct channel_oil **oilp) +{ + int result; + + /* + It appears that in certain circumstances that + igmp_source_forward_stop is called when IGMP forwarding + was not enabled in oif_flags for this outgoing interface. + Possibly because of multiple calls. When that happens, we + enter the below if statement and this function returns early + which in turn triggers the calling function to assert. + Making the call to pim_channel_del_oif and ignoring the return code + fixes the issue without ill effect, similar to + pim_forward_stop below. + */ + result = pim_channel_del_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_IGMP, + __func__); + if (result) { + if (PIM_DEBUG_IGMP_TRACE) + zlog_debug( + "%s: pim_channel_del_oif() failed with return=%d", + __func__, result); + return; + } + + /* + Feed IGMPv3-gathered local membership information into PIM + per-interface (S,G) state. + */ + pim_ifchannel_local_membership_del(oif, &sg); +} diff --git a/pimd/pim_tib.h b/pimd/pim_tib.h new file mode 100644 index 000000000..b320f4cde --- /dev/null +++ b/pimd/pim_tib.h @@ -0,0 +1,33 @@ +/* + * TIB (Tree Information Base) - just PIM <> IGMP/MLD glue for now + * Copyright (C) 2022 David Lamparter for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FRR_PIM_GLUE_H +#define _FRR_PIM_GLUE_H + +#include "pim_addr.h" + +struct pim_instance; +struct channel_oil; + +extern bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, + struct interface *oif, struct channel_oil **oilp); +extern void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg, + struct interface *oif, struct channel_oil **oilp); + +#endif /* _FRR_PIM_GLUE_H */ diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index a4f60e519..86403dd54 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -29,6 +29,12 @@ #include "pim_str.h" #include "pim_msg.h" +#if PIM_IPV == 4 +#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4 +#else +#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6 +#endif + uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value) { @@ -117,7 +123,23 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, * The unicast address as represented by the given Address Family * and Encoding Type. */ -int pim_encode_addr_ucast(uint8_t *buf, struct prefix *p) +int pim_encode_addr_ucast(uint8_t *buf, pim_addr addr) +{ + uint8_t *start = buf; + +#if PIM_IPV == 4 + *buf++ = PIM_MSG_ADDRESS_FAMILY_IPV4; +#else + *buf++ = PIM_MSG_ADDRESS_FAMILY_IPV6; +#endif + *buf++ = 0; + memcpy(buf, &addr, sizeof(addr)); + buf += sizeof(addr); + + return buf - start; +} + +int pim_encode_addr_ucast_prefix(uint8_t *buf, struct prefix *p) { switch (p->family) { case AF_INET: @@ -188,28 +210,22 @@ int pim_encode_addr_ucast(uint8_t *buf, struct prefix *p) * Contains the group address. */ int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope, - struct in_addr group) + pim_addr group) { + uint8_t *start = buf; uint8_t flags = 0; flags |= bidir << 8; flags |= scope; - switch (afi) { - case AFI_IP: - *buf = PIM_MSG_ADDRESS_FAMILY_IPV4; - ++buf; - *buf = 0; - ++buf; - *buf = flags; - ++buf; - *buf = 32; - ++buf; - memcpy(buf, &group, sizeof(struct in_addr)); - return group_ipv4_encoding_len; - default: - return 0; - } + *buf++ = PIM_MSG_ADDRESS_FAMILY; + *buf++ = 0; + *buf++ = flags; + *buf++ = sizeof(group) / 8; + memcpy(buf, &group, sizeof(group)); + buf += sizeof(group); + + return buf - start; } uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, @@ -248,7 +264,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, if (p->family != family) continue; - l_encode = pim_encode_addr_ucast(curr, p); + l_encode = pim_encode_addr_ucast_prefix(curr, p); curr += l_encode; option_len += l_encode; } @@ -274,15 +290,13 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, } static int check_tlv_length(const char *label, const char *tlv_name, - const char *ifname, struct in_addr src_addr, + const char *ifname, pim_addr src_addr, int correct_len, int option_len) { if (option_len != correct_len) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", - label, tlv_name, option_len, correct_len, src_str, + "%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %pPAs on interface %s", + label, tlv_name, option_len, correct_len, &src_addr, ifname); return -1; } @@ -290,49 +304,44 @@ static int check_tlv_length(const char *label, const char *tlv_name, return 0; } -static void check_tlv_redefinition_uint16( - const char *label, const char *tlv_name, const char *ifname, - struct in_addr src_addr, pim_hello_options options, - pim_hello_options opt_mask, uint16_t new, uint16_t old) +static void check_tlv_redefinition_uint16(const char *label, + const char *tlv_name, + const char *ifname, pim_addr src_addr, + pim_hello_options options, + pim_hello_options opt_mask, + uint16_t new, uint16_t old) { - if (PIM_OPTION_IS_SET(options, opt_mask)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (PIM_OPTION_IS_SET(options, opt_mask)) zlog_warn( - "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", - label, tlv_name, new, old, src_str, ifname); - } + "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s", + label, tlv_name, new, old, &src_addr, ifname); } -static void check_tlv_redefinition_uint32( - const char *label, const char *tlv_name, const char *ifname, - struct in_addr src_addr, pim_hello_options options, - pim_hello_options opt_mask, uint32_t new, uint32_t old) +static void check_tlv_redefinition_uint32(const char *label, + const char *tlv_name, + const char *ifname, pim_addr src_addr, + pim_hello_options options, + pim_hello_options opt_mask, + uint32_t new, uint32_t old) { - if (PIM_OPTION_IS_SET(options, opt_mask)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (PIM_OPTION_IS_SET(options, opt_mask)) zlog_warn( - "%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", - label, tlv_name, new, old, src_str, ifname); - } + "%s: PIM hello TLV redefined %s=%u old=%u from %pPAs on interface %s", + label, tlv_name, new, old, &src_addr, ifname); } static void check_tlv_redefinition_uint32_hex( const char *label, const char *tlv_name, const char *ifname, - struct in_addr src_addr, pim_hello_options options, + pim_addr src_addr, pim_hello_options options, pim_hello_options opt_mask, uint32_t new, uint32_t old) { - if (PIM_OPTION_IS_SET(options, opt_mask)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); + if (PIM_OPTION_IS_SET(options, opt_mask)) zlog_warn( - "%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", - label, tlv_name, new, old, src_str, ifname); - } + "%s: PIM hello TLV redefined %s=%08x old=%08x from %pPAs on interface %s", + label, tlv_name, new, old, &src_addr, ifname); } -int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_holdtime(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, const uint8_t *tlv_curr) @@ -356,7 +365,7 @@ int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, return 0; } -int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_lan_prune_delay(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, @@ -392,7 +401,7 @@ int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, return 0; } -int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_dr_priority(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, const uint8_t *tlv_curr) @@ -416,7 +425,7 @@ int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, return 0; } -int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_generation_id(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, const uint8_t *tlv_curr) @@ -441,7 +450,8 @@ int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, return 0; } -int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size) +int pim_parse_addr_ucast_prefix(struct prefix *p, const uint8_t *buf, + int buf_size) { const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ const uint8_t *addr; @@ -510,6 +520,25 @@ int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size) return addr - buf; } +int pim_parse_addr_ucast(pim_addr *out, const uint8_t *buf, int buf_size, + bool *wrong_af) +{ + struct prefix p; + int ret; + + ret = pim_parse_addr_ucast_prefix(&p, buf, buf_size); + if (ret < 0) + return ret; + + if (p.family != PIM_AF) { + *wrong_af = true; + return -5; + } + + memcpy(out, &p.u.val, sizeof(*out)); + return ret; +} + int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size) { const int grp_encoding_min_len = @@ -532,40 +561,32 @@ int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size) family = *addr++; type = *addr++; - //++addr; ++addr; /* skip b_reserved_z fields */ mask_len = *addr++; - switch (family) { - case PIM_MSG_ADDRESS_FAMILY_IPV4: - if (type) { - zlog_warn( - "%s: unknown group address encoding type=%d from", - __func__, type); - return -2; - } - - if ((addr + sizeof(struct in_addr)) > pastend) { - zlog_warn( - "%s: IPv4 group address overflow: left=%td needed=%zu from", - __func__, pastend - addr, - sizeof(struct in_addr)); - return -3; - } - - memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr)); - - addr += sizeof(struct in_addr); + if (type) { + zlog_warn("%s: unknown group address encoding type=%d from", + __func__, type); + return -2; + } - break; - default: { + if (family != PIM_MSG_ADDRESS_FAMILY) { zlog_warn( "%s: unknown group address encoding family=%d mask_len=%d from", __func__, family, mask_len); return -4; } + + if ((addr + sizeof(sg->grp)) > pastend) { + zlog_warn( + "%s: group address overflow: left=%td needed=%zu from", + __func__, pastend - addr, sizeof(sg->grp)); + return -3; } + memcpy(&sg->grp, addr, sizeof(sg->grp)); + addr += sizeof(sg->grp); + return addr - buf; } @@ -654,7 +675,7 @@ int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf, } \ } -int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_addr_list(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, const uint8_t *tlv_curr) @@ -670,20 +691,18 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, addr = tlv_curr; pastend = tlv_curr + option_len; while (addr < pastend) { - struct prefix tmp; + struct prefix tmp, src_pfx; int addr_offset; /* Parse ucast addr */ - addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr); + addr_offset = + pim_parse_addr_ucast_prefix(&tmp, addr, pastend - addr); if (addr_offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); zlog_warn( - "%s: pim_parse_addr_ucast() failure: from %s on %s", - __func__, src_str, ifname); + "%s: pim_parse_addr_ucast() failure: from %pPAs on %s", + __func__, &src_addr, ifname); FREE_ADDR_LIST(*hello_option_addr_list); return -1; } @@ -696,35 +715,28 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, switch (tmp.family) { case AF_INET: { char addr_str[INET_ADDRSTRLEN]; - char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("", tmp.u.prefix4, addr_str, sizeof(addr_str)); - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); zlog_debug( - "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", + "%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %pPAs on %s", __func__, *hello_option_addr_list ? ((int)listcount( - *hello_option_addr_list)) + *hello_option_addr_list)) : -1, - addr_str, src_str, ifname); + addr_str, &src_addr, ifname); } break; case AF_INET6: break; - default: { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); + default: zlog_debug( - "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", + "%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %pPAs on %s", __func__, *hello_option_addr_list ? ((int)listcount( - *hello_option_addr_list)) + *hello_option_addr_list)) : -1, - src_str, ifname); - } + &src_addr, ifname); } } @@ -732,16 +744,12 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, Exclude neighbor's primary address if incorrectly included in the secondary address list */ - if (tmp.family == AF_INET) { - if (tmp.u.prefix4.s_addr == src_addr.s_addr) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", src_addr, src_str, - sizeof(src_str)); - zlog_warn( - "%s: ignoring primary address in secondary list from %s on %s", - __func__, src_str, ifname); - continue; - } + pim_addr_to_prefix(&src_pfx, src_addr); + if (!prefix_cmp(&tmp, &src_pfx)) { + zlog_warn( + "%s: ignoring primary address in secondary list from %pPAs on %s", + __func__, &src_addr, ifname); + continue; } /* diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h index 1aa60d5db..64b3a0b6b 100644 --- a/pimd/pim_tlv.h +++ b/pimd/pim_tlv.h @@ -84,33 +84,37 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, struct list *ifconnected, int family); -int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_holdtime(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, const uint8_t *tlv_curr); -int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_lan_prune_delay(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, uint16_t option_len, const uint8_t *tlv_curr); -int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_dr_priority(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, const uint8_t *tlv_curr); -int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_generation_id(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, const uint8_t *tlv_curr); -int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, +int pim_tlv_parse_addr_list(const char *ifname, pim_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, const uint8_t *tlv_curr); -int pim_encode_addr_ucast(uint8_t *buf, struct prefix *p); +int pim_encode_addr_ucast(uint8_t *buf, pim_addr addr); +int pim_encode_addr_ucast_prefix(uint8_t *buf, struct prefix *p); int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope, - struct in_addr group); + pim_addr group); -int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size); +int pim_parse_addr_ucast(pim_addr *out, const uint8_t *buf, int buf_size, + bool *wrong_af); +int pim_parse_addr_ucast_prefix(struct prefix *out, const uint8_t *buf, + int buf_size); int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size); int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf, int buf_size); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index ef356213e..24833f5a6 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -101,18 +101,15 @@ static void pim_upstream_find_new_children(struct pim_instance *pim, { struct pim_upstream *child; - if ((up->sg.src.s_addr != INADDR_ANY) - && (up->sg.grp.s_addr != INADDR_ANY)) + if (!pim_addr_is_any(up->sg.src) && !pim_addr_is_any(up->sg.grp)) return; - if ((up->sg.src.s_addr == INADDR_ANY) - && (up->sg.grp.s_addr == INADDR_ANY)) + if (pim_addr_is_any(up->sg.src) && pim_addr_is_any(up->sg.grp)) return; frr_each (rb_pim_upstream, &pim->upstream_head, child) { - if ((up->sg.grp.s_addr != INADDR_ANY) - && (child->sg.grp.s_addr == up->sg.grp.s_addr) - && (child != up)) { + if (!pim_addr_is_any(up->sg.grp) && + !pim_addr_cmp(child->sg.grp, up->sg.grp) && (child != up)) { child->parent = up; listnode_add_sort(up->sources, child); if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) @@ -135,9 +132,9 @@ static struct pim_upstream *pim_upstream_find_parent(struct pim_instance *pim, struct pim_upstream *up = NULL; // (S,G) - if ((child->sg.src.s_addr != INADDR_ANY) - && (child->sg.grp.s_addr != INADDR_ANY)) { - any.src.s_addr = INADDR_ANY; + if (!pim_addr_is_any(child->sg.src) && + !pim_addr_is_any(child->sg.grp)) { + any.src = PIMADDR_ANY; up = pim_upstream_find(pim, &any); if (up) @@ -217,7 +214,7 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, if (up->join_state == PIM_UPSTREAM_JOINED) { pim_jp_agg_single_upstream_send(&up->rpf, up, 0); - if (up->sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->sg.src)) { /* if a (*, G) entry in the joined state is being * deleted we * need to notify MSDP */ @@ -229,7 +226,7 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, pim_jp_agg_upstream_verification(up, false); up->rpf.source_nexthop.interface = NULL; - if (up->sg.src.s_addr != INADDR_ANY) { + if (!pim_addr_is_any(up->sg.src)) { if (pim->upstream_sg_wheel) wheel_remove_item(pim->upstream_sg_wheel, up); notify_msdp = true; @@ -262,11 +259,9 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, * to INADDR_ANY. This is done in order to avoid de-registering for * 255.255.255.255 which is maintained for some reason.. */ - if (up->upstream_addr.s_addr != INADDR_ANY) { + if (!pim_addr_is_any(up->upstream_addr)) { /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; + pim_addr_to_prefix(&nht_p, up->upstream_addr); if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Deregister upstream %s addr %pFX with Zebra NHT", @@ -307,7 +302,7 @@ void pim_upstream_send_join(struct pim_upstream *up) pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */); } -static int on_join_timer(struct thread *t) +static void on_join_timer(struct thread *t) { struct pim_upstream *up; @@ -317,14 +312,14 @@ static int on_join_timer(struct thread *t) if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __func__, up->sg_str); - return 0; + return; } /* * In the case of a HFR we will not ahve anyone to send this to. */ if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) - return 0; + return; /* * Don't send the join if the outgoing interface is a loopback @@ -335,8 +330,6 @@ static int on_join_timer(struct thread *t) pim_upstream_send_join(up); join_timer_start(up); - - return 0; } static void join_timer_stop(struct pim_upstream *up) @@ -346,8 +339,8 @@ static void join_timer_stop(struct pim_upstream *up) THREAD_OFF(up->t_join_timer); if (up->rpf.source_nexthop.interface) - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface, + &up->rpf.rpf_addr); if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr); @@ -360,8 +353,8 @@ void join_timer_start(struct pim_upstream *up) struct pim_neighbor *nbr = NULL; if (up->rpf.source_nexthop.interface) { - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface, + &up->rpf.rpf_addr); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug( @@ -429,8 +422,8 @@ void pim_update_suppress_timers(uint32_t suppress_time) } } -void pim_upstream_join_suppress(struct pim_upstream *up, - struct in_addr rpf_addr, int holdtime) +void pim_upstream_join_suppress(struct pim_upstream *up, struct prefix rpf, + int holdtime) { long t_joinsuppress_msec; long join_timer_remain_msec = 0; @@ -452,8 +445,8 @@ void pim_upstream_join_suppress(struct pim_upstream *up, pim_time_timer_remain_msec(up->t_join_timer); else { /* Remove it from jp agg from the nbr for suppression */ - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface, + &up->rpf.rpf_addr); if (nbr) { join_timer_remain_msec = pim_time_timer_remain_msec(nbr->jp_timer); @@ -462,7 +455,8 @@ void pim_upstream_join_suppress(struct pim_upstream *up, if (PIM_DEBUG_PIM_TRACE) { char rpf_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", rpf_addr, rpf_str, sizeof(rpf_str)); + + pim_addr_dump("", &rpf, rpf_str, sizeof(rpf_str)); zlog_debug( "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec", __FILE__, __func__, up->sg_str, rpf_str, @@ -507,8 +501,8 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, /* upstream join tracked with neighbor jp timer */ struct pim_neighbor *nbr; - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface, + &up->rpf.rpf_addr); if (nbr) join_timer_remain_msec = pim_time_timer_remain_msec(nbr->jp_timer); @@ -519,8 +513,10 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, if (PIM_DEBUG_PIM_TRACE) { char rpf_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", up->rpf.rpf_addr.u.prefix4, rpf_str, - sizeof(rpf_str)); + + pim_addr_dump("", &up->rpf.rpf_addr, rpf_str, + sizeof(rpf_str)); + zlog_debug( "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec", debug_label, up->sg_str, rpf_str, @@ -656,7 +652,7 @@ void pim_upstream_update_use_rpt(struct pim_upstream *up, bool old_use_rpt; bool new_use_rpt; - if (up->sg.src.s_addr == INADDR_ANY) + if (pim_addr_is_any(up->sg.src)) return; old_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags); @@ -704,7 +700,7 @@ void pim_upstream_reeval_use_rpt(struct pim_instance *pim) struct pim_upstream *up; frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (up->sg.src.s_addr == INADDR_ANY) + if (pim_addr_is_any(up->sg.src)) continue; pim_upstream_update_use_rpt(up, true /*update_mroute*/); @@ -716,7 +712,7 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, { enum pim_upstream_state old_state = up->join_state; - if (up->upstream_addr.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->upstream_addr)) { if (PIM_DEBUG_PIM_EVENTS) zlog_debug("%s: RPF not configured for %s", __func__, up->sg_str); @@ -775,7 +771,7 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, * RFC 4601 Sec 4.5.7: * JoinDesired(S,G) -> False, set SPTbit to false. */ - if (up->sg.src.s_addr != INADDR_ANY) + if (!pim_addr_is_any(up->sg.src)) up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE; if (old_state == PIM_UPSTREAM_JOINED) @@ -827,19 +823,7 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, int pim_upstream_compare(const struct pim_upstream *up1, const struct pim_upstream *up2) { - if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr)) - return -1; - - if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr)) - return 1; - - if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr)) - return -1; - - if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr)) - return 1; - - return 0; + return pim_sgaddr_cmp(up1->sg, up2->sg); } void pim_upstream_fill_static_iif(struct pim_upstream *up, @@ -848,9 +832,8 @@ void pim_upstream_fill_static_iif(struct pim_upstream *up, up->rpf.source_nexthop.interface = incoming; /* reset other parameters to matched a connected incoming interface */ - up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET; - up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = - PIM_NET_INADDR_ANY; + pim_addr_to_prefix(&up->rpf.source_nexthop.mrib_nexthop_addr, + PIMADDR_ANY); up->rpf.source_nexthop.mrib_metric_preference = ZEBRA_CONNECT_DISTANCE_DEFAULT; up->rpf.source_nexthop.mrib_route_metric = 0; @@ -873,7 +856,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, up->pim = pim; up->sg = *sg; - pim_str_sg_set(sg, up->sg_str); + snprintfrr(up->sg_str, sizeof(up->sg_str), "%pSG", sg); if (ch) ch->upstream = up; @@ -889,7 +872,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, } up->parent = pim_upstream_find_parent(pim, up); - if (up->sg.src.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->sg.src)) { up->sources = list_new(); up->sources->cmp = (int (*)(void *, void *))pim_upstream_compare; @@ -910,20 +893,17 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE; up->rpf.source_nexthop.interface = NULL; - up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET; - up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = - PIM_NET_INADDR_ANY; + pim_addr_to_prefix(&up->rpf.source_nexthop.mrib_nexthop_addr, + PIMADDR_ANY); up->rpf.source_nexthop.mrib_metric_preference = router->infinite_assert_metric.metric_preference; up->rpf.source_nexthop.mrib_route_metric = router->infinite_assert_metric.route_metric; - up->rpf.rpf_addr.family = AF_INET; - up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY; - + pim_addr_to_prefix(&up->rpf.rpf_addr, PIMADDR_ANY); up->ifchannels = list_new(); up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare; - if (up->sg.src.s_addr != INADDR_ANY) { + if (!pim_addr_is_any(up->sg.src)) { wheel_add_item(pim->upstream_sg_wheel, up); /* Inherit the DF role from the parent (*, G) entry for @@ -952,7 +932,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) pim_upstream_keep_alive_timer_start( up, pim->keep_alive_time); - } else if (up->upstream_addr.s_addr != INADDR_ANY) { + } else if (!pim_addr_is_any(up->upstream_addr)) { pim_upstream_update_use_rpt(up, false /*update_mroute*/); rpf_result = pim_rpf_update(pim, up, NULL, __func__); @@ -979,7 +959,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (PIM_DEBUG_PIM_TRACE) { zlog_debug( - "%s: Created Upstream %s upstream_addr %pI4 ref count %d increment", + "%s: Created Upstream %s upstream_addr %pPAs ref count %d increment", __func__, up->sg_str, &up->upstream_addr, up->ref_count); } @@ -1092,8 +1072,8 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim, pim_sgaddr *sg, up->rpf.source_nexthop.interface->name : "Unknown" , found, up->ref_count); else - zlog_debug("%s(%s): (%s) failure to create", __func__, - name, pim_str_sg_dump(sg)); + zlog_debug("%s(%s): (%pSG) failure to create", __func__, + name, sg); } return up; @@ -1225,7 +1205,7 @@ bool pim_upstream_evaluate_join_desired(struct pim_instance *pim, empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up); /* (*,G) */ - if (up->sg.src.s_addr == INADDR_ANY) + if (pim_addr_is_any(up->sg.src)) return !empty_imm_oil; /* (S,G) */ @@ -1280,7 +1260,7 @@ void pim_upstream_update_join_desired(struct pim_instance *pim, it so that it expires after t_override seconds. */ void pim_upstream_rpf_genid_changed(struct pim_instance *pim, - struct in_addr neigh_addr) + pim_addr neigh_addr) { struct pim_upstream *up; @@ -1288,26 +1268,24 @@ void pim_upstream_rpf_genid_changed(struct pim_instance *pim, * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (PIM_DEBUG_PIM_TRACE) { - char neigh_str[INET_ADDRSTRLEN]; - char rpf_addr_str[PREFIX_STRLEN]; - pim_inet4_dump("", neigh_addr, neigh_str, - sizeof(neigh_str)); - pim_addr_dump("", &up->rpf.rpf_addr, rpf_addr_str, - sizeof(rpf_addr_str)); + pim_addr rpf_addr; + + rpf_addr = pim_addr_from_prefix(&up->rpf.rpf_addr); + + if (PIM_DEBUG_PIM_TRACE) zlog_debug( - "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s", - __func__, neigh_str, up->sg_str, pim->vrf->name, + "%s: matching neigh=%pPA against upstream (S,G)=%s[%s] joined=%d rpf_addr=%pPA", + __func__, &neigh_addr, up->sg_str, + pim->vrf->name, up->join_state == PIM_UPSTREAM_JOINED, - rpf_addr_str); - } + &rpf_addr); /* consider only (S,G) upstream in Joined state */ if (up->join_state != PIM_UPSTREAM_JOINED) continue; /* match RPF'(S,G)=neigh_addr */ - if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr) + if (pim_addr_cmp(rpf_addr, neigh_addr)) continue; pim_upstream_join_timer_decrease_to_t_override( @@ -1501,7 +1479,7 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc( return up; } -static int pim_upstream_keep_alive_timer(struct thread *t) +static void pim_upstream_keep_alive_timer(struct thread *t) { struct pim_upstream *up; @@ -1510,10 +1488,9 @@ static int pim_upstream_keep_alive_timer(struct thread *t) /* pull the stats and re-check */ if (pim_upstream_sg_running_proc(up)) /* kat was restarted because of new activity */ - return 0; + return; pim_upstream_keep_alive_timer_proc(up); - return 0; } void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time) @@ -1535,15 +1512,15 @@ void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time) } /* MSDP on RP needs to know if a source is registerable to this RP */ -static int pim_upstream_msdp_reg_timer(struct thread *t) +static void pim_upstream_msdp_reg_timer(struct thread *t) { struct pim_upstream *up = THREAD_ARG(t); struct pim_instance *pim = up->channel_oil->pim; /* source is no longer active - pull the SA from MSDP's cache */ pim_msdp_sa_local_del(pim, &up->sg); - return 1; } + void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) { THREAD_OFF(up->t_msdp_reg_timer); @@ -1721,7 +1698,7 @@ const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str, return state_str; } -static int pim_upstream_register_stop_timer(struct thread *t) +static void pim_upstream_register_stop_timer(struct thread *t) { struct pim_interface *pim_ifp; struct pim_instance *pim; @@ -1754,7 +1731,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) zlog_debug("%s: up %s RPF is not present", __func__, up->sg_str); up->reg_state = PIM_REG_NOINFO; - return 0; + return; } pim_ifp = up->rpf.source_nexthop.interface->info; @@ -1764,7 +1741,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) "%s: Interface: %s is not configured for pim", __func__, up->rpf.source_nexthop.interface->name); - return 0; + return; } up->reg_state = PIM_REG_JOIN_PENDING; pim_upstream_start_register_stop_timer(up, 1); @@ -1776,15 +1753,13 @@ static int pim_upstream_register_stop_timer(struct thread *t) zlog_debug( "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __func__); - return 0; + return; } pim_null_register_send(up); break; case PIM_REG_NOINFO: break; } - - return 0; } void pim_upstream_start_register_stop_timer(struct pim_upstream *up, @@ -1929,7 +1904,7 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim) * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (up->upstream_addr.s_addr == INADDR_ANY) { + if (pim_addr_is_any(up->upstream_addr)) { if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: RP not configured for Upstream %s", @@ -1961,7 +1936,7 @@ unsigned int pim_upstream_hash_key(const void *arg) { const struct pim_upstream *up = arg; - return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0); + return pim_sgaddr_hash(up->sg, 0); } void pim_upstream_terminate(struct pim_instance *pim) @@ -1984,11 +1959,7 @@ bool pim_upstream_equal(const void *arg1, const void *arg2) const struct pim_upstream *up1 = (const struct pim_upstream *)arg1; const struct pim_upstream *up2 = (const struct pim_upstream *)arg2; - if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) - && (up1->sg.src.s_addr == up2->sg.src.s_addr)) - return true; - - return false; + return !pim_sgaddr_cmp(up1->sg, up2->sg); } /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines @@ -2020,7 +1991,7 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up) return false; pim_ifp = ifp->info; - if (pim_ifp->mroute_vif_index != c_oil->oil.mfcc_parent) + if (pim_ifp->mroute_vif_index != *oil_parent(c_oil)) return false; if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, @@ -2131,7 +2102,7 @@ void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim) struct pim_upstream *up; frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (up->sg.src.s_addr != INADDR_ANY) + if (!pim_addr_is_any(up->sg.src)) continue; if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) @@ -2172,13 +2143,10 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim, struct prefix g; enum prefix_list_type apply_new; - np = prefix_list_lookup(AFI_IP, nlist); - - g.family = AF_INET; - g.prefixlen = IPV4_MAX_BITLEN; + np = prefix_list_lookup(PIM_AFI, nlist); frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (up->sg.src.s_addr != INADDR_ANY) + if (!pim_addr_is_any(up->sg.src)) continue; if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) @@ -2189,7 +2157,7 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim, PIM_OIF_FLAG_PROTO_IGMP, __func__); continue; } - g.u.prefix4 = up->sg.grp; + pim_addr_to_prefix(&g, up->sg.grp); apply_new = prefix_list_apply(np, &g); if (apply_new == PREFIX_DENY) pim_channel_add_oif(up->channel_oil, pim->regiface, diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 25ff3bffe..8feffb8fd 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -317,8 +317,8 @@ void pim_upstream_update_join_desired(struct pim_instance *pim, struct pim_upstream *up); void pim_update_suppress_timers(uint32_t suppress_time); -void pim_upstream_join_suppress(struct pim_upstream *up, - struct in_addr rpf_addr, int holdtime); +void pim_upstream_join_suppress(struct pim_upstream *up, struct prefix rpf, + int holdtime); void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, struct pim_upstream *up); @@ -326,7 +326,7 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, void pim_upstream_join_timer_restart(struct pim_upstream *up, struct pim_rpf *old); void pim_upstream_rpf_genid_changed(struct pim_instance *pim, - struct in_addr neigh_addr); + pim_addr neigh_addr); void pim_upstream_rpf_interface_changed(struct pim_upstream *up, struct interface *old_rpf_ifp); diff --git a/pimd/pim_util.c b/pimd/pim_util.c index decc491ed..4b67dbf1b 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -139,7 +139,7 @@ int pim_is_group_224_4(struct in_addr group_addr) return prefix_match(&group_all, &group); } -bool pim_is_group_filtered(struct pim_interface *pim_ifp, struct in_addr *grp) +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp) { struct prefix grp_pfx; struct prefix_list *pl; @@ -147,10 +147,22 @@ bool pim_is_group_filtered(struct pim_interface *pim_ifp, struct in_addr *grp) if (!pim_ifp->boundary_oil_plist) return false; - grp_pfx.family = AF_INET; - grp_pfx.prefixlen = IPV4_MAX_BITLEN; - grp_pfx.u.prefix4 = *grp; + pim_addr_to_prefix(&grp_pfx, *grp); - pl = prefix_list_lookup(AFI_IP, pim_ifp->boundary_oil_plist); + pl = prefix_list_lookup(PIM_AFI, pim_ifp->boundary_oil_plist); return pl ? prefix_list_apply(pl, &grp_pfx) == PREFIX_DENY : false; } + + +/* This function returns all multicast group */ +int pim_get_all_mcast_group(struct prefix *prefix) +{ +#if PIM_IPV == 4 + if (!str2prefix("224.0.0.0/4", prefix)) + return 0; +#else + if (!str2prefix("FF00::0/8", prefix)) + return 0; +#endif + return 1; +} diff --git a/pimd/pim_util.h b/pimd/pim_util.h index c66dd7b66..a4362bef9 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -35,5 +35,6 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size); int pim_is_group_224_0_0_0_24(struct in_addr group_addr); int pim_is_group_224_4(struct in_addr group_addr); -bool pim_is_group_filtered(struct pim_interface *pim_ifp, struct in_addr *grp); +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp); +int pim_get_all_mcast_group(struct prefix *prefix); #endif /* PIM_UTIL_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 8c0132a9a..6de3a04b6 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -193,30 +193,30 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) if (pim->vrf->vrf_id == VRF_DEFAULT) { if (router->register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) { - vty_out(vty, "%sip pim register-suppress-time %d\n", - spaces, router->register_suppress_time); + vty_out(vty, "%s" PIM_AF_NAME " pim register-suppress-time %d\n", + spaces, router->register_suppress_time); ++writes; } if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) { - vty_out(vty, "%sip pim join-prune-interval %d\n", + vty_out(vty, "%s" PIM_AF_NAME " pim join-prune-interval %d\n", spaces, router->t_periodic); ++writes; } if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) { - vty_out(vty, "%sip pim packets %d\n", spaces, + vty_out(vty, "%s" PIM_AF_NAME " pim packets %d\n", spaces, router->packet_process); ++writes; } } if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) { - vty_out(vty, "%sip pim keep-alive-timer %d\n", spaces, - pim->keep_alive_time); + vty_out(vty, "%s" PIM_AF_NAME " pim keep-alive-timer %d\n", + spaces, pim->keep_alive_time); ++writes; } if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) { - vty_out(vty, "%sip pim rp keep-alive-timer %d\n", spaces, - pim->rp_keep_alive_time); + vty_out(vty, "%s" PIM_AF_NAME " pim rp keep-alive-timer %d\n", + spaces, pim->rp_keep_alive_time); ++writes; } if (ssm->plist_name) { @@ -232,11 +232,11 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) if (pim->spt.switchover == PIM_SPT_INFINITY) { if (pim->spt.plist) vty_out(vty, - "%sip pim spt-switchover infinity-and-beyond prefix-list %s\n", + "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond prefix-list %s\n", spaces, pim->spt.plist); else vty_out(vty, - "%sip pim spt-switchover infinity-and-beyond\n", + "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond\n", spaces); ++writes; } @@ -281,6 +281,134 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) return writes; } +#if PIM_IPV == 4 +static int pim_igmp_config_write(struct vty *vty, int writes, + struct pim_interface *pim_ifp) +{ + /* IF ip igmp */ + if (PIM_IF_TEST_IGMP(pim_ifp->options)) { + vty_out(vty, " ip igmp\n"); + ++writes; + } + + /* ip igmp version */ + if (pim_ifp->igmp_version != IGMP_DEFAULT_VERSION) { + vty_out(vty, " ip igmp version %d\n", pim_ifp->igmp_version); + ++writes; + } + + /* IF ip igmp query-max-response-time */ + if (pim_ifp->gm_query_max_response_time_dsec != + IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) { + vty_out(vty, " ip igmp query-max-response-time %d\n", + pim_ifp->gm_query_max_response_time_dsec); + ++writes; + } + + /* IF ip igmp query-interval */ + if (pim_ifp->gm_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL) { + vty_out(vty, " ip igmp query-interval %d\n", + pim_ifp->gm_default_query_interval); + ++writes; + } + + /* IF ip igmp last-member_query-count */ + if (pim_ifp->gm_last_member_query_count != + IGMP_DEFAULT_ROBUSTNESS_VARIABLE) { + vty_out(vty, " ip igmp last-member-query-count %d\n", + pim_ifp->gm_last_member_query_count); + ++writes; + } + + /* IF ip igmp last-member_query-interval */ + if (pim_ifp->gm_specific_query_max_response_time_dsec != + IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) { + vty_out(vty, " ip igmp last-member-query-interval %d\n", + pim_ifp->gm_specific_query_max_response_time_dsec); + ++writes; + } + + /* IF ip igmp join */ + if (pim_ifp->gm_join_list) { + struct listnode *node; + struct gm_join *ij; + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) { + char group_str[INET_ADDRSTRLEN]; + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("", ij->group_addr, group_str, + sizeof(group_str)); + if (ij->source_addr.s_addr == INADDR_ANY) { + vty_out(vty, " ip igmp join %s\n", group_str); + } else { + inet_ntop(AF_INET, &ij->source_addr, source_str, + sizeof(source_str)); + vty_out(vty, " ip igmp join %s %s\n", group_str, + source_str); + } + ++writes; + } + } + + return writes; +} +#endif + +int pim_config_write(struct vty *vty, int writes, struct interface *ifp, + struct pim_instance *pim) +{ + struct pim_interface *pim_ifp = ifp->info; + + if (PIM_IF_TEST_PIM(pim_ifp->options)) { + vty_out(vty, " " PIM_AF_NAME " pim\n"); + ++writes; + } + + /* IF ip pim drpriority */ + if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) { + vty_out(vty, " " PIM_AF_NAME " pim drpriority %u\n", + pim_ifp->pim_dr_priority); + ++writes; + } + + /* IF ip pim hello */ + if (pim_ifp->pim_hello_period != PIM_DEFAULT_HELLO_PERIOD) { + vty_out(vty, " " PIM_AF_NAME " pim hello %d", pim_ifp->pim_hello_period); + if (pim_ifp->pim_default_holdtime != -1) + vty_out(vty, " %d", pim_ifp->pim_default_holdtime); + vty_out(vty, "\n"); + ++writes; + } + +#if PIM_IPV == 4 + writes += pim_igmp_config_write(vty, writes, pim_ifp); +#endif + + /* update source */ + if (!pim_addr_is_any(pim_ifp->update_source)) { + vty_out(vty, " " PIM_AF_NAME " pim use-source %pPA\n", + &pim_ifp->update_source); + ++writes; + } + + if (pim_ifp->activeactive) + vty_out(vty, " " PIM_AF_NAME " pim active-active\n"); + + /* boundary */ + if (pim_ifp->boundary_oil_plist) { + vty_out(vty, " " PIM_AF_NAME " multicast boundary oil %s\n", + pim_ifp->boundary_oil_plist); + ++writes; + } + + writes += pim_static_write_mroute(pim, vty, ifp); + pim_bsm_write_config(vty, ifp); + ++writes; + pim_bfd_write_config(vty, ifp); + ++writes; + + return writes; +} + int pim_interface_config_write(struct vty *vty) { struct pim_instance *pim; @@ -312,147 +440,10 @@ int pim_interface_config_write(struct vty *vty) } if (ifp->info) { - struct pim_interface *pim_ifp = ifp->info; - - if (PIM_IF_TEST_PIM(pim_ifp->options)) { - vty_out(vty, " ip pim\n"); - ++writes; - } - - /* IF ip pim drpriority */ - if (pim_ifp->pim_dr_priority - != PIM_DEFAULT_DR_PRIORITY) { - vty_out(vty, " ip pim drpriority %u\n", - pim_ifp->pim_dr_priority); - ++writes; - } - - /* IF ip pim hello */ - if (pim_ifp->pim_hello_period - != PIM_DEFAULT_HELLO_PERIOD) { - vty_out(vty, " ip pim hello %d", - pim_ifp->pim_hello_period); - if (pim_ifp->pim_default_holdtime != -1) - vty_out(vty, " %d", - pim_ifp->pim_default_holdtime); - vty_out(vty, "\n"); - ++writes; - } - - /* update source */ - if (PIM_INADDR_ISNOT_ANY( - pim_ifp->update_source)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - pim_ifp->update_source, - src_str, - sizeof(src_str)); - vty_out(vty, " ip pim use-source %s\n", - src_str); - ++writes; - } - - /* IF ip igmp */ - if (PIM_IF_TEST_IGMP(pim_ifp->options)) { - vty_out(vty, " ip igmp\n"); - ++writes; - } - - /* ip igmp version */ - if (pim_ifp->igmp_version - != IGMP_DEFAULT_VERSION) { - vty_out(vty, " ip igmp version %d\n", - pim_ifp->igmp_version); - ++writes; - } - - /* IF ip igmp query-max-response-time */ - if (pim_ifp->gm_query_max_response_time_dsec != - IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) { - vty_out(vty, - " ip igmp query-max-response-time %d\n", - pim_ifp->gm_query_max_response_time_dsec); - ++writes; - } - - /* IF ip igmp query-interval */ - if (pim_ifp->gm_default_query_interval != - IGMP_GENERAL_QUERY_INTERVAL) { - vty_out(vty, - " ip igmp query-interval %d\n", - pim_ifp->gm_default_query_interval); - ++writes; - } - - /* IF ip igmp last-member_query-count */ - if (pim_ifp->gm_last_member_query_count != - IGMP_DEFAULT_ROBUSTNESS_VARIABLE) { - vty_out(vty, - " ip igmp last-member-query-count %d\n", - pim_ifp->gm_last_member_query_count); - ++writes; - } - - /* IF ip igmp last-member_query-interval */ - if (pim_ifp->gm_specific_query_max_response_time_dsec != - IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) { - vty_out(vty, - " ip igmp last-member-query-interval %d\n", - pim_ifp->gm_specific_query_max_response_time_dsec); - ++writes; - } - - /* IF ip igmp join */ - if (pim_ifp->gm_join_list) { - struct listnode *node; - struct gm_join *ij; - for (ALL_LIST_ELEMENTS_RO( - pim_ifp->gm_join_list, - node, ij)) { - char group_str[INET_ADDRSTRLEN]; - char source_str - [INET_ADDRSTRLEN]; - pim_inet4_dump( - "", - ij->group_addr, - group_str, - sizeof(group_str)); - if (ij->source_addr.s_addr == INADDR_ANY) { - vty_out(vty, - " ip igmp join %s\n", - group_str); - } else { - inet_ntop(AF_INET, - &ij->source_addr, - source_str, - sizeof(source_str)); - vty_out(vty, - " ip igmp join %s %s\n", - group_str, source_str); - } - ++writes; - } - } - - if (pim_ifp->activeactive) - vty_out(vty, " ip pim active-active\n"); - - /* boundary */ - if (pim_ifp->boundary_oil_plist) { - vty_out(vty, - " ip multicast boundary oil %s\n", - pim_ifp->boundary_oil_plist); - ++writes; - } - - writes += - pim_static_write_mroute(pim, vty, ifp); - pim_bsm_write_config(vty, ifp); - ++writes; - pim_bfd_write_config(vty, ifp); - ++writes; + pim_config_write(vty, writes, ifp, pim); } if_vty_config_end(vty); + ++writes; } } diff --git a/pimd/pim_vty.h b/pimd/pim_vty.h index 22ac3333e..c192ba3bb 100644 --- a/pimd/pim_vty.h +++ b/pimd/pim_vty.h @@ -25,5 +25,6 @@ int pim_debug_config_write(struct vty *vty); int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty); int pim_interface_config_write(struct vty *vty); - +int pim_config_write(struct vty *vty, int writes, struct interface *ifp, + struct pim_instance *pim); #endif /* PIM_VTY_H */ diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 3aa8bacb8..5e55b9f9c 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -184,11 +184,10 @@ void pim_vxlan_update_sg_reg_state(struct pim_instance *pim, pim_vxlan_del_work(vxlan_sg); } -static int pim_vxlan_work_timer_cb(struct thread *t) +static void pim_vxlan_work_timer_cb(struct thread *t) { pim_vxlan_do_reg_work(); pim_vxlan_work_timer_setup(true /* start */); - return 0; } /* global 1second timer used for periodic processing */ @@ -354,9 +353,7 @@ static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg) * iif */ if (!PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) { - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; + pim_addr_to_prefix(&nht_p, up->upstream_addr); pim_delete_tracked_nexthop(vxlan_sg->pim, &nht_p, up, NULL); } @@ -720,8 +717,7 @@ static unsigned int pim_vxlan_sg_hash_key_make(const void *p) { const struct pim_vxlan_sg *vxlan_sg = p; - return (jhash_2words(vxlan_sg->sg.src.s_addr, - vxlan_sg->sg.grp.s_addr, 0)); + return pim_sgaddr_hash(vxlan_sg->sg, 0); } static bool pim_vxlan_sg_hash_eq(const void *p1, const void *p2) @@ -729,8 +725,7 @@ static bool pim_vxlan_sg_hash_eq(const void *p1, const void *p2) const struct pim_vxlan_sg *sg1 = p1; const struct pim_vxlan_sg *sg2 = p2; - return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr) - && (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr)); + return !pim_sgaddr_cmp(sg1->sg, sg2->sg); } static struct pim_vxlan_sg *pim_vxlan_sg_new(struct pim_instance *pim, @@ -742,7 +737,7 @@ static struct pim_vxlan_sg *pim_vxlan_sg_new(struct pim_instance *pim, vxlan_sg->pim = pim; vxlan_sg->sg = *sg; - pim_str_sg_set(sg, vxlan_sg->sg_str); + snprintfrr(vxlan_sg->sg_str, sizeof(vxlan_sg->sg_str), "%pSG", sg); if (PIM_DEBUG_VXLAN) zlog_debug("vxlan SG %s alloc", vxlan_sg->sg_str); diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h index cd3de23e6..96882918a 100644 --- a/pimd/pim_vxlan.h +++ b/pimd/pim_vxlan.h @@ -109,14 +109,14 @@ struct pim_vxlan { */ static inline bool pim_vxlan_is_orig_mroute(struct pim_vxlan_sg *vxlan_sg) { - return (vxlan_sg->sg.src.s_addr != INADDR_ANY); + return !pim_addr_is_any(vxlan_sg->sg.src); } static inline bool pim_vxlan_is_local_sip(struct pim_upstream *up) { - return (up->sg.src.s_addr != INADDR_ANY) && - up->rpf.source_nexthop.interface && - if_is_loopback(up->rpf.source_nexthop.interface); + return !pim_addr_is_any(up->sg.src) && + up->rpf.source_nexthop.interface && + if_is_loopback(up->rpf.source_nexthop.interface); } static inline bool pim_vxlan_is_term_dev_cfg(struct pim_instance *pim, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 05b6f23ed..7f463715a 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -112,7 +112,6 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS) struct connected *c; struct prefix *p; struct pim_interface *pim_ifp; - struct pim_instance *pim; /* zebra api notifies address adds/dels events by using the same call @@ -141,12 +140,15 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS) #endif } - if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { - /* trying to add primary address */ +#if PIM_IPV == 4 + if (p->family != PIM_AF) + SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY); + else if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { + /* trying to add primary address? */ + pim_addr primary_addr = pim_find_primary_addr(c->ifp); + pim_addr addr = pim_addr_from_prefix(p); - struct in_addr primary_addr = pim_find_primary_addr(c->ifp); - if (p->family != AF_INET - || primary_addr.s_addr != p->u.prefix4.s_addr) { + if (pim_addr_cmp(primary_addr, addr)) { if (PIM_DEBUG_ZEBRA) zlog_warn( "%s: %s : forcing secondary flag on %pFX", @@ -154,9 +156,15 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS) SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY); } } +#else /* PIM_IPV != 4 */ + if (p->family != PIM_AF) + return 0; +#endif pim_if_addr_add(c); if (pim_ifp) { + struct pim_instance *pim; + pim = pim_get_pim_instance(vrf_id); pim_ifp->pim = pim; @@ -172,7 +180,6 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS) pim_if_addr_add_all(ifp); } } - return 0; } @@ -181,11 +188,9 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS) struct connected *c; struct prefix *p; struct vrf *vrf = vrf_lookup_by_id(vrf_id); - struct pim_instance *pim; if (!vrf) return 0; - pim = vrf->info; /* zebra api notifies address adds/dels events by using the same call @@ -200,20 +205,23 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS) return 0; p = c->address; - if (p->family == AF_INET) { - if (PIM_DEBUG_ZEBRA) { - zlog_debug( - "%s: %s(%u) disconnected IP address %pFX flags %u %s", - __func__, c->ifp->name, vrf_id, p, c->flags, - CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) - ? "secondary" - : "primary"); + if (PIM_DEBUG_ZEBRA) { + zlog_debug( + "%s: %s(%u) disconnected IP address %pFX flags %u %s", + __func__, c->ifp->name, vrf_id, p, c->flags, + CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) + ? "secondary" + : "primary"); #ifdef PIM_DEBUG_IFADDR_DUMP - dump_if_address(c->ifp); + dump_if_address(c->ifp); #endif - } + } + + if (p->family == PIM_AF) { + struct pim_instance *pim; + pim = vrf->info; pim_if_addr_del(c, 0); pim_rp_setup(pim); pim_i_am_rp_re_evaluate(pim); @@ -240,7 +248,7 @@ void pim_zebra_update_all_interfaces(struct pim_instance *pim) struct pim_rpf rpf; rpf.source_nexthop.interface = ifp; - rpf.rpf_addr.u.prefix4 = us->address; + pim_addr_to_prefix(&rpf.rpf_addr, us->address); pim_joinprune_send(&rpf, us->us); pim_jp_agg_clear_group(us->us); } @@ -254,8 +262,8 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, if (old->source_nexthop.interface) { struct pim_neighbor *nbr; - nbr = pim_neighbor_find(old->source_nexthop.interface, - old->rpf_addr.u.prefix4); + nbr = pim_neighbor_find_prefix(old->source_nexthop.interface, + &old->rpf_addr); if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr); @@ -323,6 +331,7 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, pim_upstream_update_join_desired(pim, up); } +__attribute__((unused)) static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS) { struct stream *s; @@ -337,17 +346,12 @@ static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS) s = zclient->ibuf; prefixlen = stream_getl(s); - stream_get(&sg.src.s_addr, s, prefixlen); - stream_get(&sg.grp.s_addr, s, prefixlen); + stream_get(&sg.src, s, prefixlen); + stream_get(&sg.grp, s, prefixlen); - if (PIM_DEBUG_ZEBRA) { - char sg_str[PIM_SG_LEN]; - - pim_str_sg_set(&sg, sg_str); - zlog_debug("%u:recv SG %s %s", vrf_id, - (cmd == ZEBRA_VXLAN_SG_ADD)?"add":"del", - sg_str); - } + if (PIM_DEBUG_ZEBRA) + zlog_debug("%u:recv SG %s %pSG", vrf_id, + (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", &sg); if (cmd == ZEBRA_VXLAN_SG_ADD) pim_vxlan_sg_add(pim, &sg); @@ -357,6 +361,7 @@ static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS) return 0; } +__attribute__((unused)) static void pim_zebra_vxlan_replay(void) { struct stream *s = NULL; @@ -385,7 +390,7 @@ void pim_scan_oil(struct pim_instance *pim) pim_upstream_mroute_iif_update(c_oil, __func__); } -static int on_rpf_cache_refresh(struct thread *t) +static void on_rpf_cache_refresh(struct thread *t) { struct pim_instance *pim = THREAD_ARG(t); @@ -397,7 +402,6 @@ static int on_rpf_cache_refresh(struct thread *t) // It is called as part of pim_neighbor_add // pim_rp_setup (); - return 0; } void sched_rpf_cache_refresh(struct pim_instance *pim) @@ -425,13 +429,17 @@ void sched_rpf_cache_refresh(struct pim_instance *pim) static void pim_zebra_connected(struct zclient *zclient) { +#if PIM_IPV == 4 /* Send the client registration */ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id); +#endif zclient_send_reg_requests(zclient, router->vrf_id); +#if PIM_IPV == 4 /* request for VxLAN BUM group addresses */ pim_zebra_vxlan_replay(); +#endif } static void pim_zebra_capabilities(struct zclient_capabilities *cap) @@ -440,18 +448,21 @@ static void pim_zebra_capabilities(struct zclient_capabilities *cap) } static zclient_handler *const pim_handlers[] = { - [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del, - [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update, + [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update, + [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra, + [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update, +#if PIM_IPV == 4 [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc, [ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc, [ZEBRA_MLAG_PROCESS_UP] = pim_zebra_mlag_process_up, [ZEBRA_MLAG_PROCESS_DOWN] = pim_zebra_mlag_process_down, [ZEBRA_MLAG_FORWARD_MSG] = pim_zebra_mlag_handle_msg, +#endif }; void pim_zebra_init(void) @@ -471,369 +482,14 @@ void pim_zebra_init(void) zclient_lookup_new(); } -void igmp_anysource_forward_start(struct pim_instance *pim, - struct gm_group *group) -{ - struct gm_source *source; - struct in_addr src_addr = {.s_addr = 0}; - /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ - assert(group->group_filtermode_isexcl); - assert(listcount(group->group_source_list) < 1); - - source = igmp_get_source_by_addr(group, src_addr, NULL); - if (!source) { - zlog_warn("%s: Failure to create * source", __func__); - return; - } - - igmp_source_forward_start(pim, source); -} - -void igmp_anysource_forward_stop(struct gm_group *group) -{ - struct gm_source *source; - struct in_addr star = {.s_addr = 0}; - - source = igmp_find_source_by_addr(group, star); - if (source) - igmp_source_forward_stop(source); -} - -static void igmp_source_forward_reevaluate_one(struct pim_instance *pim, - struct gm_source *source) -{ - pim_sgaddr sg; - struct gm_group *group = source->source_group; - struct pim_ifchannel *ch; - - if ((source->source_addr.s_addr != INADDR_ANY) - || !IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) - return; - - memset(&sg, 0, sizeof(sg)); - sg.src = source->source_addr; - sg.grp = group->group_addr; - - ch = pim_ifchannel_find(group->interface, &sg); - if (pim_is_grp_ssm(pim, group->group_addr)) { - /* If SSM group withdraw local membership */ - if (ch - && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) { - if (PIM_DEBUG_PIM_EVENTS) - zlog_debug( - "local membership del for %s as G is now SSM", - pim_str_sg_dump(&sg)); - pim_ifchannel_local_membership_del(group->interface, - &sg); - } - } else { - /* If ASM group add local membership */ - if (!ch - || (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) { - if (PIM_DEBUG_PIM_EVENTS) - zlog_debug( - "local membership add for %s as G is now ASM", - pim_str_sg_dump(&sg)); - pim_ifchannel_local_membership_add( - group->interface, &sg, false /*is_vxlan*/); - } - } -} - -void igmp_source_forward_reevaluate_all(struct pim_instance *pim) -{ - struct interface *ifp; - - FOR_ALL_INTERFACES (pim->vrf, ifp) { - struct pim_interface *pim_ifp = ifp->info; - struct listnode *grpnode; - struct gm_group *grp; - struct pim_ifchannel *ch, *ch_temp; - - if (!pim_ifp) - continue; - - /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, - grp)) { - struct listnode *srcnode; - struct gm_source *src; - - /* scan group sources */ - for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, - srcnode, src)) { - igmp_source_forward_reevaluate_one(pim, src); - } /* scan group sources */ - } /* scan igmp groups */ - - RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb, - ch_temp) { - if (pim_is_grp_ssm(pim, ch->sg.grp)) { - if (ch->sg.src.s_addr == INADDR_ANY) - pim_ifchannel_delete(ch); - } - } - } /* scan interfaces */ -} - -void igmp_source_forward_start(struct pim_instance *pim, - struct gm_source *source) -{ - struct pim_interface *pim_oif; - struct gm_group *group; - pim_sgaddr sg; - int result; - int input_iface_vif_index = 0; - - memset(&sg, 0, sizeof(sg)); - sg.src = source->source_addr; - sg.grp = source->source_group->group_addr; - - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug("%s: (S,G)=%s oif=%s fwd=%d", __func__, - pim_str_sg_dump(&sg), - source->source_group->interface->name, - IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); - } - - /* Prevent IGMP interface from installing multicast route multiple - times */ - if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { - return; - } - - group = source->source_group; - pim_oif = group->interface->info; - if (!pim_oif) { - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug("%s: multicast not enabled on oif=%s ?", - __func__, - source->source_group->interface->name); - } - return; - } - - if (!source->source_channel_oil) { - struct in_addr vif_source; - struct prefix src, grp; - struct pim_nexthop nexthop; - struct pim_upstream *up = NULL; - - if (!pim_rp_set_upstream_addr(pim, &vif_source, - source->source_addr, sg.grp)) { - /*Create a dummy channel oil */ - source->source_channel_oil = - pim_channel_oil_add(pim, &sg, __func__); - } - - else { - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = vif_source; // RP or Src address - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = sg.grp; - - up = pim_upstream_find(pim, &sg); - if (up) { - memcpy(&nexthop, &up->rpf.source_nexthop, - sizeof(struct pim_nexthop)); - pim_ecmp_nexthop_lookup(pim, &nexthop, &src, - &grp, 0); - if (nexthop.interface) - input_iface_vif_index = - pim_if_find_vifindex_by_ifindex( - pim, - nexthop.interface->ifindex); - } else - input_iface_vif_index = - pim_ecmp_fib_lookup_if_vif_index( - pim, &src, &grp); - - if (PIM_DEBUG_ZEBRA) { - char buf2[INET_ADDRSTRLEN]; - - pim_inet4_dump("", vif_source, buf2, - sizeof(buf2)); - zlog_debug( - "%s: NHT %s vif_source %s vif_index:%d ", - __func__, pim_str_sg_dump(&sg), buf2, - input_iface_vif_index); - } - - if (input_iface_vif_index < 1) { - if (PIM_DEBUG_IGMP_TRACE) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - source->source_addr, - source_str, sizeof(source_str)); - zlog_debug( - "%s %s: could not find input interface for source %s", - __FILE__, __func__, source_str); - } - source->source_channel_oil = - pim_channel_oil_add(pim, &sg, __func__); - } - - else { - /* - * Protect IGMP against adding looped MFC - * entries created by both source and receiver - * attached to the same interface. See TODO - * T22. Block only when the intf is non DR - * DR must create upstream. - */ - if ((input_iface_vif_index == - pim_oif->mroute_vif_index) && - !(PIM_I_am_DR(pim_oif))) { - /* ignore request for looped MFC entry - */ - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s: ignoring request for looped MFC entry (S,G)=%s: oif=%s vif_index=%d", - __func__, - pim_str_sg_dump(&sg), - source->source_group - ->interface->name, - input_iface_vif_index); - } - return; - } - - source->source_channel_oil = - pim_channel_oil_add(pim, &sg, __func__); - if (!source->source_channel_oil) { - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s %s: could not create OIL for channel (S,G)=%s", - __FILE__, __func__, - pim_str_sg_dump(&sg)); - } - return; - } - } - } - } - - if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) { - result = pim_channel_add_oif(source->source_channel_oil, - group->interface, - PIM_OIF_FLAG_PROTO_IGMP, __func__); - if (result) { - if (PIM_DEBUG_MROUTE) { - zlog_warn("%s: add_oif() failed with return=%d", - __func__, result); - } - return; - } - } else { - if (PIM_DEBUG_IGMP_TRACE) - zlog_debug( - "%s: %s was received on %s interface but we are not DR for that interface", - __func__, pim_str_sg_dump(&sg), - group->interface->name); - - return; - } - /* - Feed IGMPv3-gathered local membership information into PIM - per-interface (S,G) state. - */ - if (!pim_ifchannel_local_membership_add(group->interface, &sg, - false /*is_vxlan*/)) { - if (PIM_DEBUG_MROUTE) - zlog_warn("%s: Failure to add local membership for %s", - __func__, pim_str_sg_dump(&sg)); - - pim_channel_del_oif(source->source_channel_oil, - group->interface, PIM_OIF_FLAG_PROTO_IGMP, - __func__); - return; - } - - IGMP_SOURCE_DO_FORWARDING(source->source_flags); -} - -/* - igmp_source_forward_stop: stop fowarding, but keep the source - igmp_source_delete: stop fowarding, and delete the source - */ -void igmp_source_forward_stop(struct gm_source *source) -{ - struct gm_group *group; - pim_sgaddr sg; - int result; - - memset(&sg, 0, sizeof(sg)); - sg.src = source->source_addr; - sg.grp = source->source_group->group_addr; - - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug("%s: (S,G)=%s oif=%s fwd=%d", __func__, - pim_str_sg_dump(&sg), - source->source_group->interface->name, - IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); - } - - /* Prevent IGMP interface from removing multicast route multiple - times */ - if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { - return; - } - - group = source->source_group; - - /* - It appears that in certain circumstances that - igmp_source_forward_stop is called when IGMP forwarding - was not enabled in oif_flags for this outgoing interface. - Possibly because of multiple calls. When that happens, we - enter the below if statement and this function returns early - which in turn triggers the calling function to assert. - Making the call to pim_channel_del_oif and ignoring the return code - fixes the issue without ill effect, similar to - pim_forward_stop below. - */ - result = pim_channel_del_oif(source->source_channel_oil, - group->interface, PIM_OIF_FLAG_PROTO_IGMP, - __func__); - if (result) { - if (PIM_DEBUG_IGMP_TRACE) - zlog_debug( - "%s: pim_channel_del_oif() failed with return=%d", - __func__, result); - return; - } - - /* - Feed IGMPv3-gathered local membership information into PIM - per-interface (S,G) state. - */ - pim_ifchannel_local_membership_del(group->interface, &sg); - - IGMP_SOURCE_DONT_FORWARDING(source->source_flags); -} - void pim_forward_start(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; uint32_t mask = 0; - if (PIM_DEBUG_PIM_TRACE) { - char source_str[INET_ADDRSTRLEN]; - char group_str[INET_ADDRSTRLEN]; - char upstream_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("", ch->sg.src, source_str, - sizeof(source_str)); - pim_inet4_dump("", ch->sg.grp, group_str, - sizeof(group_str)); - pim_inet4_dump("", up->upstream_addr, upstream_str, - sizeof(upstream_str)); - zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%pI4)", __func__, - source_str, group_str, ch->interface->name, - &up->upstream_addr); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: (S,G)=%pSG oif=%s (%pPA)", __func__, &ch->sg, + ch->interface->name, &up->upstream_addr); if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags)) mask = PIM_OIF_FLAG_PROTO_IGMP; diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index 8656d7563..5879cdefb 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -23,7 +23,6 @@ #include #include "zclient.h" -#include "pim_igmp.h" #include "pim_ifchannel.h" void pim_zebra_init(void); @@ -32,15 +31,6 @@ void pim_zebra_zclient_update(struct vty *vty); void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index); void pim_scan_oil(struct pim_instance *pim_matcher); -void igmp_anysource_forward_start(struct pim_instance *pim, - struct gm_group *group); -void igmp_anysource_forward_stop(struct gm_group *group); - -void igmp_source_forward_start(struct pim_instance *pim, - struct gm_source *source); -void igmp_source_forward_stop(struct gm_source *source); -void igmp_source_forward_reevaluate_all(struct pim_instance *pim); - void pim_forward_start(struct pim_ifchannel *ch); void pim_forward_stop(struct pim_ifchannel *ch); diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 755b9b132..c33e6032b 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -36,22 +36,23 @@ #include "pim_str.h" #include "pim_oil.h" #include "pim_zlookup.h" +#include "pim_addr.h" static struct zclient *zlookup = NULL; struct thread *zlookup_read; static void zclient_lookup_sched(struct zclient *zlookup, int delay); -static int zclient_lookup_read_pipe(struct thread *thread); +static void zclient_lookup_read_pipe(struct thread *thread); /* Connect to zebra for nexthop lookup. */ -static int zclient_lookup_connect(struct thread *t) +static void zclient_lookup_connect(struct thread *t) { struct zclient *zlookup; zlookup = THREAD_ARG(t); if (zlookup->sock >= 0) { - return 0; + return; } if (zclient_socket_connect(zlookup) < 0) { @@ -73,12 +74,11 @@ static int zclient_lookup_connect(struct thread *t) if (zlookup->sock < 0) { /* Since last connect failed, retry within 10 secs */ zclient_lookup_sched(zlookup, 10); - return -1; + return; } thread_add_timer(router->master, zclient_lookup_read_pipe, zlookup, 60, &zlookup_read); - return 0; } /* Schedule connection with delay. */ @@ -300,9 +300,9 @@ static int zclient_read_nexthop(struct pim_instance *pim, if (nbr) { nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET; - nexthop_tab[num_ifindex] - .nexthop_addr.u.prefix4 = - nbr->source_addr; + pim_addr_to_prefix( + &nexthop_tab[num_ifindex].nexthop_addr, + nbr->source_addr); } ++num_ifindex; break; @@ -381,7 +381,7 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim, return zclient_read_nexthop(pim, zlookup, nexthop_tab, tab_size, addr); } -int zclient_lookup_read_pipe(struct thread *thread) +void zclient_lookup_read_pipe(struct thread *thread) { struct zclient *zlookup = THREAD_ARG(thread); struct pim_instance *pim = pim_get_pim_instance(VRF_DEFAULT); @@ -391,13 +391,11 @@ int zclient_lookup_read_pipe(struct thread *thread) zclient_lookup_nexthop_once(pim, nexthop_tab, 10, l); thread_add_timer(router->master, zclient_lookup_read_pipe, zlookup, 60, &zlookup_read); - - return 1; } int zclient_lookup_nexthop(struct pim_instance *pim, struct pim_zlookup_nexthop nexthop_tab[], - const int tab_size, struct in_addr addr, + const int tab_size, pim_addr addr, int max_lookup) { int lookup; @@ -414,15 +412,11 @@ int zclient_lookup_nexthop(struct pim_instance *pim, num_ifindex = zclient_lookup_nexthop_once(pim, nexthop_tab, tab_size, addr); if (num_ifindex < 1) { - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, addr_str, - sizeof(addr_str)); + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: lookup=%d/%d: could not find nexthop ifindex for address %s(%s)", - __func__, lookup, max_lookup, addr_str, + "%s: lookup=%d/%d: could not find nexthop ifindex for address %pPA(%s)", + __func__, lookup, max_lookup, &addr, pim->vrf->name); - } return -1; } @@ -451,23 +445,19 @@ int zclient_lookup_nexthop(struct pim_instance *pim, if (lookup > 0) { /* Report non-recursive success after first * lookup */ - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, - addr_str, - sizeof(addr_str)); + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: lookup=%d/%d: found non-recursive ifindex=%d for address %s(%s) dist=%d met=%d", + "%s: lookup=%d/%d: found non-recursive ifindex=%d for address %pPA(%s) dist=%d met=%d", __func__, lookup, max_lookup, - first_ifindex, addr_str, + first_ifindex, &addr, pim->vrf->name, nexthop_tab[0] .protocol_distance, nexthop_tab[0].route_metric); - } /* use last address as nexthop address */ - nexthop_tab[0].nexthop_addr.u.prefix4 = addr; + pim_addr_to_prefix( + &(nexthop_tab[0].nexthop_addr), addr); /* report original route metric/distance */ nexthop_tab[0].route_metric = route_metric; @@ -486,25 +476,22 @@ int zclient_lookup_nexthop(struct pim_instance *pim, pim_addr_dump("", &nexthop_addr, nexthop_str, sizeof(nexthop_str)); zlog_debug( - "%s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s(%s) dist=%d met=%d", + "%s: lookup=%d/%d: zebra returned recursive nexthop %s for address %pPA(%s) dist=%d met=%d", __func__, lookup, max_lookup, nexthop_str, - addr_str, pim->vrf->name, + &addr, pim->vrf->name, nexthop_tab[0].protocol_distance, nexthop_tab[0].route_metric); } - addr = nexthop_addr.u.prefix4; /* use nexthop addr for - recursive lookup */ + addr = pim_addr_from_prefix(&(nexthop_addr)); /* use nexthop + addr for recursive lookup */ } /* for (max_lookup) */ - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); + if (PIM_DEBUG_PIM_NHT) zlog_warn( - "%s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s(%s)", - __func__, lookup, max_lookup, addr_str, pim->vrf->name); - } + "%s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %pPA(%s)", + __func__, lookup, max_lookup, &addr, pim->vrf->name); return -2; } @@ -535,10 +522,9 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) more.src = c_oil->oil.mfcc_origin; more.grp = c_oil->oil.mfcc_mcastgrp; - zlog_debug( - "Sending Request for New Channel Oil Information%s VIIF %d(%s)", - pim_str_sg_dump(&more), c_oil->oil.mfcc_parent, - c_oil->pim->vrf->name); + zlog_debug("Sending Request for New Channel Oil Information%pSG VIIF %d(%s)", + &more, c_oil->oil.mfcc_parent, + c_oil->pim->vrf->name); } if (!ifp) @@ -593,9 +579,8 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) more.grp = c_oil->oil.mfcc_mcastgrp; flog_err( EC_LIB_ZAPI_MISSMATCH, - "%s: Received wrong %s(%s) information requested", - __func__, pim_str_sg_dump(&more), - c_oil->pim->vrf->name); + "%s: Received wrong %pSG(%s) information requested", + __func__, &more, c_oil->pim->vrf->name); } zclient_lookup_failed(zlookup); return -3; diff --git a/pimd/pim_zlookup.h b/pimd/pim_zlookup.h index 09e8dcd51..c3818dbdb 100644 --- a/pimd/pim_zlookup.h +++ b/pimd/pim_zlookup.h @@ -39,7 +39,7 @@ void zclient_lookup_free(void); int zclient_lookup_nexthop(struct pim_instance *pim, struct pim_zlookup_nexthop nexthop_tab[], - const int tab_size, struct in_addr addr, + const int tab_size, pim_addr addr, int max_lookup); void pim_zlookup_show_ip_multicast(struct vty *vty); diff --git a/pimd/pim_zpthread.c b/pimd/pim_zpthread.c index 518b02474..a34293108 100644 --- a/pimd/pim_zpthread.c +++ b/pimd/pim_zpthread.c @@ -140,7 +140,7 @@ static void pim_mlag_zebra_check_for_buffer_flush(uint32_t curr_msg_type, * Thsi thread reads the clients data from the Gloabl queue and encodes with * protobuf and pass on to the MLAG socket. */ -static int pim_mlag_zthread_handler(struct thread *event) +static void pim_mlag_zthread_handler(struct thread *event) { struct stream *read_s; uint32_t wr_count = 0; @@ -155,7 +155,7 @@ static int pim_mlag_zthread_handler(struct thread *event) __func__, wr_count); if (wr_count == 0) - return 0; + return; for (wr_count = 0; wr_count < PIM_MLAG_POST_LIMIT; wr_count++) { /* FIFO is empty,wait for teh message to be add */ @@ -207,8 +207,6 @@ stream_failure: if (wr_count >= PIM_MLAG_POST_LIMIT) pim_mlag_signal_zpthread(); - - return 0; } diff --git a/pimd/pimd.c b/pimd/pimd.c index 992bb931b..58e874fd1 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -32,7 +32,11 @@ #include "bfd.h" #include "pimd.h" +#if PIM_IPV == 4 #include "pim_cmd.h" +#else +#include "pim6_cmd.h" +#endif #include "pim_str.h" #include "pim_oil.h" #include "pim_pim.h" @@ -49,15 +53,22 @@ CPP_NOTICE("Work needs to be done to make this work properly via the pim mroute socket\n"); #endif /* MAXVIFS > 256 */ +#if PIM_IPV == 4 const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; const char *const PIM_ALL_PIM_ROUTERS = MCAST_ALL_PIM_ROUTERS; const char *const PIM_ALL_IGMP_ROUTERS = MCAST_ALL_IGMP_ROUTERS; +#else +const char *const PIM_ALL_SYSTEMS = "ff02::1"; +const char *const PIM_ALL_ROUTERS = "ff02::2"; +const char *const PIM_ALL_PIM_ROUTERS = "ff02::d"; +const char *const PIM_ALL_IGMP_ROUTERS = "ff02::16"; +#endif DEFINE_MTYPE_STATIC(PIMD, ROUTER, "PIM Router information"); struct pim_router *router = NULL; -struct in_addr qpim_all_pim_routers_addr; +pim_addr qpim_all_pim_routers_addr; void pim_prefix_list_update(struct prefix_list *plist) { @@ -103,7 +114,7 @@ void pim_router_init(void) PIM_ASSERT_METRIC_PREFERENCE_MAX; router->infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; - router->infinite_assert_metric.ip_address.s_addr = INADDR_ANY; + router->infinite_assert_metric.ip_address = PIMADDR_ANY; router->rpf_cache_refresh_delay_msec = 50; router->register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; router->packet_process = PIM_DEFAULT_PACKET_PROCESS; @@ -120,7 +131,8 @@ void pim_router_terminate(void) void pim_init(void) { - if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { + if (!inet_pton(PIM_AF, PIM_ALL_PIM_ROUTERS, + &qpim_all_pim_routers_addr)) { flog_err( EC_LIB_SOCKET, "%s %s: could not solve %s to group address: errno=%d: %s", diff --git a/pimd/pimd.h b/pimd/pimd.h index 5ba29f9c4..d4eac58a2 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -83,8 +83,6 @@ #define PIM_FORCE_BOOLEAN(expr) ((expr) != 0) #define PIM_NET_INADDR_ANY (htonl(INADDR_ANY)) -#define PIM_INADDR_IS_ANY(addr) (addr).s_addr == PIM_NET_INADDR_ANY -#define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */ #define PIM_MASK_PIM_EVENTS (1 << 0) #define PIM_MASK_PIM_EVENTS_DETAIL (1 << 1) @@ -136,7 +134,7 @@ extern const char *const PIM_ALL_PIM_ROUTERS; extern const char *const PIM_ALL_IGMP_ROUTERS; extern struct zebra_privs_t pimd_privs; -extern struct in_addr qpim_all_pim_routers_addr; +extern pim_addr qpim_all_pim_routers_addr; extern uint8_t qpim_ecmp_enable; extern uint8_t qpim_ecmp_rebalance_enable; diff --git a/pimd/subdir.am b/pimd/subdir.am index 6c267f290..cda5acb00 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -6,8 +6,12 @@ if PIMD sbin_PROGRAMS += pimd/pimd bin_PROGRAMS += pimd/mtracebis noinst_PROGRAMS += pimd/test_igmpv3_join -vtysh_scan += pimd/pim_cmd.c +vtysh_scan += \ + pimd/pim_cmd.c \ + pimd/pim6_cmd.c \ + #end vtysh_daemons += pimd +vtysh_daemons += pim6d man8 += $(MANBUILD)/frr-pimd.8 man8 += $(MANBUILD)/mtracebis.8 endif @@ -17,24 +21,17 @@ pim_common = \ pimd/pim_assert.c \ pimd/pim_bfd.c \ pimd/pim_br.c \ - pimd/pim_bsm.c \ - pimd/pim_cmd.c \ + pimd/pim_cmd_common.c \ pimd/pim_errors.c \ pimd/pim_hello.c \ pimd/pim_iface.c \ pimd/pim_ifchannel.c \ - pimd/pim_igmp.c \ - pimd/pim_igmp_mtrace.c \ - pimd/pim_igmp_stats.c \ - pimd/pim_igmpv2.c \ - pimd/pim_igmpv3.c \ pimd/pim_instance.c \ pimd/pim_int.c \ pimd/pim_join.c \ pimd/pim_jp_agg.c \ pimd/pim_macro.c \ pimd/pim_memory.c \ - pimd/pim_mlag.c \ pimd/pim_mroute.c \ pimd/pim_msg.c \ pimd/pim_nb.c \ @@ -42,8 +39,6 @@ pim_common = \ pimd/pim_neighbor.c \ pimd/pim_nht.c \ pimd/pim_oil.c \ - pimd/pim_pim.c \ - pimd/pim_register.c \ pimd/pim_routemap.c \ pimd/pim_rp.c \ pimd/pim_rpf.c \ @@ -52,25 +47,36 @@ pim_common = \ pimd/pim_ssmpingd.c \ pimd/pim_static.c \ pimd/pim_str.c \ + pimd/pim_tib.c \ pimd/pim_time.c \ pimd/pim_tlv.c \ pimd/pim_upstream.c \ pimd/pim_util.c \ pimd/pim_vty.c \ pimd/pim_zebra.c \ - pimd/pim_zlookup.c \ pimd/pim_vxlan.c \ - pimd/pim_zpthread.c \ pimd/pimd.c \ # end pimd_pimd_SOURCES = \ $(pim_common) \ + pimd/pim_bsm.c \ + pimd/pim_cmd.c \ + pimd/pim_igmp.c \ + pimd/pim_igmp_mtrace.c \ + pimd/pim_igmp_stats.c \ + pimd/pim_igmpv2.c \ + pimd/pim_igmpv3.c \ pimd/pim_main.c \ + pimd/pim_mlag.c \ pimd/pim_msdp.c \ pimd/pim_msdp_packet.c \ pimd/pim_msdp_socket.c \ + pimd/pim_pim.c \ + pimd/pim_register.c \ pimd/pim_signals.c \ + pimd/pim_zlookup.c \ + pimd/pim_zpthread.c \ # end nodist_pimd_pimd_SOURCES = \ @@ -82,9 +88,14 @@ nodist_pimd_pimd_SOURCES = \ pimd_pim6d_SOURCES = \ $(pim_common) \ pimd/pim6_main.c \ + pimd/pim6_stubs.c \ + pimd/pim6_cmd.c \ # end nodist_pimd_pim6d_SOURCES = \ + yang/frr-pim.yang.c \ + yang/frr-pim-rp.yang.c \ + yang/frr-gmp.yang.c \ # end noinst_HEADERS += \ @@ -94,6 +105,7 @@ noinst_HEADERS += \ pimd/pim_br.h \ pimd/pim_bsm.h \ pimd/pim_cmd.h \ + pimd/pim_cmd_common.h \ pimd/pim_errors.h \ pimd/pim_hello.h \ pimd/pim_iface.h \ @@ -130,6 +142,7 @@ noinst_HEADERS += \ pimd/pim_ssmpingd.h \ pimd/pim_static.h \ pimd/pim_str.h \ + pimd/pim_tib.h \ pimd/pim_time.h \ pimd/pim_tlv.h \ pimd/pim_upstream.h \ @@ -142,10 +155,12 @@ noinst_HEADERS += \ pimd/pimd.h \ pimd/mtracebis_netlink.h \ pimd/mtracebis_routeget.h \ + pimd/pim6_cmd.h \ # end clippy_scan += \ pimd/pim_cmd.c \ + pimd/pim6_cmd.c \ # end pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4 @@ -158,7 +173,7 @@ if DEV_BUILD # (change noinst_ to sbin_ below to install it.) # noinst_PROGRAMS += pimd/pim6d -pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6 $(and $(PIM_V6_TEMP_BREAK),-DPIM_V6_TEMP_BREAK) +pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6 pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP) endif endif diff --git a/python/clidef.py b/python/clidef.py index b57a00fc8..101c9a5ae 100644 --- a/python/clidef.py +++ b/python/clidef.py @@ -241,24 +241,51 @@ def get_always_args(token, always_args, args=[], stack=[]): class Macros(dict): + def __init__(self): + super().__init__() + self._loc = {} + def load(self, filename): filedata = clippy.parse(filename) for entry in filedata["data"]: if entry["type"] != "PREPROC": continue - ppdir = entry["line"].lstrip().split(None, 1) - if ppdir[0] != "define" or len(ppdir) != 2: - continue - ppdef = ppdir[1].split(None, 1) - name = ppdef[0] - if "(" in name: - continue - val = ppdef[1] if len(ppdef) == 2 else "" - - val = val.strip(" \t\n\\") - if name in self: - sys.stderr.write("warning: macro %s redefined!\n" % (name)) + self.load_preproc(filename, entry) + + def setup(self, key, val, where="built-in"): + self[key] = val + self._loc[key] = (where, 0) + + def load_preproc(self, filename, entry): + ppdir = entry["line"].lstrip().split(None, 1) + if ppdir[0] != "define" or len(ppdir) != 2: + return + ppdef = ppdir[1].split(None, 1) + name = ppdef[0] + if "(" in name: + return + val = ppdef[1] if len(ppdef) == 2 else "" + + val = val.strip(" \t\n\\") + if self.get(name, val) != val: + sys.stderr.write( + "%s:%d: warning: macro %s redefined!\n" + % ( + filename, + entry["lineno"], + name, + ) + ) + sys.stderr.write( + "%s:%d: note: previously defined here\n" + % ( + self._loc[name][0], + self._loc[name][1], + ) + ) + else: self[name] = val + self._loc[name] = (filename, entry["lineno"]) def process_file(fn, ofd, dumpfd, all_defun, macros): @@ -283,6 +310,11 @@ def process_file(fn, ofd, dumpfd, all_defun, macros): cond_stack.append(prev_line + line) elif tokens[0] in ["endif"]: cond_stack.pop(-1) + elif tokens[0] in ["define"]: + if not cond_stack: + macros.load_preproc(fn, entry) + elif len(cond_stack) == 1 and cond_stack[0] == "#ifdef CLIPPY\n": + macros.load_preproc(fn, entry) continue if entry["type"].startswith("DEFPY") or ( all_defun and entry["type"].startswith("DEFUN") @@ -454,9 +486,9 @@ if __name__ == "__main__": macros.load(os.path.join(basepath, "lib/command.h")) macros.load(os.path.join(basepath, "bgpd/bgp_vty.h")) # sigh :( - macros["PROTO_REDIST_STR"] = "FRR_REDIST_STR_ISISD" - macros["PROTO_IP_REDIST_STR"] = "FRR_IP_REDIST_STR_ISISD" - macros["PROTO_IP6_REDIST_STR"] = "FRR_IP6_REDIST_STR_ISISD" + macros.setup("PROTO_REDIST_STR", "FRR_REDIST_STR_ISISD") + macros.setup("PROTO_IP_REDIST_STR", "FRR_IP_REDIST_STR_ISISD") + macros.setup("PROTO_IP6_REDIST_STR", "FRR_IP6_REDIST_STR_ISISD") errors = process_file(args.cfile, ofd, dumpfd, args.all_defun, macros) if errors != 0: diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 7f8e89de1..740cfe498 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -775,6 +775,8 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %changelog * Tue Nov 4 2021 Martin Winter - %{version} +* Tue Feb 1 2022 Donatas Abraitis - 8.2 + * Tue Nov 2 2021 Jafar Al-Gharaibeh - 8.1 - FRR 8.1 brings a long list of enhancements and fixes with 1200 commits from - 75 developers. Thanks to all contributers. diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 8fd64f287..1269f25b3 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -789,7 +789,7 @@ int rip_enable_if_delete(struct rip *rip, const char *ifname) } /* Join to multicast group and send request to the interface. */ -static int rip_interface_wakeup(struct thread *t) +static void rip_interface_wakeup(struct thread *t) { struct interface *ifp; struct rip_interface *ri; @@ -804,7 +804,7 @@ static int rip_interface_wakeup(struct thread *t) flog_err_sys(EC_LIB_SOCKET, "multicast join failed, interface %s not running", ifp->name); - return 0; + return; } /* Set running flag. */ @@ -812,8 +812,6 @@ static int rip_interface_wakeup(struct thread *t) /* Send RIP request to the interface. */ rip_request_interface(ifp); - - return 0; } static void rip_connect_set(struct interface *ifp, int set) diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index 12c4edd43..8febb436e 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -67,15 +67,13 @@ struct rip_peer *rip_peer_lookup_next(struct rip *rip, struct in_addr *addr) } /* RIP peer is timeout. */ -static int rip_peer_timeout(struct thread *t) +static void rip_peer_timeout(struct thread *t) { struct rip_peer *peer; peer = THREAD_ARG(t); listnode_delete(peer->rip->peer_list, peer); rip_peer_free(peer); - - return 0; } /* Get RIP peer. At the same time update timeout thread. */ diff --git a/ripd/ripd.c b/ripd/ripd.c index 346c11ad3..2a05f30bc 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -65,7 +65,7 @@ DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance"); /* Prototypes. */ static void rip_output_process(struct connected *, struct sockaddr_in *, int, uint8_t); -static int rip_triggered_update(struct thread *); +static void rip_triggered_update(struct thread *); static int rip_update_jitter(unsigned long); static void rip_distance_table_node_cleanup(struct route_table *table, struct route_node *node); @@ -136,7 +136,7 @@ struct rip *rip_info_get_instance(const struct rip_info *rinfo) } /* RIP route garbage collect timer. */ -static int rip_garbage_collect(struct thread *t) +static void rip_garbage_collect(struct thread *t) { struct rip_info *rinfo; struct route_node *rp; @@ -158,8 +158,6 @@ static int rip_garbage_collect(struct thread *t) /* Free RIP routing information. */ rip_info_free(rinfo); - - return 0; } static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo); @@ -224,13 +222,15 @@ struct rip_info *rip_ecmp_replace(struct rip *rip, struct rip_info *rinfo_new) rip_zebra_ipv4_delete(rip, rp); /* Re-use the first entry, and delete the others. */ - for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) - if (tmp_rinfo != rinfo) { - RIP_TIMER_OFF(tmp_rinfo->t_timeout); - RIP_TIMER_OFF(tmp_rinfo->t_garbage_collect); - list_delete_node(list, node); - rip_info_free(tmp_rinfo); - } + for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) { + if (tmp_rinfo == rinfo) + continue; + + RIP_TIMER_OFF(tmp_rinfo->t_timeout); + RIP_TIMER_OFF(tmp_rinfo->t_garbage_collect); + list_delete_node(list, node); + rip_info_free(tmp_rinfo); + } RIP_TIMER_OFF(rinfo->t_timeout); RIP_TIMER_OFF(rinfo->t_garbage_collect); @@ -302,14 +302,12 @@ struct rip_info *rip_ecmp_delete(struct rip *rip, struct rip_info *rinfo) } /* Timeout RIP routes. */ -static int rip_timeout(struct thread *t) +static void rip_timeout(struct thread *t) { struct rip_info *rinfo = THREAD_ARG(t); struct rip *rip = rip_info_get_instance(rinfo); rip_ecmp_delete(rip, rinfo); - - return 0; } static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo) @@ -332,61 +330,56 @@ static int rip_filter(int rip_distribute, struct prefix_ipv4 *p, const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in"; /* Input distribute-list filtering. */ - if (ri->list[rip_distribute]) { - if (access_list_apply(ri->list[rip_distribute], - (struct prefix *)p) - == FILTER_DENY) { - if (IS_RIP_DEBUG_PACKET) - zlog_debug("%pFX filtered by distribute %s", p, - inout); - return -1; - } + if (ri->list[rip_distribute] && + access_list_apply(ri->list[rip_distribute], (struct prefix *)p) == + FILTER_DENY) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug("%pFX filtered by distribute %s", p, inout); + return -1; } - if (ri->prefix[rip_distribute]) { - if (prefix_list_apply(ri->prefix[rip_distribute], - (struct prefix *)p) - == PREFIX_DENY) { - if (IS_RIP_DEBUG_PACKET) - zlog_debug("%pFX filtered by prefix-list %s", p, - inout); - return -1; - } + + if (ri->prefix[rip_distribute] && + prefix_list_apply(ri->prefix[rip_distribute], (struct prefix *)p) == + PREFIX_DENY) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug("%pFX filtered by prefix-list %s", p, inout); + return -1; } /* All interface filter check. */ dist = distribute_lookup(ri->rip->distribute_ctx, NULL); - if (dist) { - if (dist->list[distribute]) { - alist = access_list_lookup(AFI_IP, - dist->list[distribute]); + if (!dist) + return 0; - if (alist) { - if (access_list_apply(alist, (struct prefix *)p) - == FILTER_DENY) { - if (IS_RIP_DEBUG_PACKET) - zlog_debug( - "%pFX filtered by distribute %s", - p, inout); - return -1; - } + if (dist->list[distribute]) { + alist = access_list_lookup(AFI_IP, dist->list[distribute]); + + if (alist) { + if (access_list_apply(alist, (struct prefix *)p) == + FILTER_DENY) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "%pFX filtered by distribute %s", + p, inout); + return -1; } } - if (dist->prefix[distribute]) { - plist = prefix_list_lookup(AFI_IP, - dist->prefix[distribute]); - - if (plist) { - if (prefix_list_apply(plist, (struct prefix *)p) - == PREFIX_DENY) { - if (IS_RIP_DEBUG_PACKET) - zlog_debug( - "%pFX filtered by prefix-list %s", - p, inout); - return -1; - } + } + if (dist->prefix[distribute]) { + plist = prefix_list_lookup(AFI_IP, dist->prefix[distribute]); + + if (plist) { + if (prefix_list_apply(plist, (struct prefix *)p) == + PREFIX_DENY) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "%pFX filtered by prefix-list %s", + p, inout); + return -1; } } } + return 0; } @@ -532,46 +525,46 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from, && IPV4_ADDR_SAME(&rinfo->nh.gate.ipv4, nexthop)) break; - if (!listnextnode(node)) { - /* Not found in the list */ + if (listnextnode(node)) + continue; - if (rte->metric > rinfo->metric) { - /* New route has a greater metric. - * Discard it. */ - route_unlock_node(rp); - return; - } + /* Not found in the list */ - if (rte->metric < rinfo->metric) - /* New route has a smaller metric. - * Replace the ECMP list - * with the new one in below. */ - break; + if (rte->metric > rinfo->metric) { + /* New route has a greater metric. + * Discard it. */ + route_unlock_node(rp); + return; + } - /* Metrics are same. We compare the distances. - */ - old_dist = rinfo->distance - ? rinfo->distance + if (rte->metric < rinfo->metric) + /* New route has a smaller metric. + * Replace the ECMP list + * with the new one in below. */ + break; + + /* Metrics are same. We compare the distances. + */ + old_dist = rinfo->distance ? rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; - if (new_dist > old_dist) { - /* New route has a greater distance. - * Discard it. */ - route_unlock_node(rp); - return; - } + if (new_dist > old_dist) { + /* New route has a greater distance. + * Discard it. */ + route_unlock_node(rp); + return; + } - if (new_dist < old_dist) - /* New route has a smaller distance. - * Replace the ECMP list - * with the new one in below. */ - break; + if (new_dist < old_dist) + /* New route has a smaller distance. + * Replace the ECMP list + * with the new one in below. */ + break; - /* Metrics and distances are both same. Keep - * "rinfo" null and - * the new route is added in the ECMP list in - * below. */ - } + /* Metrics and distances are both same. Keep + * "rinfo" null and + * the new route is added in the ECMP list in + * below. */ } if (rinfo) { @@ -1278,15 +1271,14 @@ static void rip_response_process(struct rip_packet *packet, int size, } /* For RIPv1, there won't be a valid netmask. - - This is a best guess at the masks. If everyone was using old - Ciscos before the 'ip subnet zero' option, it would be almost - right too :-) - - Cisco summarize ripv1 advertisements to the classful boundary - (/16 for class B's) except when the RIP packet does to inside - the classful network in question. */ - + * This is a best guess at the masks. If everyone was using old + * Ciscos before the 'ip subnet zero' option, it would be almost + * right too :-) + * + * Cisco summarize ripv1 advertisements to the classful boundary + * (/16 for class B's) except when the RIP packet does to inside + * the classful network in question. + */ if ((packet->version == RIPv1 && rte->prefix.s_addr != INADDR_ANY) || (packet->version == RIPv2 @@ -1467,19 +1459,16 @@ static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to, if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) { /* * ZEBRA_IFA_SECONDARY is set on linux when an interface is - * configured - * with multiple addresses on the same subnet: the first address - * on the subnet is configured "primary", and all subsequent - * addresses - * on that subnet are treated as "secondary" addresses. - * In order to avoid routing-table bloat on other rip listeners, - * we do not send out RIP packets with ZEBRA_IFA_SECONDARY - * source addrs. + * configured with multiple addresses on the same + * subnet: the first address on the subnet is configured + * "primary", and all subsequent addresses on that subnet + * are treated as "secondary" addresses. In order to avoid + * routing-table bloat on other rip listeners, we do not send + * out RIP packets with ZEBRA_IFA_SECONDARY source addrs. * XXX Since Linux is the only system for which the - * ZEBRA_IFA_SECONDARY - * flag is set, we would end up sending a packet for a - * "secondary" - * source address on non-linux systems. + * ZEBRA_IFA_SECONDARY flag is set, we would end up + * sending a packet for a "secondary" source address on + * non-linux systems. */ if (IS_RIP_DEBUG_PACKET) zlog_debug("duplicate dropped"); @@ -1522,6 +1511,7 @@ static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to, cmsgptr->cmsg_type = IP_PKTINFO; pkt = (struct in_pktinfo *)CMSG_DATA(cmsgptr); pkt->ipi_ifindex = ifc->ifp->ifindex; + pkt->ipi_spec_dst.s_addr = ifc->address->u.prefix4.s_addr; #endif /* GNU_LINUX */ ret = sendmsg(rip->sock, &msg, 0); @@ -1724,7 +1714,7 @@ static void rip_request_process(struct rip_packet *packet, int size, } /* First entry point of RIP packet. */ -static int rip_read(struct thread *t) +static void rip_read(struct thread *t) { struct rip *rip = THREAD_ARG(t); int sock; @@ -1756,7 +1746,7 @@ static int rip_read(struct thread *t) if (len < 0) { zlog_info("recvfrom failed (VRF %s): %s", rip->vrf_name, safe_strerror(errno)); - return len; + return; } /* Check is this packet comming from myself? */ @@ -1764,7 +1754,7 @@ static int rip_read(struct thread *t) if (IS_RIP_DEBUG_PACKET) zlog_debug("ignore packet comes from myself (VRF %s)", rip->vrf_name); - return -1; + return; } /* Which interface is this packet comes from. */ @@ -1785,7 +1775,7 @@ static int rip_read(struct thread *t) "rip_read: cannot find interface for packet from %pI4 port %d (VRF %s)", &from.sin_addr, ntohs(from.sin_port), rip->vrf_name); - return -1; + return; } p.family = AF_INET; @@ -1799,7 +1789,7 @@ static int rip_read(struct thread *t) "rip_read: cannot find connected address for packet from %pI4 port %d on interface %s (VRF %s)", &from.sin_addr, ntohs(from.sin_port), ifp->name, rip->vrf_name); - return -1; + return; } /* Packet length check. */ @@ -1807,13 +1797,13 @@ static int rip_read(struct thread *t) zlog_warn("packet size %d is smaller than minimum size %d", len, RIP_PACKET_MINSIZ); rip_peer_bad_packet(rip, &from); - return len; + return; } if (len > RIP_PACKET_MAXSIZ) { zlog_warn("packet size %d is larger than max size %d", len, RIP_PACKET_MAXSIZ); rip_peer_bad_packet(rip, &from); - return len; + return; } /* Packet alignment check. */ @@ -1821,7 +1811,7 @@ static int rip_read(struct thread *t) zlog_warn("packet size %d is wrong for RIP packet alignment", len); rip_peer_bad_packet(rip, &from); - return len; + return; } /* Set RTE number. */ @@ -1835,7 +1825,7 @@ static int rip_read(struct thread *t) zlog_info("version 0 with command %d received.", packet->command); rip_peer_bad_packet(rip, &from); - return -1; + return; } /* Dump RIP packet. */ @@ -1856,7 +1846,7 @@ static int rip_read(struct thread *t) zlog_debug("RIP is not enabled on interface %s.", ifp->name); rip_peer_bad_packet(rip, &from); - return -1; + return; } /* RIP Version check. RFC2453, 4.6 and 5.1 */ @@ -1870,7 +1860,7 @@ static int rip_read(struct thread *t) " packet's v%d doesn't fit to if version spec", packet->version); rip_peer_bad_packet(rip, &from); - return -1; + return; } /* RFC2453 5.2 If the router is not configured to authenticate RIP-2 @@ -1885,7 +1875,7 @@ static int rip_read(struct thread *t) packet->version); ripd_notif_send_auth_type_failure(ifp->name); rip_peer_bad_packet(rip, &from); - return -1; + return; } /* RFC: @@ -1921,7 +1911,7 @@ static int rip_read(struct thread *t) "RIPv1 dropped because authentication enabled"); ripd_notif_send_auth_type_failure(ifp->name); rip_peer_bad_packet(rip, &from); - return -1; + return; } } else if (ri->auth_type != RIP_NO_AUTH) { const char *auth_desc; @@ -1934,7 +1924,7 @@ static int rip_read(struct thread *t) "RIPv2 authentication failed: no auth RTE in packet"); ripd_notif_send_auth_type_failure(ifp->name); rip_peer_bad_packet(rip, &from); - return -1; + return; } /* First RTE must be an Authentication Family RTE */ @@ -1944,7 +1934,7 @@ static int rip_read(struct thread *t) "RIPv2 dropped because authentication enabled"); ripd_notif_send_auth_type_failure(ifp->name); rip_peer_bad_packet(rip, &from); - return -1; + return; } /* Check RIPv2 authentication. */ @@ -1980,7 +1970,7 @@ static int rip_read(struct thread *t) auth_desc); ripd_notif_send_auth_failure(ifp->name); rip_peer_bad_packet(rip, &from); - return -1; + return; } } @@ -2010,8 +2000,6 @@ static int rip_read(struct thread *t) rip_peer_bad_packet(rip, &from); break; } - - return len; } /* Write routing table entry to the stream and return next index of @@ -2122,270 +2110,240 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to, subnetted = 1; } - for (rp = route_top(rip->table); rp; rp = route_next(rp)) - if ((list = rp->info) != NULL && listcount(list) != 0) { - rinfo = listgetdata(listhead(list)); - /* For RIPv1, if we are subnetted, output subnets in our - * network */ - /* that have the same mask as the output "interface". - * For other */ - /* networks, only the classfull version is output. */ + for (rp = route_top(rip->table); rp; rp = route_next(rp)) { + list = rp->info; - if (version == RIPv1) { - p = (struct prefix_ipv4 *)&rp->p; + if (list == NULL) + continue; - if (IS_RIP_DEBUG_PACKET) - zlog_debug( - "RIPv1 mask check, %pFX considered for output", - &rp->p); - - if (subnetted - && prefix_match( - (struct prefix *)&ifaddrclass, - &rp->p)) { - if ((ifc->address->prefixlen - != rp->p.prefixlen) - && (rp->p.prefixlen - != IPV4_MAX_BITLEN)) - continue; - } else { - memcpy(&classfull, &rp->p, - sizeof(struct prefix_ipv4)); - apply_classful_mask_ipv4(&classfull); - if (rp->p.u.prefix4.s_addr != INADDR_ANY - && classfull.prefixlen - != rp->p.prefixlen) - continue; - } - if (IS_RIP_DEBUG_PACKET) - zlog_debug( - "RIPv1 mask check, %pFX made it through", - &rp->p); - } else - p = (struct prefix_ipv4 *)&rp->p; + if (listcount(list) == 0) + continue; - /* Apply output filters. */ - ret = rip_filter(RIP_FILTER_OUT, p, ri); - if (ret < 0) - continue; + rinfo = listgetdata(listhead(list)); + /* + * For RIPv1, if we are subnetted, output subnets in our + * network that have the same mask as the output "interface". + * For other networks, only the classfull version is output. + */ + if (version == RIPv1) { + p = (struct prefix_ipv4 *)&rp->p; - /* Changed route only output. */ - if (route_type == rip_changed_route - && (!(rinfo->flags & RIP_RTF_CHANGED))) - continue; + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIPv1 mask check, %pFX considered for output", + &rp->p); + + if (subnetted && + prefix_match((struct prefix *)&ifaddrclass, + &rp->p)) { + if ((ifc->address->prefixlen != + rp->p.prefixlen) && + (rp->p.prefixlen != IPV4_MAX_BITLEN)) + continue; + } else { + memcpy(&classfull, &rp->p, + sizeof(struct prefix_ipv4)); + apply_classful_mask_ipv4(&classfull); + if (rp->p.u.prefix4.s_addr != INADDR_ANY && + classfull.prefixlen != rp->p.prefixlen) + continue; + } + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIPv1 mask check, %pFX made it through", + &rp->p); + } else + p = (struct prefix_ipv4 *)&rp->p; - /* Split horizon. */ - /* if (split_horizon == rip_split_horizon) */ - if (ri->split_horizon == RIP_SPLIT_HORIZON) { - /* - * We perform split horizon for RIP and - * connected route. - * For rip routes, we want to suppress the route - * if we would - * end up sending the route back on the - * interface that we - * learned it from, with a higher metric. For - * connected routes, - * we suppress the route if the prefix is a - * subset of the - * source address that we are going to use for - * the packet - * (in order to handle the case when multiple - * subnets are - * configured on the same interface). - */ - int suppress = 0; - struct rip_info *tmp_rinfo = NULL; - struct connected *tmp_ifc = NULL; - - for (ALL_LIST_ELEMENTS_RO(list, listnode, - tmp_rinfo)) - if (tmp_rinfo->type == ZEBRA_ROUTE_RIP - && tmp_rinfo->nh.ifindex - == ifc->ifp->ifindex) { - suppress = 1; - break; - } + /* Apply output filters. */ + ret = rip_filter(RIP_FILTER_OUT, p, ri); + if (ret < 0) + continue; + + /* Changed route only output. */ + if (route_type == rip_changed_route && + (!(rinfo->flags & RIP_RTF_CHANGED))) + continue; - if (!suppress - && rinfo->type == ZEBRA_ROUTE_CONNECT) { - for (ALL_LIST_ELEMENTS_RO( - ifc->ifp->connected, - listnode, tmp_ifc)) - if (prefix_match( - (struct prefix *)p, - tmp_ifc->address)) { - suppress = 1; - break; - } + /* Split horizon. */ + if (ri->split_horizon == RIP_SPLIT_HORIZON) { + /* + * We perform split horizon for RIP and connected + * route. For rip routes, we want to suppress the + * route if we would end up sending the route back on + * the interface that we learned it from, with a + * higher metric. For connected routes, we suppress + * the route if the prefix is a subset of the source + * address that we are going to use for the packet + * (in order to handle the case when multiple subnets + * are configured on the same interface). + */ + int suppress = 0; + struct rip_info *tmp_rinfo = NULL; + struct connected *tmp_ifc = NULL; + + for (ALL_LIST_ELEMENTS_RO(list, listnode, tmp_rinfo)) + if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && + tmp_rinfo->nh.ifindex == + ifc->ifp->ifindex) { + suppress = 1; + break; } - if (suppress) - continue; + if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT) { + for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, + listnode, tmp_ifc)) + if (prefix_match((struct prefix *)p, + tmp_ifc->address)) { + suppress = 1; + break; + } } - /* Preparation for route-map. */ - rinfo->metric_set = 0; - rinfo->nexthop_out.s_addr = 0; - rinfo->metric_out = rinfo->metric; - rinfo->tag_out = rinfo->tag; - rinfo->ifindex_out = ifc->ifp->ifindex; - - /* In order to avoid some local loops, - * if the RIP route has a nexthop via this interface, - * keep the nexthop, - * otherwise set it to 0. The nexthop should not be - * propagated - * beyond the local broadcast/multicast area in order - * to avoid an IGP multi-level recursive look-up. - * see (4.4) - */ - if (rinfo->nh.ifindex == ifc->ifp->ifindex) - rinfo->nexthop_out = rinfo->nh.gate.ipv4; + if (suppress) + continue; + } - /* Interface route-map */ - if (ri->routemap[RIP_FILTER_OUT]) { - ret = route_map_apply( - ri->routemap[RIP_FILTER_OUT], - (struct prefix *)p, rinfo); + /* Preparation for route-map. */ + rinfo->metric_set = 0; + rinfo->nexthop_out.s_addr = 0; + rinfo->metric_out = rinfo->metric; + rinfo->tag_out = rinfo->tag; + rinfo->ifindex_out = ifc->ifp->ifindex; + + /* In order to avoid some local loops, if the RIP route has + * a nexthop via this interface, keep the nexthop, otherwise + * set it to 0. The nexthop should not be propagated beyond + * the local broadcast/multicast area in order to avoid an + * IGP multi-level recursive look-up. see (4.4) + */ + if (rinfo->nh.ifindex == ifc->ifp->ifindex) + rinfo->nexthop_out = rinfo->nh.gate.ipv4; - if (ret == RMAP_DENYMATCH) { - if (IS_RIP_DEBUG_PACKET) - zlog_debug( - "RIP %pFX is filtered by route-map out", - p); - continue; - } + /* Interface route-map */ + if (ri->routemap[RIP_FILTER_OUT]) { + ret = route_map_apply(ri->routemap[RIP_FILTER_OUT], + (struct prefix *)p, rinfo); + + if (ret == RMAP_DENYMATCH) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "RIP %pFX is filtered by route-map out", + p); + continue; } + } - /* Apply redistribute route map - continue, if deny */ - if (rip->redist[rinfo->type].route_map.name - && rinfo->sub_type != RIP_ROUTE_INTERFACE) { - ret = route_map_apply( - rip->redist[rinfo->type].route_map.map, - (struct prefix *)p, rinfo); + /* Apply redistribute route map - continue, if deny */ + if (rip->redist[rinfo->type].route_map.name && + rinfo->sub_type != RIP_ROUTE_INTERFACE) { + ret = route_map_apply( + rip->redist[rinfo->type].route_map.map, + (struct prefix *)p, rinfo); - if (ret == RMAP_DENYMATCH) { - if (IS_RIP_DEBUG_PACKET) - zlog_debug( - "%pFX is filtered by route-map", - p); - continue; - } + if (ret == RMAP_DENYMATCH) { + if (IS_RIP_DEBUG_PACKET) + zlog_debug( + "%pFX is filtered by route-map", + p); + continue; } + } - /* When route-map does not set metric. */ - if (!rinfo->metric_set) { - /* If redistribute metric is set. */ - if (rip->redist[rinfo->type].metric_config - && rinfo->metric != RIP_METRIC_INFINITY) { - rinfo->metric_out = - rip->redist[rinfo->type].metric; - } else { - /* If the route is not connected or - localy generated - one, use default-metric value*/ - if (rinfo->type != ZEBRA_ROUTE_RIP - && rinfo->type - != ZEBRA_ROUTE_CONNECT - && rinfo->metric - != RIP_METRIC_INFINITY) - rinfo->metric_out = - rip->default_metric; - } + /* When route-map does not set metric. */ + if (!rinfo->metric_set) { + /* If redistribute metric is set. */ + if (rip->redist[rinfo->type].metric_config && + rinfo->metric != RIP_METRIC_INFINITY) { + rinfo->metric_out = + rip->redist[rinfo->type].metric; + } else { + /* If the route is not connected or localy + * generated one, use default-metric value + */ + if (rinfo->type != ZEBRA_ROUTE_RIP && + rinfo->type != ZEBRA_ROUTE_CONNECT && + rinfo->metric != RIP_METRIC_INFINITY) + rinfo->metric_out = rip->default_metric; } + } - /* Apply offset-list */ - if (rinfo->metric != RIP_METRIC_INFINITY) - rip_offset_list_apply_out(p, ifc->ifp, - &rinfo->metric_out); - - if (rinfo->metric_out > RIP_METRIC_INFINITY) - rinfo->metric_out = RIP_METRIC_INFINITY; - - /* Perform split-horizon with poisoned reverse - * for RIP and connected routes. - **/ - if (ri->split_horizon - == RIP_SPLIT_HORIZON_POISONED_REVERSE) { - /* - * We perform split horizon for RIP and - * connected route. - * For rip routes, we want to suppress the route - * if we would - * end up sending the route back on the - * interface that we - * learned it from, with a higher metric. For - * connected routes, - * we suppress the route if the prefix is a - * subset of the - * source address that we are going to use for - * the packet - * (in order to handle the case when multiple - * subnets are - * configured on the same interface). - */ - struct rip_info *tmp_rinfo = NULL; - struct connected *tmp_ifc = NULL; - - for (ALL_LIST_ELEMENTS_RO(list, listnode, - tmp_rinfo)) - if (tmp_rinfo->type == ZEBRA_ROUTE_RIP - && tmp_rinfo->nh.ifindex - == ifc->ifp->ifindex) + /* Apply offset-list */ + if (rinfo->metric != RIP_METRIC_INFINITY) + rip_offset_list_apply_out(p, ifc->ifp, + &rinfo->metric_out); + + if (rinfo->metric_out > RIP_METRIC_INFINITY) + rinfo->metric_out = RIP_METRIC_INFINITY; + + /* Perform split-horizon with poisoned reverse + * for RIP and connected routes. + **/ + if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) { + /* + * We perform split horizon for RIP and connected + * route. For rip routes, we want to suppress the + * route if we would end up sending the route back + * on the interface that we learned it from, with a + * higher metric. For connected routes, we suppress + * the route if the prefix is a subset of the source + * address that we are going to use for the packet + * (in order to handle the case when multiple + * subnets are configured on the same interface). + */ + struct rip_info *tmp_rinfo = NULL; + struct connected *tmp_ifc = NULL; + + for (ALL_LIST_ELEMENTS_RO(list, listnode, tmp_rinfo)) + if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && + tmp_rinfo->nh.ifindex == ifc->ifp->ifindex) + rinfo->metric_out = RIP_METRIC_INFINITY; + + if (rinfo->metric_out != RIP_METRIC_INFINITY && + rinfo->type == ZEBRA_ROUTE_CONNECT) { + for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, + listnode, tmp_ifc)) + if (prefix_match((struct prefix *)p, + tmp_ifc->address)) { rinfo->metric_out = RIP_METRIC_INFINITY; - - if (rinfo->metric_out != RIP_METRIC_INFINITY - && rinfo->type == ZEBRA_ROUTE_CONNECT) { - for (ALL_LIST_ELEMENTS_RO( - ifc->ifp->connected, - listnode, tmp_ifc)) - if (prefix_match( - (struct prefix *)p, - tmp_ifc->address)) { - rinfo->metric_out = - RIP_METRIC_INFINITY; - break; - } - } + break; + } } + } - /* Prepare preamble, auth headers, if needs be */ - if (num == 0) { - stream_putc(s, RIP_RESPONSE); - stream_putc(s, version); - stream_putw(s, 0); - - /* auth header for !v1 && !no_auth */ - if ((ri->auth_type != RIP_NO_AUTH) - && (version != RIPv1)) - doff = rip_auth_header_write( - s, ri, key, auth_str, - RIP_AUTH_SIMPLE_SIZE); - } + /* Prepare preamble, auth headers, if needs be */ + if (num == 0) { + stream_putc(s, RIP_RESPONSE); + stream_putc(s, version); + stream_putw(s, 0); + + /* auth header for !v1 && !no_auth */ + if ((ri->auth_type != RIP_NO_AUTH) && + (version != RIPv1)) + doff = rip_auth_header_write( + s, ri, key, auth_str, + RIP_AUTH_SIMPLE_SIZE); + } - /* Write RTE to the stream. */ - num = rip_write_rte(num, s, p, version, rinfo); - if (num == rtemax) { - if (version == RIPv2 - && ri->auth_type == RIP_AUTH_MD5) - rip_auth_md5_set(s, ri, doff, auth_str, - RIP_AUTH_SIMPLE_SIZE); - - ret = rip_send_packet(STREAM_DATA(s), - stream_get_endp(s), to, - ifc); - - if (ret >= 0 && IS_RIP_DEBUG_SEND) - rip_packet_dump((struct rip_packet *) - STREAM_DATA(s), - stream_get_endp(s), - "SEND"); - num = 0; - stream_reset(s); - } + /* Write RTE to the stream. */ + num = rip_write_rte(num, s, p, version, rinfo); + if (num == rtemax) { + if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) + rip_auth_md5_set(s, ri, doff, auth_str, + RIP_AUTH_SIMPLE_SIZE); + + ret = rip_send_packet(STREAM_DATA(s), + stream_get_endp(s), to, ifc); + + if (ret >= 0 && IS_RIP_DEBUG_SEND) + rip_packet_dump( + (struct rip_packet *)STREAM_DATA(s), + stream_get_endp(s), "SEND"); + num = 0; + stream_reset(s); } + } /* Flush unwritten RTE. */ if (num != 0) { @@ -2481,65 +2439,63 @@ static void rip_update_process(struct rip *rip, int route_type) if (ri->passive) continue; - if (ri->running) { - /* - * If there is no version configuration in the - * interface, - * use rip's version setting. - */ - int vsend = ((ri->ri_send == RI_RIP_UNSPEC) - ? rip->version_send - : ri->ri_send); + if (!ri->running) + continue; - if (IS_RIP_DEBUG_EVENT) - zlog_debug("SEND UPDATE to %s ifindex %d", - ifp->name, ifp->ifindex); - - /* send update on each connected network */ - for (ALL_LIST_ELEMENTS(ifp->connected, ifnode, ifnnode, - connected)) { - if (connected->address->family == AF_INET) { - if (vsend & RIPv1) - rip_update_interface( - connected, RIPv1, - route_type); - if ((vsend & RIPv2) - && if_is_multicast(ifp)) - rip_update_interface( - connected, RIPv2, - route_type); - } + /* + * If there is no version configuration in the + * interface, use rip's version setting. + */ + int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? rip->version_send + : ri->ri_send); + + if (IS_RIP_DEBUG_EVENT) + zlog_debug("SEND UPDATE to %s ifindex %d", ifp->name, + ifp->ifindex); + + /* send update on each connected network */ + for (ALL_LIST_ELEMENTS(ifp->connected, ifnode, ifnnode, + connected)) { + if (connected->address->family == AF_INET) { + if (vsend & RIPv1) + rip_update_interface(connected, RIPv1, + route_type); + if ((vsend & RIPv2) && if_is_multicast(ifp)) + rip_update_interface(connected, RIPv2, + route_type); } } } /* RIP send updates to each neighbor. */ - for (rp = route_top(rip->neighbor); rp; rp = route_next(rp)) - if (rp->info != NULL) { - p = &rp->p; - - connected = if_lookup_address(&p->u.prefix4, AF_INET, - rip->vrf->vrf_id); - if (!connected) { - zlog_warn( - "Neighbor %pI4 doesn't have connected interface!", - &p->u.prefix4); - continue; - } + for (rp = route_top(rip->neighbor); rp; rp = route_next(rp)) { + if (rp->info == NULL) + continue; - /* Set destination address and port */ - memset(&to, 0, sizeof(struct sockaddr_in)); - to.sin_addr = p->u.prefix4; - to.sin_port = htons(RIP_PORT_DEFAULT); + p = &rp->p; - /* RIP version is rip's configuration. */ - rip_output_process(connected, &to, route_type, - rip->version_send); + connected = if_lookup_address(&p->u.prefix4, AF_INET, + rip->vrf->vrf_id); + if (!connected) { + zlog_warn( + "Neighbor %pI4 doesn't have connected interface!", + &p->u.prefix4); + continue; } + + /* Set destination address and port */ + memset(&to, 0, sizeof(struct sockaddr_in)); + to.sin_addr = p->u.prefix4; + to.sin_port = htons(RIP_PORT_DEFAULT); + + /* RIP version is rip's configuration. */ + rip_output_process(connected, &to, route_type, + rip->version_send); + } } /* RIP's periodical timer. */ -static int rip_update(struct thread *t) +static void rip_update(struct thread *t) { struct rip *rip = THREAD_ARG(t); @@ -2556,8 +2512,6 @@ static int rip_update(struct thread *t) /* Register myself. */ rip_event(rip, RIP_UPDATE_EVENT, 0); - - return 0; } /* Walk down the RIP routing table then clear changed flag. */ @@ -2568,18 +2522,22 @@ static void rip_clear_changed_flag(struct rip *rip) struct list *list = NULL; struct listnode *listnode = NULL; - for (rp = route_top(rip->table); rp; rp = route_next(rp)) - if ((list = rp->info) != NULL) - for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { - UNSET_FLAG(rinfo->flags, RIP_RTF_CHANGED); - /* This flag can be set only on the first entry. - */ - break; - } + for (rp = route_top(rip->table); rp; rp = route_next(rp)) { + list = rp->info; + + if (list == NULL) + continue; + + for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { + UNSET_FLAG(rinfo->flags, RIP_RTF_CHANGED); + /* This flag can be set only on the first entry. */ + break; + } + } } /* Triggered update interval timer. */ -static int rip_triggered_interval(struct thread *t) +static void rip_triggered_interval(struct thread *t) { struct rip *rip = THREAD_ARG(t); @@ -2587,11 +2545,10 @@ static int rip_triggered_interval(struct thread *t) rip->trigger = 0; rip_triggered_update(t); } - return 0; } /* Execute triggered update. */ -static int rip_triggered_update(struct thread *t) +static void rip_triggered_update(struct thread *t) { struct rip *rip = THREAD_ARG(t); int interval; @@ -2620,8 +2577,6 @@ static int rip_triggered_update(struct thread *t) thread_add_timer(master, rip_triggered_interval, rip, interval, &rip->t_triggered_interval); - - return 0; } /* Withdraw redistributed route. */ @@ -2631,34 +2586,39 @@ void rip_redistribute_withdraw(struct rip *rip, int type) struct rip_info *rinfo = NULL; struct list *list = NULL; - for (rp = route_top(rip->table); rp; rp = route_next(rp)) - if ((list = rp->info) != NULL) { - rinfo = listgetdata(listhead(list)); - if (rinfo->type == type - && rinfo->sub_type != RIP_ROUTE_INTERFACE) { - /* Perform poisoned reverse. */ - rinfo->metric = RIP_METRIC_INFINITY; - RIP_TIMER_ON(rinfo->t_garbage_collect, - rip_garbage_collect, - rip->garbage_time); - RIP_TIMER_OFF(rinfo->t_timeout); - rinfo->flags |= RIP_RTF_CHANGED; + for (rp = route_top(rip->table); rp; rp = route_next(rp)) { + list = rp->info; - if (IS_RIP_DEBUG_EVENT) { - struct prefix_ipv4 *p = - (struct prefix_ipv4 *)&rp->p; + if (list == NULL) + continue; - zlog_debug( - "Poisone %pFX on the interface %s with an infinity metric [withdraw]", - p, - ifindex2ifname( - rinfo->nh.ifindex, - rip->vrf->vrf_id)); - } + rinfo = listgetdata(listhead(list)); - rip_event(rip, RIP_TRIGGERED_UPDATE, 0); - } + if (rinfo->type != type) + continue; + + if (rinfo->sub_type == RIP_ROUTE_INTERFACE) + continue; + + /* Perform poisoned reverse. */ + rinfo->metric = RIP_METRIC_INFINITY; + RIP_TIMER_ON(rinfo->t_garbage_collect, rip_garbage_collect, + rip->garbage_time); + RIP_TIMER_OFF(rinfo->t_timeout); + rinfo->flags |= RIP_RTF_CHANGED; + + if (IS_RIP_DEBUG_EVENT) { + struct prefix_ipv4 *p = (struct prefix_ipv4 *)&rp->p; + + zlog_debug( + "Poisone %pFX on the interface %s with an infinity metric [withdraw]", + p, + ifindex2ifname(rinfo->nh.ifindex, + rip->vrf->vrf_id)); } + + rip_event(rip, RIP_TRIGGERED_UPDATE, 0); + } } struct rip *rip_lookup_by_vrf_id(vrf_id_t vrf_id) @@ -2915,19 +2875,20 @@ static void rip_distance_show(struct vty *vty, struct rip *rip) vty_out(vty, " Distance: (default is %u)\n", rip->distance ? rip->distance : ZEBRA_RIP_DISTANCE_DEFAULT); - for (rn = route_top(rip->distance_table); rn; rn = route_next(rn)) - if ((rdistance = rn->info) != NULL) { - if (header) { - vty_out(vty, - " Address Distance List\n"); - header = 0; - } - snprintfrr(buf, sizeof(buf), "%pFX", &rn->p); - vty_out(vty, " %-20s %4d %s\n", buf, - rdistance->distance, - rdistance->access_list ? rdistance->access_list - : ""); + for (rn = route_top(rip->distance_table); rn; rn = route_next(rn)) { + rdistance = rn->info; + + if (rdistance == NULL) + continue; + + if (header) { + vty_out(vty, " Address Distance List\n"); + header = 0; } + snprintfrr(buf, sizeof(buf), "%pFX", &rn->p); + vty_out(vty, " %-20s %4d %s\n", buf, rdistance->distance, + rdistance->access_list ? rdistance->access_list : ""); + } } /* Update ECMP routes to zebra when ECMP is disabled. */ @@ -2938,31 +2899,38 @@ void rip_ecmp_disable(struct rip *rip) struct list *list; struct listnode *node, *nextnode; - for (rp = route_top(rip->table); rp; rp = route_next(rp)) - if ((list = rp->info) != NULL && listcount(list) > 1) { - rinfo = listgetdata(listhead(list)); - if (!rip_route_rte(rinfo)) - continue; + for (rp = route_top(rip->table); rp; rp = route_next(rp)) { + list = rp->info; - /* Drop all other entries, except the first one. */ - for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) - if (tmp_rinfo != rinfo) { - RIP_TIMER_OFF(tmp_rinfo->t_timeout); - RIP_TIMER_OFF( - tmp_rinfo->t_garbage_collect); - list_delete_node(list, node); - rip_info_free(tmp_rinfo); - } + if (!list) + continue; + if (listcount(list) == 0) + continue; - /* Update zebra. */ - rip_zebra_ipv4_add(rip, rp); + rinfo = listgetdata(listhead(list)); + if (!rip_route_rte(rinfo)) + continue; - /* Set the route change flag. */ - SET_FLAG(rinfo->flags, RIP_RTF_CHANGED); + /* Drop all other entries, except the first one. */ + for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) { + if (tmp_rinfo == rinfo) + continue; - /* Signal the output process to trigger an update. */ - rip_event(rip, RIP_TRIGGERED_UPDATE, 0); + RIP_TIMER_OFF(tmp_rinfo->t_timeout); + RIP_TIMER_OFF(tmp_rinfo->t_garbage_collect); + list_delete_node(list, node); + rip_info_free(tmp_rinfo); } + + /* Update zebra. */ + rip_zebra_ipv4_add(rip, rp); + + /* Set the route change flag. */ + SET_FLAG(rinfo->flags, RIP_RTF_CHANGED); + + /* Signal the output process to trigger an update. */ + rip_event(rip, RIP_TRIGGERED_UPDATE, 0); + } } /* Print out routes update time. */ @@ -3043,82 +3011,77 @@ DEFUN (show_ip_rip, " (i) - interface\n\n" " Network Next Hop Metric From Tag Time\n"); - for (np = route_top(rip->table); np; np = route_next(np)) - if ((list = np->info) != NULL) - for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { - int len; - - len = vty_out( - vty, "%c(%s) %pFX", - /* np->lock, For debugging. */ - zebra_route_char(rinfo->type), - rip_route_type_print(rinfo->sub_type), - &np->p); - - len = 24 - len; - - if (len > 0) - vty_out(vty, "%*s", len, " "); - - switch (rinfo->nh.type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, "%-20pI4 %2d ", - &rinfo->nh.gate.ipv4, - rinfo->metric); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, - "0.0.0.0 %2d ", - rinfo->metric); - break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out(vty, - "blackhole %2d ", - rinfo->metric); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, - "V6 Address Hidden %2d ", - rinfo->metric); - break; - } + for (np = route_top(rip->table); np; np = route_next(np)) { + list = np->info; - /* Route which exist in kernel routing table. */ - if ((rinfo->type == ZEBRA_ROUTE_RIP) - && (rinfo->sub_type == RIP_ROUTE_RTE)) { - vty_out(vty, "%-15pI4 ", - &rinfo->from); - vty_out(vty, "%3" ROUTE_TAG_PRI " ", - (route_tag_t)rinfo->tag); - rip_vty_out_uptime(vty, rinfo); - } else if (rinfo->metric - == RIP_METRIC_INFINITY) { - vty_out(vty, "self "); - vty_out(vty, "%3" ROUTE_TAG_PRI " ", - (route_tag_t)rinfo->tag); - rip_vty_out_uptime(vty, rinfo); - } else { - if (rinfo->external_metric) { - len = vty_out( - vty, "self (%s:%d)", - zebra_route_string( - rinfo->type), - rinfo->external_metric); - len = 16 - len; - if (len > 0) - vty_out(vty, "%*s", len, - " "); - } else - vty_out(vty, - "self "); - vty_out(vty, "%3" ROUTE_TAG_PRI, - (route_tag_t)rinfo->tag); - } + if (!list) + continue; + + for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { + int len; - vty_out(vty, "\n"); + len = vty_out(vty, "%c(%s) %pFX", + /* np->lock, For debugging. */ + zebra_route_char(rinfo->type), + rip_route_type_print(rinfo->sub_type), + &np->p); + + len = 24 - len; + + if (len > 0) + vty_out(vty, "%*s", len, " "); + + switch (rinfo->nh.type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out(vty, "%-20pI4 %2d ", + &rinfo->nh.gate.ipv4, rinfo->metric); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out(vty, "0.0.0.0 %2d ", + rinfo->metric); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out(vty, "blackhole %2d ", + rinfo->metric); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, "V6 Address Hidden %2d ", + rinfo->metric); + break; + } + + /* Route which exist in kernel routing table. */ + if ((rinfo->type == ZEBRA_ROUTE_RIP) && + (rinfo->sub_type == RIP_ROUTE_RTE)) { + vty_out(vty, "%-15pI4 ", &rinfo->from); + vty_out(vty, "%3" ROUTE_TAG_PRI " ", + (route_tag_t)rinfo->tag); + rip_vty_out_uptime(vty, rinfo); + } else if (rinfo->metric == RIP_METRIC_INFINITY) { + vty_out(vty, "self "); + vty_out(vty, "%3" ROUTE_TAG_PRI " ", + (route_tag_t)rinfo->tag); + rip_vty_out_uptime(vty, rinfo); + } else { + if (rinfo->external_metric) { + len = vty_out( + vty, "self (%s:%d)", + zebra_route_string(rinfo->type), + rinfo->external_metric); + len = 16 - len; + if (len > 0) + vty_out(vty, "%*s", len, " "); + } else + vty_out(vty, "self "); + vty_out(vty, "%3" ROUTE_TAG_PRI, + (route_tag_t)rinfo->tag); } + + vty_out(vty, "\n"); + } + } return CMD_SUCCESS; } @@ -3218,20 +3181,17 @@ DEFUN (show_ip_rip_status, vty_out(vty, " Routing for Networks:\n"); rip_show_network_config(vty, rip); - { - int found_passive = 0; - FOR_ALL_INTERFACES (rip->vrf, ifp) { - ri = ifp->info; - - if ((ri->enable_network || ri->enable_interface) - && ri->passive) { - if (!found_passive) { - vty_out(vty, - " Passive Interface(s):\n"); - found_passive = 1; - } - vty_out(vty, " %s\n", ifp->name); + int found_passive = 0; + FOR_ALL_INTERFACES (rip->vrf, ifp) { + ri = ifp->info; + + if ((ri->enable_network || ri->enable_interface) && + ri->passive) { + if (!found_passive) { + vty_out(vty, " Passive Interface(s):\n"); + found_passive = 1; } + vty_out(vty, " %s\n", ifp->name); } } diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index a6d379fda..57bc40f00 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -601,7 +601,7 @@ int ripng_enable_if_delete(struct ripng *ripng, const char *ifname) } /* Wake up interface. */ -static int ripng_interface_wakeup(struct thread *t) +static void ripng_interface_wakeup(struct thread *t) { struct interface *ifp; struct ripng_interface *ri; @@ -616,7 +616,7 @@ static int ripng_interface_wakeup(struct thread *t) flog_err_sys(EC_LIB_SOCKET, "multicast join failed, interface %s not running", ifp->name); - return 0; + return; } /* Set running flag. */ @@ -624,8 +624,6 @@ static int ripng_interface_wakeup(struct thread *t) /* Send RIP request to the interface. */ ripng_request(ifp); - - return 0; } static void ripng_connect_set(struct interface *ifp, int set) diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c index 554b1d68f..010fdda89 100644 --- a/ripngd/ripng_peer.c +++ b/ripngd/ripng_peer.c @@ -75,15 +75,13 @@ struct ripng_peer *ripng_peer_lookup_next(struct ripng *ripng, /* RIPng peer is timeout. * Garbage collector. **/ -static int ripng_peer_timeout(struct thread *t) +static void ripng_peer_timeout(struct thread *t) { struct ripng_peer *peer; peer = THREAD_ARG(t); listnode_delete(peer->ripng->peer_list, peer); ripng_peer_free(peer); - - return 0; } /* Get RIPng peer. At the same time update timeout thread. */ diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 27cffd432..e103cdc3a 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -61,7 +61,7 @@ void ripng_output_process(struct interface *, struct sockaddr_in6 *, int); static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf, int sock); static void ripng_instance_disable(struct ripng *ripng); -int ripng_triggered_update(struct thread *); +static void ripng_triggered_update(struct thread *); static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, struct if_rmap *if_rmap); @@ -423,7 +423,7 @@ static int ripng_lladdr_check(struct interface *ifp, struct in6_addr *addr) } /* RIPng route garbage collect timer. */ -static int ripng_garbage_collect(struct thread *t) +static void ripng_garbage_collect(struct thread *t) { struct ripng_info *rinfo; struct agg_node *rp; @@ -445,8 +445,6 @@ static int ripng_garbage_collect(struct thread *t) /* Free RIPng routing information. */ ripng_info_free(rinfo); - - return 0; } static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo); @@ -602,14 +600,12 @@ struct ripng_info *ripng_ecmp_delete(struct ripng *ripng, } /* Timeout RIPng routes. */ -static int ripng_timeout(struct thread *t) +static void ripng_timeout(struct thread *t) { struct ripng_info *rinfo = THREAD_ARG(t); struct ripng *ripng = ripng_info_get_instance(rinfo); ripng_ecmp_delete(ripng, rinfo); - - return 0; } static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo) @@ -1301,7 +1297,7 @@ static void ripng_request_process(struct ripng_packet *packet, int size, } /* First entry point of reading RIPng packet. */ -static int ripng_read(struct thread *thread) +static void ripng_read(struct thread *thread) { struct ripng *ripng = THREAD_ARG(thread); int len; @@ -1330,7 +1326,7 @@ static int ripng_read(struct thread *thread) if (len < 0) { zlog_warn("RIPng recvfrom failed (VRF %s): %s.", ripng->vrf_name, safe_strerror(errno)); - return len; + return; } /* Check RTE boundary. RTE size (Packet length - RIPng header size @@ -1339,7 +1335,7 @@ static int ripng_read(struct thread *thread) zlog_warn("RIPng invalid packet size %d from %pI6 (VRF %s)", len, &from.sin6_addr, ripng->vrf_name); ripng_peer_bad_packet(ripng, &from); - return 0; + return; } packet = (struct ripng_packet *)STREAM_DATA(ripng->ibuf); @@ -1361,7 +1357,7 @@ static int ripng_read(struct thread *thread) zlog_warn( "RIPng packet comes from unknown interface %d (VRF %s)", ifindex, ripng->vrf_name); - return 0; + return; } /* Packet version mismatch checking. */ @@ -1370,7 +1366,7 @@ static int ripng_read(struct thread *thread) "RIPng packet version %d doesn't fit to my version %d (VRF %s)", packet->version, ripng->version, ripng->vrf_name); ripng_peer_bad_packet(ripng, &from); - return 0; + return; } /* Process RIPng packet. */ @@ -1387,7 +1383,6 @@ static int ripng_read(struct thread *thread) ripng_peer_bad_packet(ripng, &from); break; } - return 0; } /* Walk down the RIPng routing table then clear changed flag. */ @@ -1410,7 +1405,7 @@ static void ripng_clear_changed_flag(struct ripng *ripng) /* Regular update of RIPng route. Send all routing formation to RIPng enabled interface. */ -static int ripng_update(struct thread *t) +static void ripng_update(struct thread *t) { struct ripng *ripng = THREAD_ARG(t); struct interface *ifp; @@ -1455,12 +1450,10 @@ static int ripng_update(struct thread *t) /* Reset flush event. */ ripng_event(ripng, RIPNG_UPDATE_EVENT, 0); - - return 0; } /* Triggered update interval timer. */ -static int ripng_triggered_interval(struct thread *t) +static void ripng_triggered_interval(struct thread *t) { struct ripng *ripng = THREAD_ARG(t); @@ -1468,11 +1461,10 @@ static int ripng_triggered_interval(struct thread *t) ripng->trigger = 0; ripng_triggered_update(t); } - return 0; } /* Execute triggered update. */ -int ripng_triggered_update(struct thread *t) +void ripng_triggered_update(struct thread *t) { struct ripng *ripng = THREAD_ARG(t); struct interface *ifp; @@ -1518,8 +1510,6 @@ int ripng_triggered_update(struct thread *t) thread_add_timer(master, ripng_triggered_interval, ripng, interval, &ripng->t_triggered_interval); - - return 0; } /* Write routing table entry to the stream and return next index of diff --git a/sharpd/sharp_logpump.c b/sharpd/sharp_logpump.c index 322d802b8..ad1051f22 100644 --- a/sharpd/sharp_logpump.c +++ b/sharpd/sharp_logpump.c @@ -43,7 +43,7 @@ static struct vty *lp_vty; extern struct thread_master *master; -static int logpump_done(struct thread *thread) +static void logpump_done(struct thread *thread) { double x; @@ -67,7 +67,6 @@ static int logpump_done(struct thread *thread) frr_pthread_stop(lpt, NULL); frr_pthread_destroy(lpt); lpt = NULL; - return 0; } static void *logpump_run(void *arg) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 0a323f744..78cc57cc4 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -29,7 +29,9 @@ #include "vrf.h" #include "zclient.h" #include "nexthop_group.h" +#include "linklist.h" #include "link_state.h" +#include "cspf.h" #include "sharpd/sharp_globals.h" #include "sharpd/sharp_zebra.h" @@ -425,7 +427,8 @@ DEFPY (install_seg6local_routes, End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\ End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\ End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\ - End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table>\ + End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\ + End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table>\ (1-1000000)$routes [repeat (2-1000)$rpt]", "Sharp routing Protocol\n" "install some routes\n" @@ -444,6 +447,8 @@ DEFPY (install_seg6local_routes, "V4 Nexthop address to use\n" "SRv6 End.DT6 function to use\n" "Redirect table id to use\n" + "SRv6 End.DT4 function to use\n" + "Redirect table id to use\n" "How many to create\n" "Should we repeat this command\n" "How many times to repeat this command\n") @@ -494,6 +499,9 @@ DEFPY (install_seg6local_routes, } else if (seg6l_enddt6) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6; ctx.table = seg6l_enddt6_table; + } else if (seg6l_enddt4) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DT4; + ctx.table = seg6l_enddt4_table; } else { action = ZEBRA_SEG6_LOCAL_ACTION_END; } @@ -532,7 +540,7 @@ DEFPY(vrf_label, vrf_label_cmd, vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { - vty_out(vty, "Unable to find vrf you silly head"); + vty_out(vty, "Unable to find vrf you silly head\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -1150,6 +1158,106 @@ DEFPY (show_sharp_segment_routing_srv6, return CMD_SUCCESS; } +DEFPY (show_sharp_cspf, + show_sharp_cspf_cmd, + "show sharp cspf source \ + destination \ + (0-16777215)$cost \ + [rsv-bw (0-7)$cos BANDWIDTH$bw]", + SHOW_STR + SHARP_STR + "Constraint Shortest Path First path computation\n" + "Source of the path\n" + "IPv4 Source address in dot decimal A.B.C.D\n" + "IPv6 Source address as X:X:X:X\n" + "Destination of the path\n" + "IPv4 Destination address in dot decimal A.B.C.D\n" + "IPv6 Destination address as X:X:X:X\n" + "Maximum Metric\n" + "Maximum TE Metric\n" + "Maxim Delay\n" + "Value of Maximum cost\n" + "Reserved Bandwidth of this path\n" + "Class of Service or Priority level\n" + "Bytes/second (IEEE floating point format)\n") +{ + + struct cspf *algo; + struct constraints csts; + struct c_path *path; + struct listnode *node; + struct ls_edge *edge; + int idx; + + if (sg.ted == NULL) { + vty_out(vty, "MPLS-TE import is not enabled\n"); + return CMD_WARNING; + } + + if ((src4.s_addr != INADDR_ANY && dst4.s_addr == INADDR_ANY) || + (src4.s_addr == INADDR_ANY && dst4.s_addr != INADDR_ANY)) { + vty_out(vty, "Don't mix IPv4 and IPv6 addresses\n"); + return CMD_WARNING; + } + + idx = 6; + memset(&csts, 0, sizeof(struct constraints)); + if (argv_find(argv, argc, "metric", &idx)) { + csts.ctype = CSPF_METRIC; + csts.cost = cost; + } + idx = 6; + if (argv_find(argv, argc, "te-metric", &idx)) { + csts.ctype = CSPF_TE_METRIC; + csts.cost = cost; + } + idx = 6; + if (argv_find(argv, argc, "delay", &idx)) { + csts.ctype = CSPF_DELAY; + csts.cost = cost; + } + if (argc > 9) { + if (sscanf(bw, "%g", &csts.bw) != 1) { + vty_out(vty, "Bandwidth constraints: fscanf: %s\n", + safe_strerror(errno)); + return CMD_WARNING_CONFIG_FAILED; + } + csts.cos = cos; + } + + /* Initialize and call point-to-point Path computation */ + if (src4.s_addr != INADDR_ANY) + algo = cspf_init_v4(NULL, sg.ted, src4, dst4, &csts); + else + algo = cspf_init_v6(NULL, sg.ted, src6, dst6, &csts); + path = compute_p2p_path(algo, sg.ted); + cspf_del(algo); + + if (!path) { + vty_out(vty, "Path computation failed without error\n"); + return CMD_SUCCESS; + } + if (path->status != SUCCESS) { + vty_out(vty, "Path computation failed: %d\n", path->status); + return CMD_SUCCESS; + } + + vty_out(vty, "Path computation success\n"); + vty_out(vty, "\tCost: %d\n", path->weight); + vty_out(vty, "\tEdges:"); + for (ALL_LIST_ELEMENTS_RO(path->edges, node, edge)) { + if (src4.s_addr != INADDR_ANY) + vty_out(vty, " %pI4", + &edge->attributes->standard.remote); + else + vty_out(vty, " %pI6", + &edge->attributes->standard.remote6); + } + vty_out(vty, "\n"); + + return CMD_SUCCESS; +} + void sharp_vty_init(void) { install_element(ENABLE_NODE, &install_routes_data_dump_cmd); @@ -1175,6 +1283,7 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &show_debugging_sharpd_cmd); install_element(ENABLE_NODE, &show_sharp_ted_cmd); + install_element(ENABLE_NODE, &show_sharp_cspf_cmd); install_element(ENABLE_NODE, &sharp_srv6_manager_get_locator_chunk_cmd); install_element(ENABLE_NODE, diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 8c9f0c278..5304b17f0 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -680,16 +680,17 @@ static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) { struct sharp_nh_tracker *nht; struct zapi_route nhr; + struct prefix matched; - if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { zlog_err("%s: Decode of update failed", __func__); return 0; } - zlog_debug("Received update for %pFX metric: %u", &nhr.prefix, - nhr.metric); + zlog_debug("Received update for %pFX actual match: %pFX metric: %u", + &matched, &nhr.prefix, nhr.metric); - nht = sharp_nh_tracker_get(&nhr.prefix); + nht = sharp_nh_tracker_get(&matched); nht->nhop_num = nhr.nexthop_num; nht->updates++; @@ -799,10 +800,12 @@ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) if (info.type == LINK_STATE_UPDATE) { lse = ls_stream2ted(sg.ted, s, false); - if (lse) + if (lse) { zlog_debug(" |- Got %s %s from Link State Database", status2txt[lse->status], type2txt[lse->type]); + lse->status = SYNC; + } else zlog_debug( "%s: Error to convert Stream into Link State", diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index 51252ede0..01033d041 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -306,6 +306,7 @@ parts: - make - gawk - libreadline-dev + - libelf-dev - texinfo - libncurses5-dev - texlive-latex-base diff --git a/staticd/static_main.c b/staticd/static_main.c index 6051b2df1..7badd5004 100644 --- a/staticd/static_main.c +++ b/staticd/static_main.c @@ -44,7 +44,6 @@ char backup_config_file[256]; bool mpls_enabled; - zebra_capabilities_t _caps_p[] = { }; diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index 470c7bdad..9ccffe53d 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -115,7 +115,7 @@ static int static_path_list_tag_modify(struct nb_cb_modify_args *args) } struct nexthop_iter { - int count; + uint32_t count; bool blackhole; }; @@ -169,7 +169,12 @@ static bool static_nexthop_create(struct nb_cb_create_args *args) if (iter.blackhole && iter.count > 1) { snprintf( args->errmsg, args->errmsg_len, - "Route can not have blackhole and non-blackhole nexthops simultaneously"); + "Route cannot have blackhole and non-blackhole nexthops simultaneously"); + return NB_ERR_VALIDATION; + } else if (iter.count > zebra_ecmp_count) { + snprintf(args->errmsg, args->errmsg_len, + "Route cannot have more than %d ECMP nexthops", + zebra_ecmp_count); return NB_ERR_VALIDATION; } break; diff --git a/staticd/static_routes.h b/staticd/static_routes.h index c901a8926..71c3689be 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -163,6 +163,7 @@ static_route_info_from_rnode(struct route_node *rn) } extern bool mpls_enabled; +extern uint32_t zebra_ecmp_count; extern struct zebra_privs_t static_privs; diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 311aeda33..bd293edeb 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -47,6 +47,7 @@ /* Zebra structure to hold current status. */ struct zclient *zclient; static struct hash *static_nht_hash; +uint32_t zebra_ecmp_count = MULTIPATH_NUM; /* Inteface addition message from zebra. */ static int static_ifp_create(struct interface *ifp) @@ -168,24 +169,25 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) { struct static_nht_data *nhtd, lookup; struct zapi_route nhr; + struct prefix matched; afi_t afi = AFI_IP; - if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { zlog_err("Failure to decode nexthop update message"); return 1; } - if (nhr.prefix.family == AF_INET6) + if (matched.family == AF_INET6) afi = AFI_IP6; if (nhr.type == ZEBRA_ROUTE_CONNECT) { - if (static_nexthop_is_local(vrf_id, &nhr.prefix, - nhr.prefix.family)) + if (static_nexthop_is_local(vrf_id, &matched, + nhr.prefix.family)) nhr.nexthop_num = 0; } memset(&lookup, 0, sizeof(lookup)); - lookup.nh = &nhr.prefix; + lookup.nh = &matched; lookup.nh_vrf_id = vrf_id; nhtd = hash_lookup(static_nht_hash, &lookup); @@ -193,8 +195,8 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) if (nhtd) { nhtd->nh_num = nhr.nexthop_num; - static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id); - static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi, + static_nht_reset_start(&matched, afi, nhtd->nh_vrf_id); + static_nht_update(NULL, &matched, nhr.nexthop_num, afi, nhtd->nh_vrf_id); } else zlog_err("No nhtd?"); @@ -205,6 +207,7 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) static void static_zebra_capabilities(struct zclient_capabilities *cap) { mpls_enabled = cap->mpls_enabled; + zebra_ecmp_count = cap->ecmp; } static unsigned int static_nht_hash_key(const void *data) @@ -301,12 +304,14 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg) static_nht_hash_alloc); nhtd->refcount++; - DEBUGD(&static_dbg_route, - "Registered nexthop(%pFX) for %pRN %d", &p, rn, - nhtd->nh_num); - if (nhtd->refcount > 1 && nhtd->nh_num) { - static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi, - nh->nh_vrf_id); + if (nhtd->refcount > 1) { + DEBUGD(&static_dbg_route, + "Already registered nexthop(%pFX) for %pRN %d", + &p, rn, nhtd->nh_num); + if (nhtd->nh_num) + static_nht_update(&rn->p, nhtd->nh, + nhtd->nh_num, afi, + nh->nh_vrf_id); return; } } else { @@ -322,6 +327,9 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg) static_nht_hash_free(nhtd); } + DEBUGD(&static_dbg_route, "%s nexthop(%pFX) for %pRN", + reg ? "Registering" : "Unregistering", &p, rn); + if (zclient_send_rnh(zclient, cmd, &p, false, false, nh->nh_vrf_id) == ZCLIENT_SEND_FAILURE) zlog_warn("%s: Failure to send nexthop to zebra", __func__); @@ -413,6 +421,10 @@ extern void static_zebra_route_add(struct static_path *pn, bool install) api.tableid = pn->table_id; } frr_each(static_nexthop_list, &pn->nexthop_list, nh) { + /* Don't overrun the nexthop array */ + if (nh_num == zebra_ecmp_count) + break; + api_nh = &api.nexthops[nh_num]; if (nh->nh_vrf_id == VRF_UNKNOWN) continue; diff --git a/tests/.gitignore b/tests/.gitignore index 53dbd68c9..70d0ef6e0 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -21,6 +21,7 @@ /lib/cli/test_commands_defun.c /lib/northbound/test_oper_data /lib/cxxcompat +/lib/fuzz_zlog /lib/test_assert /lib/test_atomlist /lib/test_buffer diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index c2d39752a..7288dc086 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -1062,8 +1062,7 @@ static void parse_test(struct test_segment *t) printf("\n"); - if (asp) - aspath_unintern(&asp); + aspath_unintern(&asp); } /* prepend testing */ @@ -1117,8 +1116,7 @@ static void empty_prepend_test(struct test_segment *t) printf(FAILED "!\n"); printf("\n"); - if (asp1) - aspath_unintern(&asp1); + aspath_unintern(&asp1); aspath_free(asp2); } @@ -1277,10 +1275,8 @@ static int handle_attr_test(struct aspath_tests *t) } out: - if (attr.aspath) - aspath_unintern(&attr.aspath); - if (asp) - aspath_unintern(&asp); + aspath_unintern(&attr.aspath); + aspath_unintern(&asp); return failed - initfail; } diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c index 64ecab913..ca6b18ecd 100644 --- a/tests/helpers/c/main.c +++ b/tests/helpers/c/main.c @@ -47,13 +47,12 @@ DEFUN (daemon_exit, } static int timer_count; -static int test_timer(struct thread *thread) +static void test_timer(struct thread *thread) { int *count = THREAD_ARG(thread); printf("run %d of timer\n", (*count)++); thread_add_timer(master, test_timer, count, 5, NULL); - return 0; } static void test_timer_init(void) diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c index 97aade657..8f0b92d0f 100644 --- a/tests/isisd/test_fuzz_isis_tlv.c +++ b/tests/isisd/test_fuzz_isis_tlv.c @@ -108,12 +108,12 @@ static int test(FILE *input, FILE *output) } fprintf(output, "Unpack log:\n%s", log); - const char *s_tlvs = isis_format_tlvs(tlvs); + const char *s_tlvs = isis_format_tlvs(tlvs, NULL); fprintf(output, "Unpacked TLVs:\n%s", s_tlvs); struct isis_item *orig_auth = tlvs->isis_auth.head; tlvs->isis_auth.head = NULL; - s_tlvs = isis_format_tlvs(tlvs); + s_tlvs = isis_format_tlvs(tlvs, NULL); struct isis_tlvs *tlv_copy = isis_copy_tlvs(tlvs); tlvs->isis_auth.head = orig_auth; isis_free_tlvs(tlvs); @@ -133,7 +133,7 @@ static int test(FILE *input, FILE *output) } char *orig_tlvs = XSTRDUP(MTYPE_TMP, s_tlvs); - s_tlvs = isis_format_tlvs(tlvs); + s_tlvs = isis_format_tlvs(tlvs, NULL); if (strcmp(orig_tlvs, s_tlvs)) { fprintf(output, @@ -166,7 +166,7 @@ static int test(FILE *input, FILE *output) fprintf(output, "Could not pack fragment, too large.\n"); assert(0); } - sbuf_push(&fragment_format, 0, "%s", isis_format_tlvs(tlvs)); + sbuf_push(&fragment_format, 0, "%s", isis_format_tlvs(tlvs, NULL)); isis_free_tlvs(tlvs); } list_delete(&fragments); diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz index accc906bf..20b1dc33f 100644 Binary files a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz and b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz differ diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index a30f33cca..971aba4c4 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -294,7 +294,7 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, /* Print the LDPDB. */ if (CHECK_FLAG(flags, F_DISPLAY_LSPDB)) - show_isis_database_lspdb(vty, area, level - 1, + show_isis_database_lspdb_vty(vty, area, level - 1, &area->lspdb[level - 1], NULL, ISIS_UI_LEVEL_DETAIL); diff --git a/tests/lib/fuzz_zlog.c b/tests/lib/fuzz_zlog.c new file mode 100644 index 000000000..14c857118 --- /dev/null +++ b/tests/lib/fuzz_zlog.c @@ -0,0 +1,130 @@ +/* + * zlog fuzzer target. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "log.h" +#include "zlog_5424.h" +#include "command.h" + +struct input_opts { + uint16_t out1_debug; + uint16_t out2_debug; + uint16_t out3_warn; + uint8_t fmt; + uint8_t dst; +}; + +static char buffer[65536]; + +int main(int argc, char **argv) +{ + struct input_opts io; + int fd; + int pair[2] = {-1, -1}; + + if (read(0, &io, sizeof(io)) != sizeof(io)) + return 1; + if (io.fmt > ZLOG_FMT_LAST) + return 1; + + switch (io.dst) { + case 0: + fd = 1; + break; + case 1: + socketpair(AF_UNIX, SOCK_STREAM, 0, pair); + fd = pair[0]; + break; + case 2: + socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair); + fd = pair[0]; + break; + case 3: + socketpair(AF_UNIX, SOCK_DGRAM, 0, pair); + fd = pair[0]; + break; + default: + return 1; + } + + pid_t child = -1; + + if (pair[1] != -1) { + child = fork(); + + if (child == 0) { + char buf[4096]; + + close(pair[0]); + + while (read(pair[1], buf, sizeof(buf)) > 0) + ; + exit(0); + } else if (child == -1) { + perror("fork"); + return 1; + } + close(pair[1]); + } + + for (size_t i = 0; i < sizeof(buffer); i++) + buffer[i] = (i | 0x20) & 0x7f; + + zlog_aux_init("FUZZBALL: ", LOG_DEBUG); + zlog_tls_buffer_init(); + + struct zlog_cfg_5424 cfg[1] = {}; + + zlog_5424_init(cfg); + + cfg->facility = LOG_DAEMON; + cfg->prio_min = LOG_DEBUG; + cfg->kw_version = true; + cfg->kw_location = true; + cfg->kw_uid = true; + cfg->kw_ec = true; + cfg->kw_args = true; + + cfg->ts_flags = 9; + cfg->fmt = io.fmt; + cfg->dst = ZLOG_5424_DST_FD; + cfg->fd = fd; + + cmd_hostname_set("TEST"); + cfg->master = thread_master_create("TEST"); + + zlog_5424_apply_dst(cfg); + + zlog_debug("test #1 %.*s", (int)io.out1_debug, buffer); + zlog_debug("test #2 %.*s", (int)io.out2_debug, buffer); + zlog_warn("test #1 %.*s", (int)io.out3_warn, buffer); + + zlog_tls_buffer_flush(); + zlog_tls_buffer_fini(); + + /* AFL++ seems to do some weird stuff with its fuzzing target, make + * sure the fork() child is zapped here rather than creating hordes + * of it. + */ + close(fd); + if (child != -1) + kill(child, SIGTERM); + + return 0; +} diff --git a/tests/lib/fuzz_zlog_inputs.py b/tests/lib/fuzz_zlog_inputs.py new file mode 100644 index 000000000..74f3286c5 --- /dev/null +++ b/tests/lib/fuzz_zlog_inputs.py @@ -0,0 +1,41 @@ +# zlog fuzz-tester input generator +# +# Copyright (C) 2021 David Lamparter for NetDEF, Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; see the file COPYING; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from itertools import chain +import struct + +lengths = set([128]) +# lengths = [[i, i + 1, i + 3, i - 1, i - 3] for i in lengths] +# lengths = set([i for i in chain(*lengths) if i >= 0]) + +dsts = [0, 1, 2, 3] +fmts = [0, 1, 2, 3] + + +def combo(): + for l0 in lengths: + for l1 in lengths: + for l2 in lengths: + for fmt in fmts: + for dst in dsts: + yield (l0, l1, l2, fmt, dst) + + +for i, tup in enumerate(combo()): + with open("input/i%d" % i, "wb") as fd: + fd.write(struct.pack("HHHBB", *tup)) diff --git a/tests/lib/subdir.am b/tests/lib/subdir.am index 00fe93278..62b194439 100644 --- a/tests/lib/subdir.am +++ b/tests/lib/subdir.am @@ -65,6 +65,14 @@ tests_lib_cxxcompat_SOURCES = tests/lib/cxxcompat.c tests_lib_cxxcompat_LDADD = $(ALL_TESTS_LDADD) +check_PROGRAMS += tests/lib/fuzz_zlog +tests_lib_fuzz_zlog_CFLAGS = $(TESTS_CFLAGS) +tests_lib_fuzz_zlog_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_fuzz_zlog_LDADD = $(ALL_TESTS_LDADD) +tests_lib_fuzz_zlog_SOURCES = tests/lib/fuzz_zlog.c +EXTRA_DIST += tests/lib/fuzz_zlog_inputs.py + + check_PROGRAMS += tests/lib/cli/test_cli tests_lib_cli_test_cli_CFLAGS = $(TESTS_CFLAGS) tests_lib_cli_test_cli_CPPFLAGS = $(TESTS_CPPFLAGS) @@ -140,7 +148,7 @@ check_PROGRAMS += tests/lib/test_checksum tests_lib_test_checksum_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_checksum_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_checksum_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_checksum_SOURCES = tests/lib/test_checksum.c +tests_lib_test_checksum_SOURCES = tests/lib/test_checksum.c tests/helpers/c/prng.c check_PROGRAMS += tests/lib/test_graph diff --git a/tests/lib/test_checksum.c b/tests/lib/test_checksum.c index 301078867..9a7f2b147 100644 --- a/tests/lib/test_checksum.c +++ b/tests/lib/test_checksum.c @@ -24,6 +24,7 @@ #include "checksum.h" #include "network.h" +#include "prng.h" struct thread_master *master; @@ -468,45 +469,88 @@ int main(int argc, char **argv) uint8_t buffer[BUFSIZE]; int exercise = 0; #define EXERCISESTEP 257 - srandom(time(NULL)); + struct prng *prng = prng_new(0); while (1) { uint16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc; - int i, j; + int i; exercise += EXERCISESTEP; exercise %= MAXDATALEN; - for (i = 0; i < exercise; i += sizeof(long int)) { - long int rand = frr_weak_random(); + printf("\rexercising length %d\033[K", exercise); - for (j = sizeof(long int); j > 0; j--) - buffer[i + (sizeof(long int) - j)] = - (rand >> (j * 8)) & 0xff; - } + for (i = 0; i < exercise; i++) + buffer[i] = prng_rand(prng); in_csum = in_cksum(buffer, exercise); in_csum_res = in_cksum_optimized(buffer, exercise); in_csum_rfc = in_cksum_rfc(buffer, exercise); if (in_csum_res != in_csum || in_csum != in_csum_rfc) - printf("verify: in_chksum failed in_csum:%x, in_csum_res:%x,in_csum_rfc %x, len:%d\n", + printf("\nverify: in_chksum failed in_csum:%x, in_csum_res:%x,in_csum_rfc %x, len:%d\n", in_csum, in_csum_res, in_csum_rfc, exercise); + struct iovec iov[3]; + uint16_t in_csum_iov; + + iov[0].iov_base = buffer; + iov[0].iov_len = exercise / 2; + iov[1].iov_base = buffer + iov[0].iov_len; + iov[1].iov_len = exercise - iov[0].iov_len; + + in_csum_iov = in_cksumv(iov, 2); + if (in_csum_iov != in_csum) + printf("\nverify: in_cksumv failed, lens: %zu+%zu\n", + iov[0].iov_len, iov[1].iov_len); + + if (exercise >= 6) { + /* force split with byte leftover */ + iov[0].iov_base = buffer; + iov[0].iov_len = (exercise / 2) | 1; + iov[1].iov_base = buffer + iov[0].iov_len; + iov[1].iov_len = 2; + iov[2].iov_base = buffer + iov[0].iov_len + 2; + iov[2].iov_len = exercise - iov[0].iov_len - 2; + + in_csum_iov = in_cksumv(iov, 3); + if (in_csum_iov != in_csum) + printf("\nverify: in_cksumv failed, lens: %zu+%zu+%zu, got %04x, expected %04x\n", + iov[0].iov_len, iov[1].iov_len, + iov[2].iov_len, in_csum_iov, in_csum); + + /* force split without byte leftover */ + iov[0].iov_base = buffer; + iov[0].iov_len = (exercise / 2) & ~1UL; + iov[1].iov_base = buffer + iov[0].iov_len; + iov[1].iov_len = 2; + iov[2].iov_base = buffer + iov[0].iov_len + 2; + iov[2].iov_len = exercise - iov[0].iov_len - 2; + + in_csum_iov = in_cksumv(iov, 3); + if (in_csum_iov != in_csum) + printf("\nverify: in_cksumv failed, lens: %zu+%zu+%zu, got %04x, expected %04x\n", + iov[0].iov_len, iov[1].iov_len, + iov[2].iov_len, in_csum_iov, in_csum); + } + + if (exercise >= FLETCHER_CHECKSUM_VALIDATE) + continue; + ospfd = ospfd_checksum(buffer, exercise + sizeof(uint16_t), exercise); if (verify(buffer, exercise + sizeof(uint16_t))) - printf("verify: ospfd failed\n"); + printf("\nverify: ospfd failed\n"); isisd = iso_csum_create(buffer, exercise + sizeof(uint16_t), exercise); if (verify(buffer, exercise + sizeof(uint16_t))) - printf("verify: isisd failed\n"); + printf("\nverify: isisd failed\n"); lib = fletcher_checksum(buffer, exercise + sizeof(uint16_t), exercise); if (verify(buffer, exercise + sizeof(uint16_t))) - printf("verify: lib failed\n"); + printf("\nverify: lib failed\n"); if (ospfd != lib) { - printf("Mismatch in values at size %d\n" + printf("\nMismatch in values at size %d\n" "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n" "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n" "lib: 0x%04x\n", diff --git a/tests/lib/test_grpc.cpp b/tests/lib/test_grpc.cpp index 0aa1bbb7e..88372f45a 100644 --- a/tests/lib/test_grpc.cpp +++ b/tests/lib/test_grpc.cpp @@ -79,7 +79,7 @@ static const struct frr_yang_module_info *const staticd_yang_modules[] = { &frr_staticd_info, &frr_vrf_info, }; -static int grpc_thread_stop(struct thread *thread); +static void grpc_thread_stop(struct thread *thread); static void _err_print(const void *cookie, const char *errstr) { @@ -499,7 +499,7 @@ void *grpc_client_test_start(void *arg) return NULL; } -static int grpc_thread_start(struct thread *thread) +static void grpc_thread_start(struct thread *thread) { struct frr_pthread_attr client = { .start = grpc_client_test_start, @@ -509,11 +509,9 @@ static int grpc_thread_start(struct thread *thread) auto pth = frr_pthread_new(&client, "GRPC Client thread", "grpc"); frr_pthread_run(pth, NULL); frr_pthread_wait_running(pth); - - return 0; } -static int grpc_thread_stop(struct thread *thread) +static void grpc_thread_stop(struct thread *thread) { std::cout << __func__ << ": frr_pthread_stop_all" << std::endl; frr_pthread_stop_all(); diff --git a/tests/lib/test_heavy_thread.c b/tests/lib/test_heavy_thread.c index d516ed0de..466f9a7d9 100644 --- a/tests/lib/test_heavy_thread.c +++ b/tests/lib/test_heavy_thread.c @@ -70,7 +70,7 @@ static void slow_func(struct vty *vty, const char *str, const int i) printf("%s did %d, x = %g\n", str, i, x); } -static int clear_something(struct thread *thread) +static void clear_something(struct thread *thread) { struct work_state *ws = THREAD_ARG(thread); @@ -84,14 +84,13 @@ static int clear_something(struct thread *thread) if (thread_should_yield(thread)) { thread_add_timer_msec(master, clear_something, ws, 0, NULL); - return 0; + return; } } /* All done! */ XFREE(MTYPE_TMP, ws->str); XFREE(MTYPE_TMP, ws); - return 0; } DEFUN (clear_foo, diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 8f9d637af..59d08ae82 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -207,6 +207,24 @@ int main(int argc, char **argv) assert(strcmp(p, "test#5") == 0); XFREE(MTYPE_TMP, p); + struct prefix pfx; + + str2prefix("192.168.1.23/24", &pfx); + printchk("192.168.1.23/24", "%pFX", &pfx); + printchk("192.168.1.23", "%pFXh", &pfx); + + str2prefix("2001:db8::1234/64", &pfx); + printchk("2001:db8::1234/64", "%pFX", &pfx); + printchk("2001:db8::1234", "%pFXh", &pfx); + + pfx.family = AF_UNIX; + printchk("UNK prefix", "%pFX", &pfx); + printchk("{prefix.af=AF_UNIX}", "%pFXh", &pfx); + + str2prefix_eth("02:ca:fe:f0:0d:1e/48", (struct prefix_eth *)&pfx); + printchk("02:ca:fe:f0:0d:1e/48", "%pFX", &pfx); + printchk("02:ca:fe:f0:0d:1e", "%pFXh", &pfx); + struct prefix_sg sg; sg.src.s_addr = INADDR_ANY; sg.grp.s_addr = INADDR_ANY; diff --git a/tests/lib/test_segv.c b/tests/lib/test_segv.c index 494a162a4..92c9f7a2e 100644 --- a/tests/lib/test_segv.c +++ b/tests/lib/test_segv.c @@ -62,10 +62,9 @@ void func3(void) func2(6, buf); } -static int threadfunc(struct thread *thread) +static void threadfunc(struct thread *thread) { func3(); - return 0; } int main(void) diff --git a/tests/lib/test_timer_correctness.c b/tests/lib/test_timer_correctness.c index 1756d87a6..4172ca300 100644 --- a/tests/lib/test_timer_correctness.c +++ b/tests/lib/test_timer_correctness.c @@ -76,7 +76,7 @@ static void terminate_test(void) exit(exit_code); } -static int timer_func(struct thread *thread) +static void timer_func(struct thread *thread) { int rv; @@ -90,8 +90,6 @@ static int timer_func(struct thread *thread) timers_pending--; if (!timers_pending) terminate_test(); - - return 0; } static int cmp_timeval(const void *a, const void *b) diff --git a/tests/lib/test_timer_performance.c b/tests/lib/test_timer_performance.c index f9d634b6a..c1dd07b89 100644 --- a/tests/lib/test_timer_performance.c +++ b/tests/lib/test_timer_performance.c @@ -35,9 +35,8 @@ struct thread_master *master; -static int dummy_func(struct thread *thread) +static void dummy_func(struct thread *thread) { - return 0; } int main(int argc, char **argv) diff --git a/tests/lib/test_typelist.c b/tests/lib/test_typelist.c index 607e29e56..6e6965849 100644 --- a/tests/lib/test_typelist.c +++ b/tests/lib/test_typelist.c @@ -58,9 +58,10 @@ #define T_HASH (1 << 2) #define T_HEAP (1 << 3) #define T_ATOMIC (1 << 4) +#define T_REVERSE (1 << 5) #define _T_LIST (0) -#define _T_DLIST (0) +#define _T_DLIST (0 | T_REVERSE) #define _T_ATOMLIST (0 | T_ATOMIC) #define _T_HEAP (T_SORTED | T_HEAP) #define _T_SORTLIST_UNIQ (T_SORTED | T_UNIQ) @@ -68,8 +69,8 @@ #define _T_HASH (T_SORTED | T_UNIQ | T_HASH) #define _T_SKIPLIST_UNIQ (T_SORTED | T_UNIQ) #define _T_SKIPLIST_NONUNIQ (T_SORTED) -#define _T_RBTREE_UNIQ (T_SORTED | T_UNIQ) -#define _T_RBTREE_NONUNIQ (T_SORTED) +#define _T_RBTREE_UNIQ (T_SORTED | T_UNIQ | T_REVERSE) +#define _T_RBTREE_NONUNIQ (T_SORTED | T_REVERSE) #define _T_ATOMSORT_UNIQ (T_SORTED | T_UNIQ | T_ATOMIC) #define _T_ATOMSORT_NONUNIQ (T_SORTED | T_ATOMIC) @@ -79,6 +80,7 @@ #define IS_HASH(type) (_T_TYPE(type) & T_HASH) #define IS_HEAP(type) (_T_TYPE(type) & T_HEAP) #define IS_ATOMIC(type) (_T_TYPE(type) & T_ATOMIC) +#define IS_REVERSE(type) (_T_TYPE(type) & T_REVERSE) static struct timeval ref, ref0; diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h index 8261616ed..e3579c67a 100644 --- a/tests/lib/test_typelist.h +++ b/tests/lib/test_typelist.h @@ -31,6 +31,11 @@ #define list_const_next concat(TYPE, _const_next) #define list_next concat(TYPE, _next) #define list_next_safe concat(TYPE, _next_safe) +#define list_const_last concat(TYPE, _const_last) +#define list_last concat(TYPE, _last) +#define list_const_prev concat(TYPE, _const_prev) +#define list_prev concat(TYPE, _prev) +#define list_prev_safe concat(TYPE, _prev_safe) #define list_count concat(TYPE, _count) #define list_add concat(TYPE, _add) #define list_add_head concat(TYPE, _add_head) @@ -171,6 +176,9 @@ static void concat(test_, TYPE)(void) list_init(&head); assert(list_first(&head) == NULL); +#if IS_REVERSE(REALTYPE) + assert(list_last(&head) == NULL); +#endif ts_hash("init", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"); @@ -203,6 +211,10 @@ static void concat(test_, TYPE)(void) assert(!list_first(&head)); assert(list_count(&other) == k); assert(list_first(&other) != NULL); +#if IS_REVERSE(REALTYPE) + assert(!list_last(&head)); + assert(list_last(&other) != NULL); +#endif ts_hash_headx( &other, "swap1", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); @@ -269,13 +281,36 @@ static void concat(test_, TYPE)(void) (void)cprev; #else assert(!cprev || cprev->val < citem->val); +#if IS_REVERSE(REALTYPE) + assert(list_const_prev(chead, citem) == cprev); +#endif #endif cprev = citem; k++; } assert(list_count(chead) == k); +#if IS_REVERSE(REALTYPE) + assert(cprev == list_const_last(chead)); +#endif ts_ref("walk"); +#if IS_REVERSE(REALTYPE) && !IS_HASH(REALTYPE) && !IS_HEAP(REALTYPE) + cprev = NULL; + k = 0; + + frr_rev_each(list_const, chead, citem) { + assert(!cprev || cprev->val > citem->val); + assert(list_const_next(chead, citem) == cprev); + + cprev = citem; + k++; + } + assert(list_count(chead) == k); + assert(cprev == list_const_first(chead)); + + ts_ref("reverse-walk"); +#endif + #if IS_UNIQ(REALTYPE) prng_free(prng); prng = prng_new(0); @@ -439,6 +474,9 @@ static void concat(test_, TYPE)(void) } assert(list_count(&head) == k); assert(list_first(&head) != NULL); +#if IS_REVERSE(REALTYPE) + assert(list_last(&head) != NULL); +#endif ts_hash("fill / add_tail", "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19"); #if !IS_ATOMIC(REALTYPE) @@ -451,6 +489,10 @@ static void concat(test_, TYPE)(void) assert(!list_first(&head)); assert(list_count(&other) == k); assert(list_first(&other) != NULL); +#if IS_REVERSE(REALTYPE) + assert(!list_last(&head)); + assert(list_last(&other) != NULL); +#endif ts_hash_head( &other, "swap1", "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19"); @@ -534,6 +576,21 @@ static void concat(test_, TYPE)(void) } ts_hash("member", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d"); #endif +#if IS_REVERSE(REALTYPE) + i = 0; + prev = NULL; + + frr_rev_each (list, &head, item) { + assert(item->scratchpad != 0); + assert(list_next(&head, item) == prev); + + i++; + prev = item; + } + assert(list_first(&head) == prev); + assert(list_count(&head) == i); + ts_hash("reverse-walk", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d"); +#endif while ((item = list_pop(&head))) { assert(item->scratchpad != 0); @@ -746,6 +803,13 @@ static void concat(test_, TYPE)(void) #undef list_first #undef list_next #undef list_next_safe +#undef list_const_first +#undef list_const_next +#undef list_last +#undef list_prev +#undef list_prev_safe +#undef list_const_last +#undef list_const_prev #undef list_count #undef list_add #undef list_add_head diff --git a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py index 138512bc6..8a7192be2 100644 --- a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py +++ b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py @@ -18,7 +18,7 @@ # OF THIS SOFTWARE. # -""" +r""" Reference: https://www.cmand.org/communityexploration --y2-- diff --git a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf index 82525fac6..73f837c69 100644 --- a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf +++ b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf @@ -19,6 +19,7 @@ route-map ADV-MAP-1 permit 20 ! route-map ADV-MAP-2 permit 10 match ip address prefix-list IP2 + set metric 911 ! route-map EXIST-MAP permit 10 match community DEFAULT-ROUTE diff --git a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py index e9b393ba7..6153aee41 100644 --- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -334,7 +334,7 @@ def test_bgp_conditional_advertisement(): "192.0.2.1/32": None, "192.0.2.5/32": None, "10.139.224.0/20": None, - "203.0.113.1/32": [{"protocol": "bgp"}], + "203.0.113.1/32": [{"protocol": "bgp", "metric": 911}], } return topotest.json_cmp(output, expected) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/customize.py index 7d7a4bd15..36bfdfe06 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/customize.py @@ -21,7 +21,7 @@ # OF THIS SOFTWARE. # -""" +r""" customize.py: Simple FRR MPLS L3VPN test topology | diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index fce8e708f..5161d8471 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -21,7 +21,7 @@ # OF THIS SOFTWARE. # -""" +r""" customize.py: Simple FRR MPLS L3VPN test topology | diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 9c13c1c07..9f4399d6d 100644 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -22,7 +22,7 @@ # OF THIS SOFTWARE. # -""" +r""" test_bgp_multiview_topo1.py: Simple FRR Route-Server Test +----------+ +----------+ +----------+ +----------+ +----------+ diff --git a/tests/topotests/bgp_rfapi_basic_sanity/customize.py b/tests/topotests/bgp_rfapi_basic_sanity/customize.py index 1a86746e3..c82fe8321 100644 --- a/tests/topotests/bgp_rfapi_basic_sanity/customize.py +++ b/tests/topotests/bgp_rfapi_basic_sanity/customize.py @@ -22,7 +22,7 @@ # OF THIS SOFTWARE. # -""" +r""" customize.py: Simple FRR MPLS L3VPN test topology +---------+ diff --git a/tests/topotests/bgp_route_map/test_route_map_topo1.py b/tests/topotests/bgp_route_map/test_route_map_topo1.py index 3c2d7f28a..6556c050b 100644 --- a/tests/topotests/bgp_route_map/test_route_map_topo1.py +++ b/tests/topotests/bgp_route_map/test_route_map_topo1.py @@ -444,9 +444,10 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request): result = verify_rib( tgen, adt, dut, input_dict_2, protocol=protocol, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n" - "routes are not present in rib \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \nroutes are not present in rib \n Error: {}".format( + tc_name, result ) logger.info("Expected behaviour: {}".format(result)) @@ -466,9 +467,10 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request): result = verify_rib( tgen, adt, dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "routes are not present in rib \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \nroutes are not present in rib \n Error: {}".format( + tc_name, result ) logger.info("Expected behaviour: {}".format(result)) @@ -664,9 +666,10 @@ def test_route_map_with_action_values_combination_of_prefix_action_p0( result = verify_rib( tgen, adt, dut, input_dict_2, protocol=protocol, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \nRoutes are still present \n Error: {}".format( + tc_name, result ) logger.info("Expected behaviour: {}".format(result)) else: diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/bgpd.conf new file mode 100644 index 000000000..345979662 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce1 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/ip_rib.json new file mode 100644 index 000000000..1d33fee71 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/ip_rib.json @@ -0,0 +1,58 @@ +{ + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "192.168.1.1", + "afi": "ipv4", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "192.168.1.0/24": [ + { + "prefix": "192.168.1.0/24", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/zebra.conf new file mode 100644 index 000000000..447d1b40c --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce1 +! +interface eth0 + ip address 192.168.1.2/24 +! +ip forwarding +ipv6 forwarding +! +ip route 0.0.0.0/0 192.168.1.1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/bgpd.conf new file mode 100644 index 000000000..8ed997874 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce2 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/ip_rib.json new file mode 100644 index 000000000..a21f4a11b --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/ip_rib.json @@ -0,0 +1,58 @@ +{ + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "192.168.2.1", + "afi": "ipv4", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "192.168.2.0/24": [ + { + "prefix": "192.168.2.0/24", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/zebra.conf new file mode 100644 index 000000000..11652252a --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce2 +! +interface eth0 + ip address 192.168.2.2/24 +! +ip forwarding +ipv6 forwarding +! +ip route 0.0.0.0/0 192.168.2.1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/bgpd.conf new file mode 100644 index 000000000..a85d9701c --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce3 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/ip_rib.json new file mode 100644 index 000000000..38a7807df --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/ip_rib.json @@ -0,0 +1,58 @@ +{ + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "192.168.3.1", + "afi": "ipv4", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "192.168.3.0/24": [ + { + "prefix": "192.168.3.0/24", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/zebra.conf new file mode 100644 index 000000000..299c6597c --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce3 +! +interface eth0 + ip address 192.168.3.2/24 +! +ip forwarding +ipv6 forwarding +! +ip route 0.0.0.0/0 192.168.3.1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/bgpd.conf new file mode 100644 index 000000000..93fb32fd1 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce4 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/ip_rib.json new file mode 100644 index 000000000..a0be78e98 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/ip_rib.json @@ -0,0 +1,58 @@ +{ + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "192.168.4.1", + "afi": "ipv4", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "192.168.4.0/24": [ + { + "prefix": "192.168.4.0/24", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/zebra.conf new file mode 100644 index 000000000..30f3736fe --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce4 +! +interface eth0 + ip address 192.168.4.2/24 +! +ip forwarding +ipv6 forwarding +! +ip route 0.0.0.0/0 192.168.4.1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/bgpd.conf new file mode 100644 index 000000000..2ab6f2d2a --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce5 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/ip_rib.json new file mode 100644 index 000000000..dc338d5de --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/ip_rib.json @@ -0,0 +1,58 @@ +{ + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "192.168.5.1", + "afi": "ipv4", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "192.168.5.0/24": [ + { + "prefix": "192.168.5.0/24", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/zebra.conf new file mode 100644 index 000000000..208dcb1a7 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce5 +! +interface eth0 + ip address 192.168.5.2/24 +! +ip forwarding +ipv6 forwarding +! +ip route 0.0.0.0/0 192.168.5.1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/bgpd.conf new file mode 100644 index 000000000..e0b654051 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/bgpd.conf @@ -0,0 +1,8 @@ +frr defaults traditional +! +hostname ce6 +password zebra +! +log stdout notifications +log commands +log file bgpd.log diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/ip_rib.json new file mode 100644 index 000000000..4a603a55c --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/ip_rib.json @@ -0,0 +1,58 @@ +{ + "0.0.0.0/0": [ + { + "prefix": "0.0.0.0/0", + "protocol": "static", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 1, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 73, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "ip": "192.168.6.1", + "afi": "ipv4", + "interfaceName": "eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "192.168.6.0/24": [ + { + "prefix": "192.168.6.0/24", + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth0", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/zebra.conf new file mode 100644 index 000000000..d68a008e3 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/zebra.conf @@ -0,0 +1,14 @@ +log file zebra.log +! +hostname ce6 +! +interface eth0 + ip address 192.168.6.2/24 +! +ip forwarding +ipv6 forwarding +! +ip route 0.0.0.0/0 192.168.6.1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf new file mode 100644 index 000000000..c06175193 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf @@ -0,0 +1,66 @@ +frr defaults traditional +! +hostname r1 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +!debug bgp neighbor-events +!debug bgp zebra +!debug bgp vnc verbose +!debug bgp update-groups +!debug bgp updates in +!debug bgp updates out +!debug bgp vpn label +!debug bgp vpn leak-from-vrf +!debug bgp vpn leak-to-vrf +!debug bgp vpn rmap-event +! +router bgp 1 + bgp router-id 1.1.1.1 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001::2 remote-as 2 + neighbor 2001::2 timers 3 10 + neighbor 2001::2 timers connect 1 + neighbor 2001::2 capability extended-nexthop + ! + address-family ipv4 vpn + neighbor 2001::2 activate + exit-address-family + ! + segment-routing srv6 + locator loc1 + ! +! +router bgp 1 vrf vrf10 + bgp router-id 1.1.1.1 + no bgp ebgp-requires-policy + ! + address-family ipv4 unicast + sid vpn export auto + nexthop vpn export 2001::1 + rd vpn export 1:10 + rt vpn both 99:99 + import vpn + export vpn + redistribute connected + ! + exit-address-family +! +router bgp 1 vrf vrf20 + bgp router-id 1.1.1.1 + no bgp ebgp-requires-policy + ! + address-family ipv4 unicast + sid vpn export auto + nexthop vpn export 2001::1 + rd vpn export 1:20 + rt vpn both 88:88 + import vpn + export vpn + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json new file mode 100644 index 000000000..3cc2fddcf --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json @@ -0,0 +1,167 @@ +{ + "vrfId": 0, + "vrfName": "default", + "tableVersion": 2, + "routerId": "1.1.1.1", + "defaultLocPrf": 100, + "localAS": 1, + "routes": { + "routeDistinguishers": { + "1:10": { + "192.168.1.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.1.0", + "prefixLen": 24, + "network": "192.168.1.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nhVrfName": "vrf10", + "nexthops": [ + { + "ip": "2001::1", + "hostname": "r1", + "afi": "ipv6", + "used": true + } + ] + } + ], + "192.168.3.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.3.0", + "prefixLen": 24, + "network": "192.168.3.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nhVrfName": "vrf10", + "nexthops": [ + { + "ip": "2001::1", + "hostname": "r1", + "afi": "ipv6", + "used": true + } + ] + } + ] + }, + "1:20": { + "192.168.5.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.5.0", + "prefixLen": 24, + "network": "192.168.5.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nhVrfName": "vrf20", + "nexthops": [ + { + "ip": "2001::1", + "hostname": "r1", + "afi": "ipv6", + "used": true + } + ] + } + ] + }, + "2:10": { + "192.168.2.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.2.0", + "prefixLen": 24, + "network": "192.168.2.0/24", + "metric": 0, + "weight": 0, + "peerId": "2001::2", + "path": "2", + "origin": "incomplete", + "nexthops": [ + { + "ip": "2001::2", + "hostname": "r2", + "afi": "ipv6", + "used": true + } + ] + } + ] + }, + "2:20": { + "192.168.4.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.4.0", + "prefixLen": 24, + "network": "192.168.4.0/24", + "metric": 0, + "weight": 0, + "peerId": "2001::2", + "path": "2", + "origin": "incomplete", + "nexthops": [ + { + "ip": "2001::2", + "hostname": "r2", + "afi": "ipv6", + "used": true + } + ] + } + ], + "192.168.6.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.6.0", + "prefixLen": 24, + "network": "192.168.6.0/24", + "metric": 0, + "weight": 0, + "peerId": "2001::2", + "path": "2", + "origin": "incomplete", + "nexthops": [ + { + "ip": "2001::2", + "hostname": "r2", + "afi": "ipv6", + "used": true + } + ] + } + ] + } + } + } +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf10_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf10_rib.json new file mode 100644 index 000000000..8daa9b155 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf10_rib.json @@ -0,0 +1,86 @@ +{ + "192.168.1.0/24": [ + { + "prefix": "192.168.1.0/24", + "protocol": "connected", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth1", + "active": true + } + ] + } + ], + "192.168.2.0/24": [ + { + "prefix": "192.168.2.0/24", + "protocol": "bgp", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "weight": 1, + "seg6": { + "segs": "2001:db8:2:2:100::" + } + } + ], + "asPath": "2" + } + ], + "192.168.3.0/24": [ + { + "prefix": "192.168.3.0/24", + "protocol": "connected", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth2", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf20_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf20_rib.json new file mode 100644 index 000000000..6f123cf4f --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf20_rib.json @@ -0,0 +1,92 @@ +{ + "192.168.4.0/24": [ + { + "prefix": "192.168.4.0/24", + "protocol": "bgp", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "weight": 1, + "seg6": { + "segs": "2001:db8:2:2:200::" + } + } + ], + "asPath": "2" + } + ], + "192.168.5.0/24": [ + { + "prefix": "192.168.5.0/24", + "protocol": "connected", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth3", + "active": true + } + ] + } + ], + "192.168.6.0/24": [ + { + "prefix": "192.168.6.0/24", + "protocol": "bgp", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "weight": 1, + "seg6": { + "segs": "2001:db8:2:2:200::" + } + } + ], + "asPath": "2" + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf new file mode 100644 index 000000000..a43cec20e --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf @@ -0,0 +1,41 @@ +log file zebra.log +! +hostname r1 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +debug zebra packet +debug zebra dplane +debug zebra kernel +! +interface eth0 + ipv6 address 2001::1/64 +! +interface eth1 vrf vrf10 + ip address 192.168.1.1/24 + ipv6 address 2001:1::1/64 +! +interface eth2 vrf vrf10 + ip address 192.168.3.1/24 +! +interface eth3 vrf vrf20 + ip address 192.168.5.1/24 +! +segment-routing + srv6 + locators + locator loc1 + prefix 2001:db8:1:1::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +ipv6 route 2001:db8:2:2::/64 2001::2 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf new file mode 100644 index 000000000..05170572a --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf @@ -0,0 +1,66 @@ +frr defaults traditional +! +hostname r2 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +!debug bgp neighbor-events +!debug bgp zebra +!debug bgp vnc verbose +!debug bgp update-groups +!debug bgp updates in +!debug bgp updates out +!debug bgp updates +!debug bgp vpn label +!debug bgp vpn leak-from-vrf +!debug bgp vpn leak-to-vrf +!debug bgp vpn rmap-event +! +router bgp 2 + bgp router-id 2.2.2.2 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001::1 remote-as 1 + neighbor 2001::1 timers 3 10 + neighbor 2001::1 timers connect 1 + neighbor 2001::1 capability extended-nexthop + ! + address-family ipv4 vpn + neighbor 2001::1 activate + exit-address-family + ! + segment-routing srv6 + locator loc1 + ! +! +router bgp 2 vrf vrf10 + bgp router-id 2.2.2.2 + no bgp ebgp-requires-policy + ! + address-family ipv4 unicast + sid vpn export auto + nexthop vpn export 2001::2 + rd vpn export 2:10 + rt vpn both 99:99 + import vpn + export vpn + redistribute connected + exit-address-family +! +router bgp 2 vrf vrf20 + bgp router-id 2.2.2.2 + no bgp ebgp-requires-policy + ! + address-family ipv4 unicast + sid vpn export auto + nexthop vpn export 2001::2 + rd vpn export 2:20 + rt vpn both 88:88 + import vpn + export vpn + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json new file mode 100644 index 000000000..95570541c --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json @@ -0,0 +1,167 @@ +{ + "vrfId": 0, + "vrfName": "default", + "tableVersion": 2, + "routerId": "2.2.2.2", + "defaultLocPrf": 100, + "localAS": 2, + "routes": { + "routeDistinguishers": { + "1:10": { + "192.168.1.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.1.0", + "prefixLen": 24, + "network": "192.168.1.0/24", + "metric": 0, + "weight": 0, + "peerId": "2001::1", + "path": "1", + "origin": "incomplete", + "nexthops": [ + { + "ip": "2001::1", + "hostname": "r1", + "afi": "ipv6", + "used": true + } + ] + } + ], + "192.168.3.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.3.0", + "prefixLen": 24, + "network": "192.168.3.0/24", + "metric": 0, + "weight": 0, + "peerId": "2001::1", + "path": "1", + "origin": "incomplete", + "nexthops": [ + { + "ip": "2001::1", + "hostname": "r1", + "afi": "ipv6", + "used": true + } + ] + } + ] + }, + "1:20": { + "192.168.5.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.5.0", + "prefixLen": 24, + "network": "192.168.5.0/24", + "metric": 0, + "weight": 0, + "peerId": "2001::1", + "path": "1", + "origin": "incomplete", + "nexthops": [ + { + "ip": "2001::1", + "hostname": "r1", + "afi": "ipv6", + "used": true + } + ] + } + ] + }, + "2:10": { + "192.168.2.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.2.0", + "prefixLen": 24, + "network": "192.168.2.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nhVrfName": "vrf10", + "nexthops": [ + { + "ip": "2001::2", + "hostname": "r2", + "afi": "ipv6", + "used": true + } + ] + } + ] + }, + "2:20": { + "192.168.4.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.4.0", + "prefixLen": 24, + "network": "192.168.4.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nhVrfName": "vrf20", + "nexthops": [ + { + "ip": "2001::2", + "hostname": "r2", + "afi": "ipv6", + "used": true + } + ] + } + ], + "192.168.6.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "192.168.6.0", + "prefixLen": 24, + "network": "192.168.6.0/24", + "metric": 0, + "weight": 32768, + "peerId": "(unspec)", + "path": "", + "origin": "incomplete", + "nhVrfName": "vrf20", + "nexthops": [ + { + "ip": "2001::2", + "hostname": "r2", + "afi": "ipv6", + "used": true + } + ] + } + ] + } + } + } +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf10_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf10_rib.json new file mode 100644 index 000000000..626803187 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf10_rib.json @@ -0,0 +1,92 @@ +{ + "192.168.1.0/24": [ + { + "prefix": "192.168.1.0/24", + "protocol": "bgp", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "weight": 1, + "seg6": { + "segs": "2001:db8:1:1:100::" + } + } + ], + "asPath": "1" + } + ], + "192.168.2.0/24": [ + { + "prefix": "192.168.2.0/24", + "protocol": "connected", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth1", + "active": true + } + ] + } + ], + "192.168.3.0/24": [ + { + "prefix": "192.168.3.0/24", + "protocol": "bgp", + "vrfName": "vrf10", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 10, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "weight": 1, + "seg6": { + "segs": "2001:db8:1:1:100::" + } + } + ], + "asPath": "1" + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf20_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf20_rib.json new file mode 100644 index 000000000..ffe2e07c8 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf20_rib.json @@ -0,0 +1,86 @@ +{ + "192.168.4.0/24": [ + { + "prefix": "192.168.4.0/24", + "protocol": "connected", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth2", + "active": true + } + ] + } + ], + "192.168.5.0/24": [ + { + "prefix": "192.168.5.0/24", + "protocol": "bgp", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "afi": "ipv6", + "interfaceName": "eth0", + "vrf": "default", + "active": true, + "weight": 1, + "seg6": { + "segs": "2001:db8:1:1:200::" + } + } + ], + "asPath": "1" + } + ], + "192.168.6.0/24": [ + { + "prefix": "192.168.6.0/24", + "protocol": "connected", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 20, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "flags": 3, + "fib": true, + "directlyConnected": true, + "interfaceName": "eth3", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf new file mode 100644 index 000000000..71ddedf6f --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf @@ -0,0 +1,40 @@ +log file zebra.log +! +hostname r2 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +debug zebra packet +debug zebra dplane +debug zebra kernel +! +interface eth0 + ipv6 address 2001::2/64 +! +interface eth1 vrf vrf10 + ip address 192.168.2.1/24 +! +interface eth2 vrf vrf20 + ip address 192.168.4.1/24 +! +interface eth3 vrf vrf20 + ip address 192.168.6.1/24 +! +segment-routing + srv6 + locators + locator loc1 + prefix 2001:db8:2:2::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +ipv6 route 2001:db8:1:1::/64 2001::1 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py new file mode 100755 index 000000000..af66a5a79 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018, LabN Consulting, L.L.C. +# Authored by Lou Berger +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import re +import sys +import json +import functools +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.common_config import required_linux_kernel_version + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_router("ce1") + tgen.add_router("ce2") + tgen.add_router("ce3") + tgen.add_router("ce4") + tgen.add_router("ce5") + tgen.add_router("ce6") + + tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0") + tgen.add_link(tgen.gears["ce1"], tgen.gears["r1"], "eth0", "eth1") + tgen.add_link(tgen.gears["ce2"], tgen.gears["r2"], "eth0", "eth1") + tgen.add_link(tgen.gears["ce3"], tgen.gears["r1"], "eth0", "eth2") + tgen.add_link(tgen.gears["ce4"], tgen.gears["r2"], "eth0", "eth2") + tgen.add_link(tgen.gears["ce5"], tgen.gears["r1"], "eth0", "eth3") + tgen.add_link(tgen.gears["ce6"], tgen.gears["r2"], "eth0", "eth3") + + +def setup_module(mod): + result = required_linux_kernel_version("5.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + router.load_config(TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname))) + router.load_config(TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname))) + + tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1") + tgen.gears["r1"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r1"].run("ip link set vrf10 up") + tgen.gears["r1"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r1"].run("ip link set vrf20 up") + tgen.gears["r1"].run("ip link set eth1 master vrf10") + tgen.gears["r1"].run("ip link set eth2 master vrf10") + tgen.gears["r1"].run("ip link set eth3 master vrf20") + + tgen.gears["r2"].run("sysctl net.vrf.strict_mode=1") + tgen.gears["r2"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r2"].run("ip link set vrf10 up") + tgen.gears["r2"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r2"].run("ip link set vrf20 up") + tgen.gears["r2"].run("ip link set eth1 master vrf10") + tgen.gears["r2"].run("ip link set eth2 master vrf20") + tgen.gears["r2"].run("ip link set eth3 master vrf20") + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +def check_ping(name, dest_addr, expect_connected): + def _check(name, dest_addr, match): + tgen = get_topogen() + output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) + logger.info(output) + assert match in output, "ping fail" + + match = "{} packet loss".format("0%" if expect_connected else "100%") + logger.info("[+] check {} {} {}".format(name, dest_addr, match)) + tgen = get_topogen() + func = functools.partial(_check, name, dest_addr, match) + success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + assert result is None, "Failed" + + +def check_rib(name, cmd, expected_file): + def _check(name, dest_addr, match): + logger.info("polling") + tgen = get_topogen() + router = tgen.gears[name] + output = json.loads(router.vtysh_cmd(cmd)) + expected = open_json_file("{}/{}".format(CWD, expected_file)) + return topotest.json_cmp(output, expected) + + logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file)) + tgen = get_topogen() + func = functools.partial(_check, name, cmd, expected_file) + success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + assert result is None, "Failed" + + +def test_rib(): + check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib.json") + check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib.json") + check_rib("r1", "show ip route vrf vrf10 json", "r1/vrf10_rib.json") + check_rib("r1", "show ip route vrf vrf20 json", "r1/vrf20_rib.json") + check_rib("r2", "show ip route vrf vrf10 json", "r2/vrf10_rib.json") + check_rib("r2", "show ip route vrf vrf20 json", "r2/vrf20_rib.json") + check_rib("ce1", "show ip route json", "ce1/ip_rib.json") + check_rib("ce2", "show ip route json", "ce2/ip_rib.json") + check_rib("ce3", "show ip route json", "ce3/ip_rib.json") + check_rib("ce4", "show ip route json", "ce4/ip_rib.json") + check_rib("ce5", "show ip route json", "ce5/ip_rib.json") + check_rib("ce6", "show ip route json", "ce6/ip_rib.json") + + +def test_ping(): + check_ping("ce1", "192.168.2.2", " 0% packet loss") + check_ping("ce1", "192.168.3.2", " 0% packet loss") + check_ping("ce1", "192.168.4.2", " 100% packet loss") + check_ping("ce1", "192.168.5.2", " 100% packet loss") + check_ping("ce1", "192.168.6.2", " 100% packet loss") + check_ping("ce4", "192.168.1.2", " 100% packet loss") + check_ping("ce4", "192.168.2.2", " 100% packet loss") + check_ping("ce4", "192.168.3.2", " 100% packet loss") + check_ping("ce4", "192.168.5.2", " 0% packet loss") + check_ping("ce4", "192.168.6.2", " 0% packet loss") + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/cspf_topo1/r1/isisd.conf b/tests/topotests/cspf_topo1/r1/isisd.conf new file mode 100644 index 000000000..788ac5b7a --- /dev/null +++ b/tests/topotests/cspf_topo1/r1/isisd.conf @@ -0,0 +1,33 @@ +! +hostname r1 +! +interface lo + ip router isis TE + ipv6 router isis TE + isis circuit-type level-2-only + isis passive +! +interface r1-eth0 + ip router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +interface r1-eth1 + ip router isis TE + ipv6 router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +router isis TE + net 49.0000.0000.0000.0001.00 + is-type level-2-only + topology ipv6-unicast + lsp-timers gen-interval 2 refresh-interval 10 max-lifetime 350 + mpls-te on + mpls-te router-address 10.0.255.1 + mpls-te router-address ipv6 2001:db8::1 + mpls-te export +! + diff --git a/tests/topotests/cspf_topo1/r1/sharpd.conf b/tests/topotests/cspf_topo1/r1/sharpd.conf new file mode 100644 index 000000000..272eac944 --- /dev/null +++ b/tests/topotests/cspf_topo1/r1/sharpd.conf @@ -0,0 +1,3 @@ +! +import-te +! diff --git a/tests/topotests/cspf_topo1/r1/zebra.conf b/tests/topotests/cspf_topo1/r1/zebra.conf new file mode 100644 index 000000000..3aa0cad43 --- /dev/null +++ b/tests/topotests/cspf_topo1/r1/zebra.conf @@ -0,0 +1,27 @@ +! +hostname r1 +! +interface lo + ip address 10.0.255.1/32 + ipv6 address 2001:db8::1/128 +! +interface r1-eth0 + ip address 10.0.0.1/24 + link-params + metric 20 + delay 10000 + ava-bw 1.25e+08 + enable + exit-link-params +! +interface r1-eth1 + ip address 10.0.1.1/24 + ipv6 address 2001:db8:1::1:1/64 + link-params + metric 10 + delay 20000 + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/cspf_topo1/r2/isisd.conf b/tests/topotests/cspf_topo1/r2/isisd.conf new file mode 100644 index 000000000..04df685e9 --- /dev/null +++ b/tests/topotests/cspf_topo1/r2/isisd.conf @@ -0,0 +1,46 @@ +! +hostname r2 +! +! debug isis te-events +! +interface lo + ip router isis TE + ipv6 router isis TE + isis circuit-type level-2-only + isis passive +! +interface r2-eth0 + ip router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +interface r2-eth1 + ip router isis TE + ipv6 router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +interface r2-eth2 + ip router isis TE + ipv6 router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +interface r2-eth3 + ip router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +router isis TE + net 49.0000.0000.0000.0002.00 + is-type level-2-only + topology ipv6-unicast + lsp-timers gen-interval 2 refresh-interval 10 max-lifetime 350 + mpls-te on + mpls-te router-address 10.0.255.2 + mpls-te router-address ipv6 2001:db8::2 +! diff --git a/tests/topotests/cspf_topo1/r2/zebra.conf b/tests/topotests/cspf_topo1/r2/zebra.conf new file mode 100644 index 000000000..1cc37ba12 --- /dev/null +++ b/tests/topotests/cspf_topo1/r2/zebra.conf @@ -0,0 +1,45 @@ +! +hostname r2 +! +interface lo + ip address 10.0.255.2/32 + ipv6 address 2001:db8::2/128 +! +interface r2-eth0 + ip address 10.0.0.2/24 + link-params + metric 20 + delay 10000 + enable + exit-link-params +! +interface r2-eth1 + ip address 10.0.1.2/24 + ipv6 address 2001:db8:1::1:2/64 + link-params + metric 10 + delay 20000 + enable + exit-link-params +! +interface r2-eth2 + ip address 10.0.3.2/24 + ipv6 address 2001:db8:3::3:2/64 + link-params + metric 40 + delay 40000 + enable + exit-link-params +! +interface r2-eth3 + ip address 10.0.4.2/24 + ipv6 address 2001:db8:4::4:2/64 + link-params + metric 25 + delay 25000 + use-bw 1.25e+8 + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/cspf_topo1/r3/isisd.conf b/tests/topotests/cspf_topo1/r3/isisd.conf new file mode 100644 index 000000000..9db82c7b2 --- /dev/null +++ b/tests/topotests/cspf_topo1/r3/isisd.conf @@ -0,0 +1,34 @@ +! +hostname r3 +! +! debug isis te-events +! +interface lo + ip router isis TE + ipv6 router isis TE + isis circuit-type level-2-only + isis passive +! +interface r3-eth0 + ip router isis TE + ipv6 router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +interface r3-eth1 + ipv6 router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +! +router isis TE + net 49.0000.0000.0000.0003.00 + is-type level-2-only + topology ipv6-unicast + lsp-timers gen-interval 2 refresh-interval 10 max-lifetime 350 + mpls-te on + mpls-te router-address 10.0.255.3 + mpls-te router-address ipv6 2001:db8::3 +! diff --git a/tests/topotests/cspf_topo1/r3/zebra.conf b/tests/topotests/cspf_topo1/r3/zebra.conf new file mode 100644 index 000000000..29a4c515f --- /dev/null +++ b/tests/topotests/cspf_topo1/r3/zebra.conf @@ -0,0 +1,27 @@ +! +hostname r3 +! +interface lo + ip address 10.0.255.3/32 + ipv6 address 2001:db8::3/128 +! +interface r3-eth0 + ip address 10.0.3.3/24 + ipv6 address 2001:db8:3::3:3/64 + link-params + metric 25 + delay 25000 + enable + admin-grp 0x20 + exit-link-params +! +interface r3-eth1 + ipv6 address 2001:db8:5::4:3/64 + link-params + enable + metric 10 + delay 10000 + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/cspf_topo1/r4/isisd.conf b/tests/topotests/cspf_topo1/r4/isisd.conf new file mode 100644 index 000000000..c5c4d4e05 --- /dev/null +++ b/tests/topotests/cspf_topo1/r4/isisd.conf @@ -0,0 +1,40 @@ +! +hostname r4 +! +! debug isis te-events +! debug isis sr-events +! debug isis lsp-gen +! +interface lo + ip router isis TE + ipv6 router isis TE + isis circuit-type level-2-only + isis passive +! +interface r4-eth0 + ip router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +interface r4-eth1 + ipv6 router isis TE + isis circuit-type level-2-only + isis network point-to-point + isis hello-multiplier 3 +! +! +router isis TE + net 49.0000.0000.0000.0004.00 + is-type level-2-only + topology ipv6-unicast + lsp-timers gen-interval 2 refresh-interval 10 max-lifetime 350 + mpls-te on + mpls-te router-address 10.0.255.4 + mpls-te router-address ipv6 2001:db8::4 + segment-routing on + segment-routing global-block 10000 19999 local-block 5000 5999 + segment-routing node-msd 12 + segment-routing prefix 10.0.255.4/32 index 400 no-php-flag + segment-routing prefix 2001:db8:ffff::4/128 index 1400 no-php-flag +! diff --git a/tests/topotests/cspf_topo1/r4/zebra.conf b/tests/topotests/cspf_topo1/r4/zebra.conf new file mode 100644 index 000000000..bf5306d0e --- /dev/null +++ b/tests/topotests/cspf_topo1/r4/zebra.conf @@ -0,0 +1,26 @@ +! +hostname r4 +! +interface lo + ip address 10.0.255.4/32 + ipv6 address 2001:db8::4/128 +! +interface r4-eth0 + ip address 10.0.4.4/24 + ipv6 address 2001:db8:4::2:4/64 + link-params + metric 40 + delay 40000 + enable + exit-link-params +! +interface r4-eth1 + ipv6 address 2001:db8:5::3:4/64 + link-params + metric 10 + delay 10000 + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/cspf_topo1/reference/cspf-failed-dst.txt b/tests/topotests/cspf_topo1/reference/cspf-failed-dst.txt new file mode 100644 index 000000000..df792cef9 --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-failed-dst.txt @@ -0,0 +1 @@ +Path computation failed: 2 diff --git a/tests/topotests/cspf_topo1/reference/cspf-failed-same.txt b/tests/topotests/cspf_topo1/reference/cspf-failed-same.txt new file mode 100644 index 000000000..48f6fd9b6 --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-failed-same.txt @@ -0,0 +1 @@ +Path computation failed: 3 diff --git a/tests/topotests/cspf_topo1/reference/cspf-failed-src.txt b/tests/topotests/cspf_topo1/reference/cspf-failed-src.txt new file mode 100644 index 000000000..62d00ccab --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-failed-src.txt @@ -0,0 +1 @@ +Path computation failed: 1 diff --git a/tests/topotests/cspf_topo1/reference/cspf-failed.txt b/tests/topotests/cspf_topo1/reference/cspf-failed.txt new file mode 100644 index 000000000..de53a9382 --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-failed.txt @@ -0,0 +1 @@ +Path computation failed: 0 diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv4-delay.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv4-delay.txt new file mode 100644 index 000000000..2cc042842 --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-ipv4-delay.txt @@ -0,0 +1,3 @@ +Path computation success + Cost: 35000 + Edges: 10.0.0.2 10.0.4.4 diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv4-metric.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv4-metric.txt new file mode 100644 index 000000000..060a39c9e --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-ipv4-metric.txt @@ -0,0 +1,3 @@ +Path computation success + Cost: 20 + Edges: 10.0.0.2 10.0.4.4 diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv4-te-metric.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv4-te-metric.txt new file mode 100644 index 000000000..6d983067e --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-ipv4-te-metric.txt @@ -0,0 +1,3 @@ +Path computation success + Cost: 35 + Edges: 10.0.1.2 10.0.4.4 diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv6-delay.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv6-delay.txt new file mode 100644 index 000000000..b65869bcf --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-ipv6-delay.txt @@ -0,0 +1,3 @@ +Path computation success + Cost: 70000 + Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4 diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv6-metric.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv6-metric.txt new file mode 100644 index 000000000..5acbb74d2 --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-ipv6-metric.txt @@ -0,0 +1,3 @@ +Path computation success + Cost: 30 + Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4 diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv6-te-metric.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv6-te-metric.txt new file mode 100644 index 000000000..2290a04a8 --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/cspf-ipv6-te-metric.txt @@ -0,0 +1,3 @@ +Path computation success + Cost: 60 + Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4 diff --git a/tests/topotests/cspf_topo1/reference/sharp-ted.json b/tests/topotests/cspf_topo1/reference/sharp-ted.json new file mode 100644 index 000000000..db50260ac --- /dev/null +++ b/tests/topotests/cspf_topo1/reference/sharp-ted.json @@ -0,0 +1,860 @@ +{ + "ted":{ + "name":"Sharp", + "key":1, + "verticesCount":4, + "edgesCount":14, + "subnetsCount":22, + "vertices":[ + { + "vertex-id":1, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r1", + "router-id":"10.0.255.1", + "router-id-v6":"2001:db8::1" + }, + { + "vertex-id":2, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r2", + "router-id":"10.0.255.2", + "router-id-v6":"2001:db8::2" + }, + { + "vertex-id":3, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r3", + "router-id":"10.0.255.3", + "router-id-v6":"2001:db8::3" + }, + { + "vertex-id":4, + "status":"Sync", + "origin":"ISIS_L2", + "name":"r4", + "router-id":"10.0.255.4", + "router-id-v6":"2001:db8::4", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":65537, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address-v6":"2001:db8:1::1:1", + "remote-address-v6":"2001:db8:1::1:2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":20000 + } + }, + { + "edge-id":65538, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address-v6":"2001:db8:1::1:2", + "remote-address-v6":"2001:db8:1::1:1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":20000 + } + }, + { + "edge-id":196610, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "te-metric":40, + "local-address-v6":"2001:db8:3::3:2", + "remote-address-v6":"2001:db8:3::3:3", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":40000 + } + }, + { + "edge-id":196611, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":25, + "admin-group":32, + "local-address-v6":"2001:db8:3::3:3", + "remote-address-v6":"2001:db8:3::3:2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000 + } + }, + { + "edge-id":196612, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "local-vertex-id":4, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address-v6":"2001:db8:5::3:4", + "remote-address-v6":"2001:db8:5::4:3", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000 + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0xb0", + "weight":0 + } + ] + }, + { + "edge-id":262147, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":4, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address-v6":"2001:db8:5::4:3", + "remote-address-v6":"2001:db8:5::3:4", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000 + } + }, + { + "edge-id":167772161, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000 + } + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "local-vertex-id":1, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":20000 + } + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":1, + "metric":10, + "edge-attributes":{ + "te-metric":10, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":20000 + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":3, + "metric":10, + "edge-attributes":{ + "te-metric":40, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.3", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":40000 + } + }, + { + "edge-id":167772931, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "local-vertex-id":3, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":25, + "admin-group":32, + "local-address":"10.0.3.3", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000 + } + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "local-vertex-id":2, + "remote-vertex-id":4, + "metric":10, + "edge-attributes":{ + "te-metric":25, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.4", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + } + }, + { + "edge-id":167773188, + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "local-vertex-id":4, + "remote-vertex-id":2, + "metric":10, + "edge-attributes":{ + "te-metric":40, + "local-address":"10.0.4.4", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":40000 + }, + "segment-routing":[ + { + "adj-sid":5000, + "flags":"0x30", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.0.2/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.1.1/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.1.2/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.3.2/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.3.3/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"10.0.4.2/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.4.4/24", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + }, + { + "subnet-id":"10.0.255.1/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"10.0.255.2/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"10.0.255.3/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"10.0.255.4/32", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x60" + } + }, + { + "subnet-id":"2001:db8:1::1:1/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8:1::1:2/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:3::3:2/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8:3::3:3/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8:5::3:4/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + }, + { + "subnet-id":"2001:db8:5::4:3/64", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8::1/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0001", + "vertex-id":1, + "metric":10 + }, + { + "subnet-id":"2001:db8::2/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0002", + "vertex-id":2, + "metric":10 + }, + { + "subnet-id":"2001:db8::3/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0003", + "vertex-id":3, + "metric":10 + }, + { + "subnet-id":"2001:db8::4/128", + "status":"Sync", + "origin":"ISIS_L2", + "advertised-router":"0000.0000.0004", + "vertex-id":4, + "metric":10 + } + ] + } +} diff --git a/tests/topotests/cspf_topo1/test_cspf_topo1.py b/tests/topotests/cspf_topo1/test_cspf_topo1.py new file mode 100644 index 000000000..1b71ac3a1 --- /dev/null +++ b/tests/topotests/cspf_topo1/test_cspf_topo1.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python + +# +# test_cspf_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2022 by Orange +# Author: Olivier Dugeon +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_cspf_topo1.py: Test the FRR Constraint Shortest Path First algorithm. + + +------------+ + | | + | R1 | + | 10.0.225.1 | + | | + +------------+ + r1-eth0| |r1-eth1 + | | + 10.0.0.0/24| |10.0.1.0/24 + | |2001:db8:1:/64 + | | + r2-eth0| |r2-eth1 + +------------+ +------------+ + | | | | + | R2 |r2-eth2 r3-eth0| R3 | + | 10.0.255.2 +------------------+ 10.0.255.3 | + | | 10.0.3.0/24 | | + +------------+ 2001:db8:3:/64 +------+-----+ + r2-eth3| r3-eth1| + | | + 10.0.4.0/24| | + | | + | | + r4-eth0| 2001:db8:5:/64| + +------------+ | + | | | + | R4 |r4-eth1 | + | 10.0.255.4 +-------------------------+ + | | + +------------+ + +""" + +import os +import sys +import json +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 + +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# and Finally pytest +import pytest + +pytestmark = [pytest.mark.isisd] + + +def build_topo(tgen): + "Build function" + + # Create 4 routers + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + # Interconect router 1 and 2 with 2 links + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + # Interconect router 3 and 2 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r2"]) + + # Interconect router 4 and 2 + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r2"]) + + # Interconnect router 3 and 4 + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + logger.info("\n\n---- Starting CSPF tests ----\n") + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + if rname == "r1": + router.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format("r1")) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(): + "Teardown the pytest environment" + + tgen = get_topogen() + tgen.stop_topology() + + logger.info("\n\n---- CSPF tests End ----\n") + + +def compare_ted_json_output(tgen, rname, fileref): + "Compare TED JSON output" + + logger.info('Comparing router "%s" TED output', rname) + + filename = "{}/reference/{}".format(CWD, fileref) + expected = json.loads(open(filename).read()) + command = "show sharp ted json" + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = '"{}" TED JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +def compare_cspf_output(tgen, rname, fileref, src, dst, cost, bw=""): + "Compare CSPF output" + + logger.info('Comparing router "%s" CSPF output', rname) + + filename = "{}/reference/{}".format(CWD, fileref) + expected = open(filename).read() + command = "show sharp cspf source {} destination {} {} {}".format(src, dst, cost, bw) + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(topotest.router_output_cmp, tgen.gears[rname], command, expected) + result, diff = topotest.run_and_expect(test_func, "", count=2, wait=2) + assert result, "CSPF output mismatches the expected result on {}:\n{}".format(rname, diff) + + +def setup_testcase(msg): + "Setup test case" + + logger.info(msg) + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + return tgen + + +# Note that all routers must discover the same Network Topology, so the same TED. + + +def test_step1(): + "Step1: Check initial topology" + + tgen = setup_testcase("Step1: test initial IS-IS TE Data Base import") + tgen.net["r1"].cmd('vtysh -c "sharp import-te"') + + compare_ted_json_output(tgen, "r1", "sharp-ted.json") + + +def test_step2(): + "Step2: Test CSPF from r1 to r4 for IPv4 with various metric" + + tgen = setup_testcase("Step2: CSPF(r1, r4, IPv4)") + + compare_cspf_output(tgen, "r1", "cspf-ipv4-metric.txt", "10.0.0.1", "10.0.255.4", "metric 50") + compare_cspf_output(tgen, "r1", "cspf-ipv4-te-metric.txt", "10.0.255.1", "10.0.4.4", "te-metric 50") + compare_cspf_output(tgen, "r1", "cspf-ipv4-delay.txt", "10.0.255.1", "10.0.255.4", "delay 50000") + compare_cspf_output(tgen, "r1", "cspf-ipv4-delay.txt", "10.0.255.1", "10.0.255.4", "delay 50000", "rsv 7 100000000") + + +def test_step3(): + "Step3: Test CSPF from r1 to r4 for IPv6 with various metric" + + tgen = setup_testcase("Step2: CSPF(r1, r4, IPv6)") + + compare_cspf_output(tgen, "r1", "cspf-ipv6-metric.txt", "2001:db8:1::1:1", "2001:db8::4", "metric 50") + compare_cspf_output(tgen, "r1", "cspf-ipv6-te-metric.txt", "2001:db8::1", "2001:db8:5::3:4", "te-metric 80") + compare_cspf_output(tgen, "r1", "cspf-ipv6-delay.txt", "2001:db8::1", "2001:db8::4", "delay 80000") + compare_cspf_output(tgen, "r1", "cspf-ipv6-delay.txt", "2001:db8::1", "2001:db8::4", "delay 80000", "rsv 7 100000000") + + +def test_step4(): + "Step4: Test CSPF from r1 to r4 with no possible path" + + tgen = setup_testcase("Step2: CSPF(r1, r4, failure)") + + compare_cspf_output(tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "metric 10") + compare_cspf_output(tgen, "r1", "cspf-failed.txt", "2001:db8::1", "2001:db8::4", "te-metric 50") + compare_cspf_output(tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "delay 5000") + compare_cspf_output(tgen, "r1", "cspf-failed.txt", "2001:db8::1", "2001:db8::4", "delay 80000", "rsv 7 1000000000") + compare_cspf_output(tgen, "r1", "cspf-failed-src.txt", "10.0.0.3", "10.0.255.4", "metric 10") + compare_cspf_output(tgen, "r1", "cspf-failed-dst.txt", "10.0.0.1", "10.0.4.40", "metric 10") + compare_cspf_output(tgen, "r1", "cspf-failed-same.txt", "10.0.0.1", "10.0.0.1", "metric 10") + + +def test_memory_leak(): + "Run the memory leak test and report results." + + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/isis_te_topo1/reference/ted_step1.json b/tests/topotests/isis_te_topo1/reference/ted_step1.json index 7a4773380..027dd806c 100644 --- a/tests/topotests/isis_te_topo1/reference/ted_step1.json +++ b/tests/topotests/isis_te_topo1/reference/ted_step1.json @@ -58,7 +58,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:1::1:1", "remote-address-v6":"2001:db8:1::1:2", "max-link-bandwidth":176258176.0, @@ -100,7 +99,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:1::1:2", "remote-address-v6":"2001:db8:1::1:1", "max-link-bandwidth":176258176.0, @@ -142,7 +140,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:3::3:2", "remote-address-v6":"2001:db8:3::3:3", "max-link-bandwidth":176258176.0, @@ -184,7 +181,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address-v6":"2001:db8:3::3:3", "remote-address-v6":"2001:db8:3::3:2", @@ -227,7 +223,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:5::3:4", "remote-address-v6":"2001:db8:5::4:3", "max-link-bandwidth":176258176.0, @@ -363,7 +358,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -405,7 +399,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.1", "remote-address":"10.0.1.2", "max-link-bandwidth":176258176.0, @@ -447,7 +440,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.2", "remote-address":"10.0.1.1", "max-link-bandwidth":176258176.0, @@ -489,7 +481,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.3", "max-link-bandwidth":176258176.0, @@ -531,7 +522,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.3", "remote-address":"10.0.3.2", @@ -618,7 +608,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.4", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/isis_te_topo1/reference/ted_step2.json b/tests/topotests/isis_te_topo1/reference/ted_step2.json index 8277e6d53..2e9a5ec84 100644 --- a/tests/topotests/isis_te_topo1/reference/ted_step2.json +++ b/tests/topotests/isis_te_topo1/reference/ted_step2.json @@ -58,7 +58,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:3::3:2", "remote-address-v6":"2001:db8:3::3:3", "max-link-bandwidth":176258176.0, @@ -100,7 +99,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address-v6":"2001:db8:3::3:3", "remote-address-v6":"2001:db8:3::3:2", @@ -143,7 +141,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:5::3:4", "remote-address-v6":"2001:db8:5::4:3", "max-link-bandwidth":176258176.0, @@ -279,7 +276,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -321,7 +317,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.3", "max-link-bandwidth":176258176.0, @@ -363,7 +358,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.3", "remote-address":"10.0.3.2", @@ -450,7 +444,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.4", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/isis_te_topo1/reference/ted_step3.json b/tests/topotests/isis_te_topo1/reference/ted_step3.json index 0ade39884..5c7ccdd6a 100644 --- a/tests/topotests/isis_te_topo1/reference/ted_step3.json +++ b/tests/topotests/isis_te_topo1/reference/ted_step3.json @@ -102,7 +102,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8::2", "max-link-bandwidth":176258176.0, "max-resv-link-bandwidth":176258176.0, @@ -143,7 +142,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:3::3:2", "remote-address-v6":"2001:db8:3::3:3", "max-link-bandwidth":176258176.0, @@ -185,7 +183,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address-v6":"2001:db8:3::3:3", "remote-address-v6":"2001:db8:3::3:2", @@ -228,7 +225,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:5::3:4", "remote-address-v6":"2001:db8:5::4:3", "max-link-bandwidth":176258176.0, @@ -364,7 +360,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -406,7 +401,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.3", "max-link-bandwidth":176258176.0, @@ -448,7 +442,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.3", "remote-address":"10.0.3.2", @@ -535,7 +528,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.4", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/isis_te_topo1/reference/ted_step4.json b/tests/topotests/isis_te_topo1/reference/ted_step4.json index 0ade39884..5c7ccdd6a 100644 --- a/tests/topotests/isis_te_topo1/reference/ted_step4.json +++ b/tests/topotests/isis_te_topo1/reference/ted_step4.json @@ -102,7 +102,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8::2", "max-link-bandwidth":176258176.0, "max-resv-link-bandwidth":176258176.0, @@ -143,7 +142,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:3::3:2", "remote-address-v6":"2001:db8:3::3:3", "max-link-bandwidth":176258176.0, @@ -185,7 +183,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address-v6":"2001:db8:3::3:3", "remote-address-v6":"2001:db8:3::3:2", @@ -228,7 +225,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:5::3:4", "remote-address-v6":"2001:db8:5::4:3", "max-link-bandwidth":176258176.0, @@ -364,7 +360,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -406,7 +401,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.3", "max-link-bandwidth":176258176.0, @@ -448,7 +442,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.3", "remote-address":"10.0.3.2", @@ -535,7 +528,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.4", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/isis_te_topo1/reference/ted_step5.json b/tests/topotests/isis_te_topo1/reference/ted_step5.json index ba9bdb01f..48d475c72 100644 --- a/tests/topotests/isis_te_topo1/reference/ted_step5.json +++ b/tests/topotests/isis_te_topo1/reference/ted_step5.json @@ -102,7 +102,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8::2", "max-link-bandwidth":176258176.0, "max-resv-link-bandwidth":176258176.0, @@ -143,7 +142,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:1::1:1", "remote-address-v6":"2001:db8:1::1:2", "max-link-bandwidth":176258176.0, @@ -185,7 +183,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:1::1:2", "remote-address-v6":"2001:db8:1::1:1", "max-link-bandwidth":176258176.0, @@ -227,7 +224,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:3::3:2", "remote-address-v6":"2001:db8:3::3:3", "max-link-bandwidth":176258176.0, @@ -269,7 +265,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address-v6":"2001:db8:3::3:3", "remote-address-v6":"2001:db8:3::3:2", @@ -312,7 +307,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:5::3:4", "remote-address-v6":"2001:db8:5::4:3", "max-link-bandwidth":176258176.0, @@ -448,7 +442,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -490,7 +483,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.1", "remote-address":"10.0.1.2", "max-link-bandwidth":176258176.0, @@ -532,7 +524,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.2", "remote-address":"10.0.1.1", "max-link-bandwidth":176258176.0, @@ -574,7 +565,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.3", "max-link-bandwidth":176258176.0, @@ -616,7 +606,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.3", "remote-address":"10.0.3.2", @@ -703,7 +692,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.4", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/isis_te_topo1/reference/ted_step6.json b/tests/topotests/isis_te_topo1/reference/ted_step6.json index 83bb27235..75443a42e 100644 --- a/tests/topotests/isis_te_topo1/reference/ted_step6.json +++ b/tests/topotests/isis_te_topo1/reference/ted_step6.json @@ -102,7 +102,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8::2", "max-link-bandwidth":176258176.0, "max-resv-link-bandwidth":176258176.0, @@ -143,7 +142,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:1::1:1", "remote-address-v6":"2001:db8:1::1:2", "max-link-bandwidth":176258176.0, @@ -185,7 +183,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:1::1:2", "remote-address-v6":"2001:db8:1::1:1", "max-link-bandwidth":176258176.0, @@ -227,7 +224,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:3::3:2", "remote-address-v6":"2001:db8:3::3:3", "max-link-bandwidth":176258176.0, @@ -269,7 +265,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address-v6":"2001:db8:3::3:3", "remote-address-v6":"2001:db8:3::3:2", @@ -312,7 +307,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address-v6":"2001:db8:5::3:4", "remote-address-v6":"2001:db8:5::4:3", "max-link-bandwidth":176258176.0, @@ -448,7 +442,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -490,7 +483,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.1", "remote-address":"10.0.1.2", "max-link-bandwidth":176258176.0, @@ -532,7 +524,6 @@ "remote-vertex-id":1, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.2", "remote-address":"10.0.1.1", "max-link-bandwidth":176258176.0, @@ -574,7 +565,6 @@ "remote-vertex-id":3, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.3", "max-link-bandwidth":176258176.0, @@ -616,7 +606,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.3", "remote-address":"10.0.3.2", @@ -702,7 +691,6 @@ "remote-vertex-id":2, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.4", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index 94c5faf2e..014722387 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -236,6 +236,94 @@ def test_isis_linux_route6_installation(): assert topotest.json_cmp(actual, expected) is None, assertmsg +def test_isis_summary_json(): + "Check json struct in show isis summary json" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking 'show isis summary json'") + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True) + assertmsg = "Test isis summary json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['vrf'] == "default", assertmsg + assert json_output['areas'][0]['area'] == "1", assertmsg + assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg + + +def test_isis_interface_json(): + "Check json struct in show isis interface json" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking 'show isis interface json'") + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis interface json", isjson=True) + assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg + + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis interface detail json", isjson=True) + assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg + + +def test_isis_neighbor_json(): + "Check json struct in show isis neighbor json" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + #tgen.mininet_cli() + logger.info("Checking 'show isis neighbor json'") + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor json", isjson=True) + assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['circuits'][0]['interface'] == rname+"-eth0", assertmsg + + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor detail json", isjson=True) + assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg + + +def test_isis_database_json(): + "Check json struct in show isis database json" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + #tgen.mininet_cli() + logger.info("Checking 'show isis database json'") + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis database json", isjson=True) + assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['area']['name'] == "1", assertmsg + assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg + + for rname, router in tgen.routers().items(): + logger.info("Checking router %s", rname) + json_output = tgen.gears[rname].vtysh_cmd("show isis database detail json", isjson=True) + assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output) + assert json_output['areas'][0]['area']['name'] == "1", assertmsg + assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py index 3608c5a48..01f3fe182 100644 --- a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py +++ b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py @@ -21,7 +21,7 @@ # OF THIS SOFTWARE. # -""" +r""" test_ldp_oc_acl_topo1.py: Simple FRR LDP Test +---------+ diff --git a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py index 972692691..4faaf45c1 100644 --- a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py +++ b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py @@ -21,7 +21,7 @@ # OF THIS SOFTWARE. # -""" +r""" test_ldp_oc_topo1.py: Simple FRR LDP Test +---------+ diff --git a/tests/topotests/ldp_topo1/test_ldp_topo1.py b/tests/topotests/ldp_topo1/test_ldp_topo1.py index 4a33edb9d..8d6978723 100644 --- a/tests/topotests/ldp_topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp_topo1/test_ldp_topo1.py @@ -22,7 +22,7 @@ # OF THIS SOFTWARE. # -""" +r""" test_ldp_topo1.py: Simple FRR LDP Test +---------+ diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 551483d71..34afa0d2c 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -3677,7 +3677,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): @retry(retry_timeout=10) def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer): """ - This API is to verify graceful restart timers, configured and recieved + This API is to verify graceful restart timers, configured and received Parameters ---------- diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index f538b5a52..c0572fca4 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1195,7 +1195,7 @@ def add_interfaces_to_vlan(tgen, input_dict): # Assigning IP address ifaddr = ipaddress.ip_interface( - u"{}/{}".format( + "{}/{}".format( frr_unicode(data["ip"]), frr_unicode(data["subnet"]) ) ) @@ -1626,7 +1626,7 @@ def create_interface_in_kernel( ifaddr = ipaddress.ip_interface(frr_unicode(ip_addr)) else: ifaddr = ipaddress.ip_interface( - u"{}/{}".format(frr_unicode(ip_addr), frr_unicode(netmask)) + "{}/{}".format(frr_unicode(ip_addr), frr_unicode(netmask)) ) cmd = "ip -{0} a flush {1} scope global && ip a add {2} dev {1} && ip l set {1} up".format( ifaddr.version, name, ifaddr @@ -4921,8 +4921,13 @@ def verify_ip_nht(tgen, input_dict): for nh in nh_list: if nh in show_ip_nht: - logger.info("Nexthop %s is resolved on %s", nh, router) - return True + nht = run_frr_cmd(rnode, f"show ip nht {nh}") + if "unresolved" in nht: + errormsg = "Nexthop {} became unresolved on {}".format(nh, router) + return errormsg + else: + logger.info("Nexthop %s is resolved on %s", nh, router) + return True else: errormsg = "Nexthop {} is resolved on {}".format(nh, router) return errormsg diff --git a/tests/topotests/lib/micronet.py b/tests/topotests/lib/micronet.py index 8567bd3b4..59dd80ff7 100644 --- a/tests/topotests/lib/micronet.py +++ b/tests/topotests/lib/micronet.py @@ -358,11 +358,14 @@ class Commander(object): # pylint: disable=R0205 # wait for not supported in screen for now channel = None cmd = [self.get_exec_path("screen")] + if title: + cmd.append("-t") + cmd.append(title) if not os.path.exists( "/run/screen/S-{}/{}".format(os.environ["USER"], os.environ["STY"]) ): cmd = ["sudo", "-u", os.environ["SUDO_USER"]] + cmd - cmd.append(nscmd) + cmd.extend(nscmd.split(" ")) elif "DISPLAY" in os.environ: # We need it broken up for xterm user_cmd = cmd diff --git a/tests/topotests/lib/micronet_cli.py b/tests/topotests/lib/micronet_cli.py index 6459d5d15..4292f47ce 100644 --- a/tests/topotests/lib/micronet_cli.py +++ b/tests/topotests/lib/micronet_cli.py @@ -113,11 +113,11 @@ def doline(unet, line, writef): hosts = [unet.hosts[x] for x in args] for host in hosts: if cmd == "t" or cmd == "term": - host.run_in_window("bash") + host.run_in_window("bash", title="sh-%s" % host) elif cmd == "v" or cmd == "vtysh": - host.run_in_window("vtysh") + host.run_in_window("vtysh", title="vt-%s" % host) elif cmd == "x" or cmd == "xterm": - host.run_in_window("bash", forcex=True) + host.run_in_window("bash", title="sh-%s" % host, forcex=True) elif cmd == "sh": hosts, cmd = host_cmd_split(unet, oargs) for host in hosts: diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 92d29ad1a..8d2bf12af 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -1933,7 +1933,7 @@ def verify_ospf6_interface(tgen, topo=None, dut=None, lan=False, input_dict=None True or False (Error Message) """ - logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + logger.debug("Entering lib API: verify_ospf6_interface") result = False if topo is None: @@ -2311,6 +2311,7 @@ def config_ospf6_interface( ------- True or False """ + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) result = False if topo is None: @@ -2337,6 +2338,7 @@ def config_ospf6_interface( ospf_data = input_dict[router]["links"][lnk]["ospf6"] data_ospf_area = ospf_data.setdefault("area", None) data_ospf_auth = ospf_data.setdefault("hash-algo", None) + data_ospf_keychain = ospf_data.setdefault("keychain", None) data_ospf_dr_priority = ospf_data.setdefault("priority", None) data_ospf_cost = ospf_data.setdefault("cost", None) data_ospf_mtu = ospf_data.setdefault("mtu_ignore", None) @@ -2369,9 +2371,18 @@ def config_ospf6_interface( ospf_data["hash-algo"], ospf_data["key"], ) - if "del_action" in ospf_data: - cmd = "no {}".format(cmd) - config_data.append(cmd) + config_data.append(cmd) + + # interface ospf auth with keychain + if data_ospf_keychain: + cmd = "ipv6 ospf6 authentication" + + if "del_action" in ospf_data: + cmd = "no {}".format(cmd) + + if "keychain" in ospf_data: + cmd = "{} keychain {}".format(cmd, ospf_data["keychain"]) + config_data.append(cmd) # interface ospf dr priority if data_ospf_dr_priority: diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 33e138863..a83ae7071 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -706,6 +706,7 @@ class TopoRouter(TopoGear): ] # Router Daemon enumeration definition. + RD_FRR = 0 # not a daemon, but use to setup unified configs RD_ZEBRA = 1 RD_RIP = 2 RD_RIPNG = 3 @@ -725,6 +726,7 @@ class TopoRouter(TopoGear): RD_PATH = 17 RD_SNMP = 18 RD = { + RD_FRR: "frr", RD_ZEBRA: "zebra", RD_RIP: "ripd", RD_RIPNG: "ripngd", @@ -789,6 +791,28 @@ class TopoRouter(TopoGear): self.logger.info('check capability {} for "{}"'.format(param, daemonstr)) return self.net.checkCapability(daemonstr, param) + def load_frr_config(self, source, daemons=None): + """ + Loads the unified configuration file source + Start the daemons in the list + If daemons is None, try to infer daemons from the config file + """ + self.load_config(self.RD_FRR, source) + if not daemons: + # Always add zebra + self.load_config(self.RD_ZEBRA) + for daemon in self.RD: + # This will not work for all daemons + daemonstr = self.RD.get(daemon).rstrip("d") + result = self.run( + "grep 'router {}' {}".format(daemonstr, source) + ).strip() + if result: + self.load_config(daemon) + else: + for daemon in daemons: + self.load_config(daemon) + def load_config(self, daemon, source=None, param=None): """Loads daemon configuration from the specified source Possible daemon values are: TopoRouter.RD_ZEBRA, TopoRouter.RD_RIP, diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 6be644ac0..62b6a8a70 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1319,6 +1319,7 @@ class Router(Node): self.daemondir = None self.hasmpls = False self.routertype = "frr" + self.unified_config = None self.daemons = { "zebra": 0, "ripd": 0, @@ -1521,21 +1522,28 @@ class Router(Node): ) # print "Daemons before:", self.daemons - if daemon in self.daemons.keys(): - self.daemons[daemon] = 1 + if daemon in self.daemons.keys() or daemon == "frr": + if daemon == "frr": + self.unified_config = 1 + else: + self.daemons[daemon] = 1 if param is not None: self.daemons_options[daemon] = param conf_file = "/etc/{}/{}.conf".format(self.routertype, daemon) if source is None or not os.path.exists(source): - self.cmd_raises("rm -f " + conf_file) - self.cmd_raises("touch " + conf_file) + if daemon == "frr" or not self.unified_config: + self.cmd_raises("rm -f " + conf_file) + self.cmd_raises("touch " + conf_file) else: self.cmd_raises("cp {} {}".format(source, conf_file)) - self.cmd_raises("chown {0}:{0} {1}".format(self.routertype, conf_file)) - self.cmd_raises("chmod 664 {}".format(conf_file)) + + if not self.unified_config or daemon == "frr": + self.cmd_raises("chown {0}:{0} {1}".format(self.routertype, conf_file)) + self.cmd_raises("chmod 664 {}".format(conf_file)) + if (daemon == "snmpd") and (self.routertype == "frr"): # /etc/snmp is private mount now - self.cmd('echo "agentXSocket /etc/frr/agentx" > /etc/snmp/frr.conf') + self.cmd('echo "agentXSocket /etc/frr/agentx" >> /etc/snmp/frr.conf') self.cmd('echo "mibs +ALL" > /etc/snmp/snmp.conf') if (daemon == "zebra") and (self.daemons["staticd"] == 0): @@ -1557,11 +1565,18 @@ class Router(Node): return self.run_in_window(cmd, title) def startRouter(self, tgen=None): - # Disable integrated-vtysh-config - self.cmd( - 'echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf' - % self.routertype - ) + if self.unified_config: + self.cmd( + 'echo "service integrated-vtysh-config" >> /etc/%s/vtysh.conf' + % self.routertype + ) + else: + # Disable integrated-vtysh-config + self.cmd( + 'echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf' + % self.routertype + ) + self.cmd( "chown %s:%svty /etc/%s/vtysh.conf" % (self.routertype, self.routertype, self.routertype) @@ -1613,7 +1628,7 @@ class Router(Node): shell_routers = g_extra_config["shell"] if "all" in shell_routers or self.name in shell_routers: - self.run_in_window(os.getenv("SHELL", "bash")) + self.run_in_window(os.getenv("SHELL", "bash"), title="sh-%s" % self.name) if self.daemons["eigrpd"] == 1: eigrpd_path = os.path.join(self.daemondir, "eigrpd") @@ -1631,7 +1646,10 @@ class Router(Node): vtysh_routers = g_extra_config["vtysh"] if "all" in vtysh_routers or self.name in vtysh_routers: - self.run_in_window("vtysh") + self.run_in_window("vtysh", title="vt-%s" % self.name) + + if self.unified_config: + self.cmd("vtysh -f /etc/frr/frr.conf") return status @@ -1731,7 +1749,7 @@ class Router(Node): daemon, self.logdir, self.name ) - cmdopt = "{} --log file:{}.log --log-level debug".format( + cmdopt = "{} --command-log-always --log file:{}.log --log-level debug".format( daemon_opts, daemon ) if extra_opts: diff --git a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py index a8418d400..4ab160b52 100644 --- a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py +++ b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py @@ -501,7 +501,7 @@ def test_BSR_higher_prefer_ip_p0(request): step("sleeping for 3 sec to leran new packet") do_countdown(3) - step("verify BSR1 is become prefered RP") + step("verify BSR1 has become preferred RP") dut = "l1" step("Verify if b1 chosen as BSR in f1") @@ -521,7 +521,7 @@ def test_BSR_higher_prefer_ip_p0(request): do_countdown(3) f1_b2_eth1 = topo["routers"]["f1"]["links"]["b2"]["interface"] shutdown_bringup_interface(tgen, "f1", "f1-b2-eth1", True) - step("verify BSR2 is become prefered RP") + step("verify BSR2 has become preferred RP") dut = "l1" step("Send BSR packet from b1 and b2 to FHR") diff --git a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py index 99379354f..53d84e619 100644 --- a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py @@ -22,7 +22,7 @@ # OF THIS SOFTWARE. # -""" +r""" test_ospf6_topo1.py: -----\ diff --git a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py index ac4a23da9..f823d5aef 100755 --- a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py +++ b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py @@ -23,7 +23,7 @@ # OF THIS SOFTWARE. # -""" +r""" test_ospf6_topo1_vrf.py: -----\ diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index fb96054db..88c87dcec 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -81,6 +81,8 @@ NETWORK = { "11.0.20.5/32", ] } + +NETWORK_APP_E = {"ipv4": ["12.0.0.0/24", "12.0.0.0/16", "12.0.0.0/8"]} TOPOOLOGY = """ Please view in a fixed-width font such as Courier. +---+ A1 +---+ @@ -557,6 +559,154 @@ def test_ospf_redistribution_tc8_p1(request): write_test_footer(tc_name) +def test_ospf_rfc2328_appendinxE_p0(request): + """ + Test OSPF appendinx E RFC2328. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + + reset_config_on_routers(tgen) + + step("Verify that OSPF neighbours are Full.") + # Api call verify whether OSPF is converged + ospf_covergence = verify_ospf_neighbor(tgen, topo) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) + + redistribute_ospf(tgen, topo, "r0", "static") + + step("Configure static route with prefix 24, 16, 8 to check ") + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK_APP_E["ipv4"][0], + "no_of_ip": 1, + "next_hop": "Null0", + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK_APP_E["ipv4"][1], + "no_of_ip": 1, + "next_hop": "Null0", + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK_APP_E["ipv4"][2], + "no_of_ip": 1, + "next_hop": "Null0", + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that ospf originates routes with mask 24, 16, 8") + ip_net = NETWORK_APP_E["ipv4"][0] + input_dict = {"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1}]}} + + dut = "r1" + result = verify_ospf_rib(tgen, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + protocol = "ospf" + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ip_net = NETWORK_APP_E["ipv4"][1] + input_dict = {"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1}]}} + + dut = "r1" + result = verify_ospf_rib(tgen, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + protocol = "ospf" + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ip_net = NETWORK_APP_E["ipv4"][2] + input_dict = {"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1}]}} + + dut = "r1" + result = verify_ospf_rib(tgen, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + protocol = "ospf" + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Delete static route with prefix 24, 16, 8 to check ") + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK_APP_E["ipv4"][0], + "no_of_ip": 1, + "next_hop": "Null0", + "delete": True, + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK_APP_E["ipv4"][1], + "no_of_ip": 1, + "next_hop": "Null0", + "delete": True, + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK_APP_E["ipv4"][2], + "no_of_ip": 1, + "next_hop": "Null0", + "delete": True, + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + def test_ospf_cost_tc52_p0(request): """OSPF Cost - verifying ospf interface cost functionality""" tc_name = request.node.name diff --git a/tests/topotests/ospf_netns_vrf/__init__.py b/tests/topotests/ospf_netns_vrf/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/tests/topotests/ospf_netns_vrf/r1/ospfd.conf b/tests/topotests/ospf_netns_vrf/r1/ospfd.conf new file mode 100644 index 000000000..e1e2bfb99 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r1/ospfd.conf @@ -0,0 +1,13 @@ +! +hostname r1 +password zebra +log file /tmp/r1-ospfd.log +! +router ospf vrf r1-ospf-cust1 + ospf router-id 10.0.255.1 + redistribute kernel + redistribute connected + redistribute static + network 10.0.1.0/24 area 0 + network 10.0.3.0/24 area 0 +! diff --git a/tests/topotests/ospf_netns_vrf/r1/ospfroute.txt b/tests/topotests/ospf_netns_vrf/r1/ospfroute.txt new file mode 100644 index 000000000..d617ab36d --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r1/ospfroute.txt @@ -0,0 +1,18 @@ +VRF Name: r1-ospf-cust1 +============ OSPF network routing table ============ +N 10.0.1.0/24 [10] area: 0.0.0.0 + directly attached to r1-eth0 +N 10.0.2.0/24 [20] area: 0.0.0.0 + via 10.0.3.3, r1-eth1 +N 10.0.3.0/24 [10] area: 0.0.0.0 + directly attached to r1-eth1 +N 10.0.10.0/24 [20] area: 0.0.0.0 + via 10.0.3.1, r1-eth1 + +============ OSPF router routing table ============= +R 10.0.255.2 [10] area: 0.0.0.0, ASBR + via 10.0.3.3, r1-eth1 +R 10.0.255.3 [10] area: 0.0.0.0, ASBR + via 10.0.3.1, r1-eth1 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_netns_vrf/r1/ospfroute_down.txt b/tests/topotests/ospf_netns_vrf/r1/ospfroute_down.txt new file mode 100644 index 000000000..4f7fd699c --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r1/ospfroute_down.txt @@ -0,0 +1,14 @@ +VRF Name: r1-ospf-cust1 +============ OSPF network routing table ============ +N 10.0.1.0/24 [10] area: 0.0.0.0 + directly attached to r1-eth0 +N 10.0.2.0/24 [20] area: 0.0.0.0 + via 10.0.3.3, r1-eth1 +N 10.0.3.0/24 [10] area: 0.0.0.0 + directly attached to r1-eth1 + +============ OSPF router routing table ============= +R 10.0.255.2 [10] area: 0.0.0.0, ASBR + via 10.0.3.3, r1-eth1 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_netns_vrf/r1/zebra.conf b/tests/topotests/ospf_netns_vrf/r1/zebra.conf new file mode 100644 index 000000000..56d7a9764 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r1/zebra.conf @@ -0,0 +1,17 @@ +! debug zebra kernel +! debug zebra dplane detail +! debug zebra rib +! debug zebra event +! +hostname r1 +password zebra +log file /tmp/r1-zebra.log +! +interface r1-eth0 vrf r1-ospf-cust1 + ip address 10.0.1.1/24 +! +interface r1-eth1 vrf r1-ospf-cust1 + ip address 10.0.3.2/24 +! +ip forwarding +! diff --git a/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt new file mode 100644 index 000000000..979af20c5 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt @@ -0,0 +1,8 @@ +VRF r1-ospf-cust1: +O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX +C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX +O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX +O 10.0.3.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r1-eth1, XX:XX:XX +O>* 10.0.10.0/24 [110/20] via 10.0.3.1, r1-eth1, weight 1, XX:XX:XX + diff --git a/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt new file mode 100644 index 000000000..ec99fad76 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt @@ -0,0 +1,7 @@ +VRF r1-ospf-cust1: +O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX +C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX +O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX +O 10.0.3.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r1-eth1, XX:XX:XX + diff --git a/tests/topotests/ospf_netns_vrf/r2/ospfd.conf b/tests/topotests/ospf_netns_vrf/r2/ospfd.conf new file mode 100644 index 000000000..c1984276f --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r2/ospfd.conf @@ -0,0 +1,14 @@ +! +hostname r2 +password zebra +log file /tmp/r2-ospfd.log +! +! +router ospf vrf r2-ospf-cust1 + ospf router-id 10.0.255.2 + redistribute kernel + redistribute connected + redistribute static + network 10.0.2.0/24 area 0 + network 10.0.3.0/24 area 0 +! diff --git a/tests/topotests/ospf_netns_vrf/r2/ospfroute.txt b/tests/topotests/ospf_netns_vrf/r2/ospfroute.txt new file mode 100644 index 000000000..89763ff73 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r2/ospfroute.txt @@ -0,0 +1,18 @@ +VRF Name: r2-ospf-cust1 +============ OSPF network routing table ============ +N 10.0.1.0/24 [20] area: 0.0.0.0 + via 10.0.3.2, r2-eth1 +N 10.0.2.0/24 [10] area: 0.0.0.0 + directly attached to r2-eth0 +N 10.0.3.0/24 [10] area: 0.0.0.0 + directly attached to r2-eth1 +N 10.0.10.0/24 [20] area: 0.0.0.0 + via 10.0.3.1, r2-eth1 + +============ OSPF router routing table ============= +R 10.0.255.1 [10] area: 0.0.0.0, ASBR + via 10.0.3.2, r2-eth1 +R 10.0.255.3 [10] area: 0.0.0.0, ASBR + via 10.0.3.1, r2-eth1 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_netns_vrf/r2/ospfroute_down.txt b/tests/topotests/ospf_netns_vrf/r2/ospfroute_down.txt new file mode 100644 index 000000000..d946f02df --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r2/ospfroute_down.txt @@ -0,0 +1,14 @@ +VRF Name: r2-ospf-cust1 +============ OSPF network routing table ============ +N 10.0.1.0/24 [20] area: 0.0.0.0 + via 10.0.3.2, r2-eth1 +N 10.0.2.0/24 [10] area: 0.0.0.0 + directly attached to r2-eth0 +N 10.0.3.0/24 [10] area: 0.0.0.0 + directly attached to r2-eth1 + +============ OSPF router routing table ============= +R 10.0.255.1 [10] area: 0.0.0.0, ASBR + via 10.0.3.2, r2-eth1 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_netns_vrf/r2/zebra.conf b/tests/topotests/ospf_netns_vrf/r2/zebra.conf new file mode 100644 index 000000000..6ff72d126 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r2/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r2 +password zebra +log file /tmp/r2-zebra.log +! +interface r2-eth0 vrf r2-ospf-cust1 + ip address 10.0.2.1/24 +! +interface r2-eth1 vrf r2-ospf-cust1 + ip address 10.0.3.3/24 +! +ip forwarding +! diff --git a/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt new file mode 100644 index 000000000..df66e92ab --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt @@ -0,0 +1,8 @@ +VRF r2-ospf-cust1: +O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX +O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX +C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX +O 10.0.3.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r2-eth1, XX:XX:XX +O>* 10.0.10.0/24 [110/20] via 10.0.3.1, r2-eth1, weight 1, XX:XX:XX + diff --git a/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt new file mode 100644 index 000000000..4afc354ca --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt @@ -0,0 +1,7 @@ +VRF r2-ospf-cust1: +O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX +O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX +C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX +O 10.0.3.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r2-eth1, XX:XX:XX + diff --git a/tests/topotests/ospf_netns_vrf/r3/ospfd.conf b/tests/topotests/ospf_netns_vrf/r3/ospfd.conf new file mode 100644 index 000000000..b73d547e3 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r3/ospfd.conf @@ -0,0 +1,15 @@ +! +hostname r3 +password zebra +log file /tmp/r3-ospfd.log +! +! +router ospf vrf r3-ospf-cust1 + ospf router-id 10.0.255.3 + redistribute kernel + redistribute connected + redistribute static + network 10.0.3.0/24 area 0 + network 10.0.10.0/24 area 0 + network 172.16.0.0/24 area 1 +! diff --git a/tests/topotests/ospf_netns_vrf/r3/ospfroute.txt b/tests/topotests/ospf_netns_vrf/r3/ospfroute.txt new file mode 100644 index 000000000..917702b14 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r3/ospfroute.txt @@ -0,0 +1,18 @@ +VRF Name: r3-ospf-cust1 +============ OSPF network routing table ============ +N 10.0.1.0/24 [20] area: 0.0.0.0 + via 10.0.3.2, r3-eth0 +N 10.0.2.0/24 [20] area: 0.0.0.0 + via 10.0.3.3, r3-eth0 +N 10.0.3.0/24 [10] area: 0.0.0.0 + directly attached to r3-eth0 +N 10.0.10.0/24 [10] area: 0.0.0.0 + directly attached to r3-eth1 + +============ OSPF router routing table ============= +R 10.0.255.1 [10] area: 0.0.0.0, ASBR + via 10.0.3.2, r3-eth0 +R 10.0.255.2 [10] area: 0.0.0.0, ASBR + via 10.0.3.3, r3-eth0 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_netns_vrf/r3/ospfroute_down.txt b/tests/topotests/ospf_netns_vrf/r3/ospfroute_down.txt new file mode 100644 index 000000000..966185e49 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r3/ospfroute_down.txt @@ -0,0 +1,8 @@ +VRF Name: r3-ospf-cust1 +============ OSPF network routing table ============ +N 10.0.10.0/24 [10] area: 0.0.0.0 + directly attached to r3-eth1 + +============ OSPF router routing table ============= + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_netns_vrf/r3/zebra.conf b/tests/topotests/ospf_netns_vrf/r3/zebra.conf new file mode 100644 index 000000000..153415004 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r3/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r3 +password zebra +log file /tmp/r3-zebra.log +! +interface r3-eth0 vrf r3-ospf-cust1 + ip address 10.0.3.1/24 +! +interface r3-eth1 vrf r3-ospf-cust1 + ip address 10.0.10.1/24 +! +ip forwarding +! diff --git a/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt new file mode 100644 index 000000000..b435c2ebe --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt @@ -0,0 +1,8 @@ +VRF r3-ospf-cust1: +O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r3-eth0, weight 1, XX:XX:XX +O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r3-eth0, weight 1, XX:XX:XX +O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r3-eth0, XX:XX:XX +O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX +C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX + diff --git a/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt new file mode 100644 index 000000000..f30a4be6c --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt @@ -0,0 +1,4 @@ +VRF r3-ospf-cust1: +O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX +C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX + diff --git a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.dot b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.dot new file mode 100644 index 000000000..789fdd7c0 --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.dot @@ -0,0 +1,78 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph ospf_topo1 { + label="ospf topo1"; + + # Routers + r1 [ + label="r1\nrtr-id 10.0.255.1/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r2 [ + label="r2\nrtr-id 10.0.255.2/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r3 [ + label="r3\nrtr-id 10.0.255.3/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + label="s1\n10.0.1.0/24\n2001:db8:1::/64", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + label="s2\n10.0.2.0/24\n2001:db8:2::/64", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s3 [ + label="s3\n10.0.3.0/24\n2001:db8:3::/64", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s4 [ + label="s4\n10.0.10.0/24\n2001:db8:100::/64", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + subgraph cluster0 { + label="area 0" + + r1 -- s1 [label="eth0\n.1\n::1"]; + r1 -- s3 [label="eth1\n.2\n::2"]; + + r2 -- s2 [label="eth0\n.1\n::1"]; + r2 -- s3 [label="eth1\n.3\n::3"]; + + r3 -- s3 [label="eth0\n.1\n::1"]; + r3 -- s4 [label="eth1\n.1\n::1"]; + } + +} diff --git a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.jpg b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.jpg new file mode 100644 index 000000000..85f2e52f8 Binary files /dev/null and b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.jpg differ diff --git a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py new file mode 100644 index 000000000..621d8079d --- /dev/null +++ b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py @@ -0,0 +1,324 @@ +#!/usr/bin/env python + +# +# test_ospf_netns_vrf.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_ospf_netns_vrf.py: Test OSPF with Network Namespace VRFs. +""" + +import os +import sys +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +pytestmark = [pytest.mark.ospfd] + + +def build_topo(tgen): + "Build function" + + # Create 3 routers + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + # Create a empty network for router 1 + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + # Create a empty network for router 2 + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + + # Interconect router 1, 2 and 3 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + # Create empty netowrk for router3 + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + # check for zebra capability + for rname, router in router_list.items(): + if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False: + return pytest.skip( + "Skipping OSPF VRF NETNS feature. VRF NETNS backend not available on FRR" + ) + + if os.system("ip netns list") != 0: + return pytest.skip( + "Skipping OSPF VRF NETNS Test. NETNS not available on System" + ) + + logger.info("Testing with VRF Namespace support") + + for rname, router in router_list.items(): + # create VRF rx-ospf-cust1 and link rx-eth{0,1} to rx-ospf-cust1 + ns = "{}-ospf-cust1".format(rname) + router.net.add_netns(ns) + router.net.set_intf_netns(rname + "-eth0", ns, up=True) + router.net.set_intf_netns(rname + "-eth1", ns, up=True) + + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, "{}/zebra.conf".format(rname)), + "--vrfwnetns", + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + for router in router_list.values(): + if router.has_version("<", "4.0"): + tgen.set_error("unsupported version") + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # Move interfaces out of vrf namespace and delete the namespace + router_list = tgen.routers() + for rname, router in router_list.items(): + tgen.net[rname].reset_intf_netns(rname + "-eth0") + tgen.net[rname].reset_intf_netns(rname + "-eth1") + tgen.net[rname].delete_netns(rname + "-ospf-cust1") + tgen.stop_topology() + + +# Shared test function to validate expected output. +def compare_show_ip_route_vrf(rname, expected): + """ + Calls 'show ip ospf vrf [rname]-ospf-cust1 route' for router `rname` and compare the obtained + result with the expected output. + """ + tgen = get_topogen() + vrf_name = "{0}-ospf-cust1".format(rname) + current = topotest.ip4_route_zebra(tgen.gears[rname], vrf_name) + ret = topotest.difflines( + current, expected, title1="Current output", title2="Expected output" + ) + return ret + + +def test_ospf_convergence(): + "Test OSPF daemon convergence" + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + for rname, router in tgen.routers().items(): + logger.info('Waiting for router "%s" convergence', rname) + + # Load expected results from the command + reffile = os.path.join(CWD, "{}/ospfroute.txt".format(rname)) + expected = open(reffile).read() + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial( + topotest.router_output_cmp, + router, + "show ip ospf vrf {0}-ospf-cust1 route".format(rname), + expected, + ) + result, diff = topotest.run_and_expect(test_func, "", count=160, wait=0.5) + assertmsg = "OSPF did not converge on {}:\n{}".format(rname, diff) + assert result, assertmsg + + +def test_ospf_kernel_route(): + "Test OSPF kernel route installation" + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + rlist = tgen.routers().values() + for router in rlist: + logger.info('Checking OSPF IPv4 kernel routes in "%s"', router.name) + reffile = os.path.join(CWD, "{}/zebraroute.txt".format(router.name)) + expected = open(reffile).read() + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(compare_show_ip_route_vrf, router.name, expected) + result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) + assertmsg = 'OSPF IPv4 route mismatch in router "{}": {}'.format( + router.name, diff + ) + assert result, assertmsg + + +def test_ospf_json(): + "Test 'show ip ospf json' output for coherency." + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + for rname, router in tgen.routers().items(): + logger.info( + 'Comparing router "%s" "show ip ospf vrf %s-ospf-cust1 json" output', + router.name, + router.name, + ) + expected = { + "{}-ospf-cust1".format(router.name): { + "vrfName": "{}-ospf-cust1".format(router.name), + "routerId": "10.0.255.{}".format(rname[1:]), + "tosRoutesOnly": True, + "rfc2328Conform": True, + "spfScheduleDelayMsecs": 0, + "holdtimeMinMsecs": 50, + "holdtimeMaxMsecs": 5000, + "lsaMinIntervalMsecs": 5000, + "lsaMinArrivalMsecs": 1000, + "writeMultiplier": 20, + "refreshTimerMsecs": 10000, + "asbrRouter": "injectingExternalRoutingInformation", + "attachedAreaCounter": 1, + "areas": {}, + } + } + # Area specific additional checks + if router.name == "r1" or router.name == "r2" or router.name == "r3": + expected["{}-ospf-cust1".format(router.name)]["areas"]["0.0.0.0"] = { + "areaIfActiveCounter": 2, + "areaIfTotalCounter": 2, + "authentication": "authenticationNone", + "backbone": True, + "lsaAsbrNumber": 0, + "lsaNetworkNumber": 1, + "lsaNssaNumber": 0, + "lsaNumber": 4, + "lsaOpaqueAreaNumber": 0, + "lsaOpaqueLinkNumber": 0, + "lsaRouterNumber": 3, + "lsaSummaryNumber": 0, + "nbrFullAdjacentCounter": 2, + } + + test_func = partial( + topotest.router_json_cmp, + router, + "show ip ospf vrf {0}-ospf-cust1 json".format(rname), + expected, + ) + _, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(rname) + assert diff is None, assertmsg + + +def test_ospf_link_down(): + "Test OSPF convergence after a link goes down" + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + # Simulate a network down event on router3 switch3 interface. + router3 = tgen.gears["r3"] + topotest.interface_set_status( + router3, "r3-eth0", ifaceaction=False, vrf_name="r3-ospf-cust1" + ) + + # Expect convergence on all routers + for rname, router in tgen.routers().items(): + logger.info('Waiting for router "%s" convergence after link failure', rname) + # Load expected results from the command + reffile = os.path.join(CWD, "{}/ospfroute_down.txt".format(rname)) + expected = open(reffile).read() + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial( + topotest.router_output_cmp, + router, + "show ip ospf vrf {0}-ospf-cust1 route".format(rname), + expected, + ) + result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) + assertmsg = "OSPF did not converge on {}:\n{}".format(rname, diff) + assert result, assertmsg + + +def test_ospf_link_down_kernel_route(): + "Test OSPF kernel route installation" + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + rlist = tgen.routers().values() + for router in rlist: + logger.info( + 'Checking OSPF IPv4 kernel routes in "%s" after link down', router.name + ) + + str = "{0}-ospf-cust1".format(router.name) + reffile = os.path.join(CWD, "{}/zebraroutedown.txt".format(router.name)) + expected = open(reffile).read() + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(compare_show_ip_route_vrf, router.name, expected) + result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) + assertmsg = ( + 'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format( + router.name, diff + ) + ) + assert result, assertmsg + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step1.json b/tests/topotests/ospf_te_topo1/reference/ted_step1.json index 9624292cc..d6bfca63f 100644 --- a/tests/topotests/ospf_te_topo1/reference/ted_step1.json +++ b/tests/topotests/ospf_te_topo1/reference/ted_step1.json @@ -109,7 +109,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -151,7 +150,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.1", "remote-address":"10.0.1.2", "max-link-bandwidth":176258176.0, @@ -193,7 +191,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.2", "remote-address":"10.0.1.1", "max-link-bandwidth":176258176.0, @@ -235,7 +232,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.1", "remote-address":"10.0.3.2", @@ -278,7 +274,6 @@ "remote-vertex-id":167837443, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.1", "max-link-bandwidth":176258176.0, @@ -320,7 +315,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.1", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step2.json b/tests/topotests/ospf_te_topo1/reference/ted_step2.json index 623d1dc7e..ec30af603 100644 --- a/tests/topotests/ospf_te_topo1/reference/ted_step2.json +++ b/tests/topotests/ospf_te_topo1/reference/ted_step2.json @@ -109,7 +109,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -151,7 +150,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.1", "remote-address":"10.0.3.2", @@ -194,7 +192,6 @@ "remote-vertex-id":167837443, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.1", "max-link-bandwidth":176258176.0, @@ -236,7 +233,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.1", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step3.json b/tests/topotests/ospf_te_topo1/reference/ted_step3.json index 117011a43..853704b4f 100644 --- a/tests/topotests/ospf_te_topo1/reference/ted_step3.json +++ b/tests/topotests/ospf_te_topo1/reference/ted_step3.json @@ -101,7 +101,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -143,7 +142,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.1", "remote-address":"10.0.3.2", @@ -186,7 +184,6 @@ "remote-vertex-id":167837443, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.1", "max-link-bandwidth":176258176.0, @@ -228,7 +225,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.1", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step4.json b/tests/topotests/ospf_te_topo1/reference/ted_step4.json index 5c2dee1e4..0aa57713c 100644 --- a/tests/topotests/ospf_te_topo1/reference/ted_step4.json +++ b/tests/topotests/ospf_te_topo1/reference/ted_step4.json @@ -136,7 +136,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -190,7 +189,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.1", "remote-address":"10.0.3.2", @@ -233,7 +231,6 @@ "remote-vertex-id":167837443, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.1", "max-link-bandwidth":176258176.0, @@ -287,7 +284,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.1", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step5.json b/tests/topotests/ospf_te_topo1/reference/ted_step5.json index 47e747f3c..07637f304 100644 --- a/tests/topotests/ospf_te_topo1/reference/ted_step5.json +++ b/tests/topotests/ospf_te_topo1/reference/ted_step5.json @@ -136,7 +136,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -190,7 +189,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.1", "remote-address":"10.0.1.2", "max-link-bandwidth":176258176.0, @@ -244,7 +242,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.2", "remote-address":"10.0.1.1", "max-link-bandwidth":176258176.0, @@ -298,7 +295,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.1", "remote-address":"10.0.3.2", @@ -341,7 +337,6 @@ "remote-vertex-id":167837443, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.1", "max-link-bandwidth":176258176.0, @@ -395,7 +390,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.1", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step6.json b/tests/topotests/ospf_te_topo1/reference/ted_step6.json index 74bd83fbd..e9eee96ff 100644 --- a/tests/topotests/ospf_te_topo1/reference/ted_step6.json +++ b/tests/topotests/ospf_te_topo1/reference/ted_step6.json @@ -136,7 +136,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -190,7 +189,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.1", "remote-address":"10.0.1.2", "max-link-bandwidth":176258176.0, @@ -244,7 +242,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.2", "remote-address":"10.0.1.1", "max-link-bandwidth":176258176.0, @@ -298,7 +295,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.1", "remote-address":"10.0.3.2", @@ -341,7 +337,6 @@ "remote-vertex-id":167837443, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.1", "max-link-bandwidth":176258176.0, @@ -395,7 +390,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.4.1", "remote-address":"10.0.4.2", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step7.json b/tests/topotests/ospf_te_topo1/reference/ted_step7.json index 1cea9f045..f912ae4a8 100644 --- a/tests/topotests/ospf_te_topo1/reference/ted_step7.json +++ b/tests/topotests/ospf_te_topo1/reference/ted_step7.json @@ -117,7 +117,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.0.2", "remote-address":"10.0.0.1", "max-link-bandwidth":176258176.0, @@ -171,7 +170,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.1", "remote-address":"10.0.1.2", "max-link-bandwidth":176258176.0, @@ -225,7 +223,6 @@ "remote-vertex-id":167837441, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.1.2", "remote-address":"10.0.1.1", "max-link-bandwidth":176258176.0, @@ -279,7 +276,6 @@ "remote-vertex-id":167837442, "metric":10, "edge-attributes":{ - "te-metric":0, "admin-group":32, "local-address":"10.0.3.1", "remote-address":"10.0.3.2", @@ -322,7 +318,6 @@ "remote-vertex-id":167837443, "metric":10, "edge-attributes":{ - "te-metric":0, "local-address":"10.0.3.2", "remote-address":"10.0.3.1", "max-link-bandwidth":176258176.0, diff --git a/tests/topotests/ospf_topo1_vrf/__init__.py b/tests/topotests/ospf_topo1_vrf/__init__.py deleted file mode 100755 index e69de29bb..000000000 diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf deleted file mode 100644 index e1e2bfb99..000000000 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf +++ /dev/null @@ -1,13 +0,0 @@ -! -hostname r1 -password zebra -log file /tmp/r1-ospfd.log -! -router ospf vrf r1-ospf-cust1 - ospf router-id 10.0.255.1 - redistribute kernel - redistribute connected - redistribute static - network 10.0.1.0/24 area 0 - network 10.0.3.0/24 area 0 -! diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt deleted file mode 100644 index d617ab36d..000000000 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt +++ /dev/null @@ -1,18 +0,0 @@ -VRF Name: r1-ospf-cust1 -============ OSPF network routing table ============ -N 10.0.1.0/24 [10] area: 0.0.0.0 - directly attached to r1-eth0 -N 10.0.2.0/24 [20] area: 0.0.0.0 - via 10.0.3.3, r1-eth1 -N 10.0.3.0/24 [10] area: 0.0.0.0 - directly attached to r1-eth1 -N 10.0.10.0/24 [20] area: 0.0.0.0 - via 10.0.3.1, r1-eth1 - -============ OSPF router routing table ============= -R 10.0.255.2 [10] area: 0.0.0.0, ASBR - via 10.0.3.3, r1-eth1 -R 10.0.255.3 [10] area: 0.0.0.0, ASBR - via 10.0.3.1, r1-eth1 - -============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt deleted file mode 100644 index 4f7fd699c..000000000 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt +++ /dev/null @@ -1,14 +0,0 @@ -VRF Name: r1-ospf-cust1 -============ OSPF network routing table ============ -N 10.0.1.0/24 [10] area: 0.0.0.0 - directly attached to r1-eth0 -N 10.0.2.0/24 [20] area: 0.0.0.0 - via 10.0.3.3, r1-eth1 -N 10.0.3.0/24 [10] area: 0.0.0.0 - directly attached to r1-eth1 - -============ OSPF router routing table ============= -R 10.0.255.2 [10] area: 0.0.0.0, ASBR - via 10.0.3.3, r1-eth1 - -============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebra.conf b/tests/topotests/ospf_topo1_vrf/r1/zebra.conf deleted file mode 100644 index 56d7a9764..000000000 --- a/tests/topotests/ospf_topo1_vrf/r1/zebra.conf +++ /dev/null @@ -1,17 +0,0 @@ -! debug zebra kernel -! debug zebra dplane detail -! debug zebra rib -! debug zebra event -! -hostname r1 -password zebra -log file /tmp/r1-zebra.log -! -interface r1-eth0 vrf r1-ospf-cust1 - ip address 10.0.1.1/24 -! -interface r1-eth1 vrf r1-ospf-cust1 - ip address 10.0.3.2/24 -! -ip forwarding -! diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt deleted file mode 100644 index 979af20c5..000000000 --- a/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt +++ /dev/null @@ -1,8 +0,0 @@ -VRF r1-ospf-cust1: -O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX -C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX -O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX -O 10.0.3.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r1-eth1, XX:XX:XX -O>* 10.0.10.0/24 [110/20] via 10.0.3.1, r1-eth1, weight 1, XX:XX:XX - diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt deleted file mode 100644 index ec99fad76..000000000 --- a/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt +++ /dev/null @@ -1,7 +0,0 @@ -VRF r1-ospf-cust1: -O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX -C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX -O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX -O 10.0.3.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r1-eth1, XX:XX:XX - diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf deleted file mode 100644 index c1984276f..000000000 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf +++ /dev/null @@ -1,14 +0,0 @@ -! -hostname r2 -password zebra -log file /tmp/r2-ospfd.log -! -! -router ospf vrf r2-ospf-cust1 - ospf router-id 10.0.255.2 - redistribute kernel - redistribute connected - redistribute static - network 10.0.2.0/24 area 0 - network 10.0.3.0/24 area 0 -! diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt deleted file mode 100644 index 89763ff73..000000000 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt +++ /dev/null @@ -1,18 +0,0 @@ -VRF Name: r2-ospf-cust1 -============ OSPF network routing table ============ -N 10.0.1.0/24 [20] area: 0.0.0.0 - via 10.0.3.2, r2-eth1 -N 10.0.2.0/24 [10] area: 0.0.0.0 - directly attached to r2-eth0 -N 10.0.3.0/24 [10] area: 0.0.0.0 - directly attached to r2-eth1 -N 10.0.10.0/24 [20] area: 0.0.0.0 - via 10.0.3.1, r2-eth1 - -============ OSPF router routing table ============= -R 10.0.255.1 [10] area: 0.0.0.0, ASBR - via 10.0.3.2, r2-eth1 -R 10.0.255.3 [10] area: 0.0.0.0, ASBR - via 10.0.3.1, r2-eth1 - -============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt deleted file mode 100644 index d946f02df..000000000 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt +++ /dev/null @@ -1,14 +0,0 @@ -VRF Name: r2-ospf-cust1 -============ OSPF network routing table ============ -N 10.0.1.0/24 [20] area: 0.0.0.0 - via 10.0.3.2, r2-eth1 -N 10.0.2.0/24 [10] area: 0.0.0.0 - directly attached to r2-eth0 -N 10.0.3.0/24 [10] area: 0.0.0.0 - directly attached to r2-eth1 - -============ OSPF router routing table ============= -R 10.0.255.1 [10] area: 0.0.0.0, ASBR - via 10.0.3.2, r2-eth1 - -============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebra.conf b/tests/topotests/ospf_topo1_vrf/r2/zebra.conf deleted file mode 100644 index 6ff72d126..000000000 --- a/tests/topotests/ospf_topo1_vrf/r2/zebra.conf +++ /dev/null @@ -1,13 +0,0 @@ -! -hostname r2 -password zebra -log file /tmp/r2-zebra.log -! -interface r2-eth0 vrf r2-ospf-cust1 - ip address 10.0.2.1/24 -! -interface r2-eth1 vrf r2-ospf-cust1 - ip address 10.0.3.3/24 -! -ip forwarding -! diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt deleted file mode 100644 index df66e92ab..000000000 --- a/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt +++ /dev/null @@ -1,8 +0,0 @@ -VRF r2-ospf-cust1: -O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX -O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX -C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX -O 10.0.3.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r2-eth1, XX:XX:XX -O>* 10.0.10.0/24 [110/20] via 10.0.3.1, r2-eth1, weight 1, XX:XX:XX - diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt deleted file mode 100644 index 4afc354ca..000000000 --- a/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt +++ /dev/null @@ -1,7 +0,0 @@ -VRF r2-ospf-cust1: -O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX -O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX -C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX -O 10.0.3.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r2-eth1, XX:XX:XX - diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf deleted file mode 100644 index b73d547e3..000000000 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf +++ /dev/null @@ -1,15 +0,0 @@ -! -hostname r3 -password zebra -log file /tmp/r3-ospfd.log -! -! -router ospf vrf r3-ospf-cust1 - ospf router-id 10.0.255.3 - redistribute kernel - redistribute connected - redistribute static - network 10.0.3.0/24 area 0 - network 10.0.10.0/24 area 0 - network 172.16.0.0/24 area 1 -! diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt deleted file mode 100644 index 917702b14..000000000 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt +++ /dev/null @@ -1,18 +0,0 @@ -VRF Name: r3-ospf-cust1 -============ OSPF network routing table ============ -N 10.0.1.0/24 [20] area: 0.0.0.0 - via 10.0.3.2, r3-eth0 -N 10.0.2.0/24 [20] area: 0.0.0.0 - via 10.0.3.3, r3-eth0 -N 10.0.3.0/24 [10] area: 0.0.0.0 - directly attached to r3-eth0 -N 10.0.10.0/24 [10] area: 0.0.0.0 - directly attached to r3-eth1 - -============ OSPF router routing table ============= -R 10.0.255.1 [10] area: 0.0.0.0, ASBR - via 10.0.3.2, r3-eth0 -R 10.0.255.2 [10] area: 0.0.0.0, ASBR - via 10.0.3.3, r3-eth0 - -============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt deleted file mode 100644 index 966185e49..000000000 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt +++ /dev/null @@ -1,8 +0,0 @@ -VRF Name: r3-ospf-cust1 -============ OSPF network routing table ============ -N 10.0.10.0/24 [10] area: 0.0.0.0 - directly attached to r3-eth1 - -============ OSPF router routing table ============= - -============ OSPF external routing table =========== diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebra.conf b/tests/topotests/ospf_topo1_vrf/r3/zebra.conf deleted file mode 100644 index 153415004..000000000 --- a/tests/topotests/ospf_topo1_vrf/r3/zebra.conf +++ /dev/null @@ -1,13 +0,0 @@ -! -hostname r3 -password zebra -log file /tmp/r3-zebra.log -! -interface r3-eth0 vrf r3-ospf-cust1 - ip address 10.0.3.1/24 -! -interface r3-eth1 vrf r3-ospf-cust1 - ip address 10.0.10.1/24 -! -ip forwarding -! diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt deleted file mode 100644 index b435c2ebe..000000000 --- a/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt +++ /dev/null @@ -1,8 +0,0 @@ -VRF r3-ospf-cust1: -O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r3-eth0, weight 1, XX:XX:XX -O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r3-eth0, weight 1, XX:XX:XX -O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r3-eth0, XX:XX:XX -O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX -C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX - diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt deleted file mode 100644 index f30a4be6c..000000000 --- a/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt +++ /dev/null @@ -1,4 +0,0 @@ -VRF r3-ospf-cust1: -O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX -C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX - diff --git a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1-vrf.dot b/tests/topotests/ospf_topo1_vrf/test_ospf_topo1-vrf.dot deleted file mode 100644 index 789fdd7c0..000000000 --- a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1-vrf.dot +++ /dev/null @@ -1,78 +0,0 @@ -## Color coding: -######################### -## Main FRR: #f08080 red -## Switches: #d0e0d0 gray -## RIP: #19e3d9 Cyan -## RIPng: #fcb314 dark yellow -## OSPFv2: #32b835 Green -## OSPFv3: #19e3d9 Cyan -## ISIS IPv4 #fcb314 dark yellow -## ISIS IPv6 #9a81ec purple -## BGP IPv4 #eee3d3 beige -## BGP IPv6 #fdff00 yellow -##### Colors (see http://www.color-hex.com/) - -graph ospf_topo1 { - label="ospf topo1"; - - # Routers - r1 [ - label="r1\nrtr-id 10.0.255.1/32", - shape=doubleoctagon, - fillcolor="#f08080", - style=filled, - ]; - r2 [ - label="r2\nrtr-id 10.0.255.2/32", - shape=doubleoctagon, - fillcolor="#f08080", - style=filled, - ]; - r3 [ - label="r3\nrtr-id 10.0.255.3/32", - shape=doubleoctagon, - fillcolor="#f08080", - style=filled, - ]; - - # Switches - s1 [ - label="s1\n10.0.1.0/24\n2001:db8:1::/64", - shape=oval, - fillcolor="#d0e0d0", - style=filled, - ]; - s2 [ - label="s2\n10.0.2.0/24\n2001:db8:2::/64", - shape=oval, - fillcolor="#d0e0d0", - style=filled, - ]; - s3 [ - label="s3\n10.0.3.0/24\n2001:db8:3::/64", - shape=oval, - fillcolor="#d0e0d0", - style=filled, - ]; - s4 [ - label="s4\n10.0.10.0/24\n2001:db8:100::/64", - shape=oval, - fillcolor="#d0e0d0", - style=filled, - ]; - - # Connections - subgraph cluster0 { - label="area 0" - - r1 -- s1 [label="eth0\n.1\n::1"]; - r1 -- s3 [label="eth1\n.2\n::2"]; - - r2 -- s2 [label="eth0\n.1\n::1"]; - r2 -- s3 [label="eth1\n.3\n::3"]; - - r3 -- s3 [label="eth0\n.1\n::1"]; - r3 -- s4 [label="eth1\n.1\n::1"]; - } - -} diff --git a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.jpg b/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.jpg deleted file mode 100644 index 85f2e52f8..000000000 Binary files a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.jpg and /dev/null differ diff --git a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py b/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py deleted file mode 100644 index 44de61d82..000000000 --- a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py +++ /dev/null @@ -1,324 +0,0 @@ -#!/usr/bin/env python - -# -# test_ospf_topo1.py -# Part of NetDEF Topology Tests -# -# Copyright (c) 2017 by -# Network Device Education Foundation, Inc. ("NetDEF") -# -# Permission to use, copy, modify, and/or distribute this software -# for any purpose with or without fee is hereby granted, provided -# that the above copyright notice and this permission notice appear -# in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# - -""" -test_ospf_topo1.py: Test the FRR OSPF routing daemon. -""" - -import os -import sys -from functools import partial -import pytest - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(CWD, "../")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger - -# Required to instantiate the topology builder class. - -pytestmark = [pytest.mark.ospfd] - - -def build_topo(tgen): - "Build function" - - # Create 3 routers - for routern in range(1, 4): - tgen.add_router("r{}".format(routern)) - - # Create a empty network for router 1 - switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - - # Create a empty network for router 2 - switch = tgen.add_switch("s2") - switch.add_link(tgen.gears["r2"]) - - # Interconect router 1, 2 and 3 - switch = tgen.add_switch("s3") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["r2"]) - switch.add_link(tgen.gears["r3"]) - - # Create empty netowrk for router3 - switch = tgen.add_switch("s4") - switch.add_link(tgen.gears["r3"]) - - -def setup_module(mod): - "Sets up the pytest environment" - tgen = Topogen(build_topo, mod.__name__) - tgen.start_topology() - - router_list = tgen.routers() - - # check for zebra capability - for rname, router in router_list.items(): - if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False: - return pytest.skip( - "Skipping OSPF VRF NETNS feature. VRF NETNS backend not available on FRR" - ) - - if os.system("ip netns list") != 0: - return pytest.skip( - "Skipping OSPF VRF NETNS Test. NETNS not available on System" - ) - - logger.info("Testing with VRF Namespace support") - - for rname, router in router_list.items(): - # create VRF rx-ospf-cust1 and link rx-eth{0,1} to rx-ospf-cust1 - ns = "{}-ospf-cust1".format(rname) - router.net.add_netns(ns) - router.net.set_intf_netns(rname + "-eth0", ns, up=True) - router.net.set_intf_netns(rname + "-eth1", ns, up=True) - - router.load_config( - TopoRouter.RD_ZEBRA, - os.path.join(CWD, "{}/zebra.conf".format(rname)), - "--vrfwnetns", - ) - router.load_config( - TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) - ) - - # Initialize all routers. - tgen.start_router() - for router in router_list.values(): - if router.has_version("<", "4.0"): - tgen.set_error("unsupported version") - - -def teardown_module(mod): - "Teardown the pytest environment" - tgen = get_topogen() - - # Move interfaces out of vrf namespace and delete the namespace - router_list = tgen.routers() - for rname, router in router_list.items(): - tgen.net[rname].reset_intf_netns(rname + "-eth0") - tgen.net[rname].reset_intf_netns(rname + "-eth1") - tgen.net[rname].delete_netns(rname + "-ospf-cust1") - tgen.stop_topology() - - -# Shared test function to validate expected output. -def compare_show_ip_route_vrf(rname, expected): - """ - Calls 'show ip ospf vrf [rname]-ospf-cust1 route' for router `rname` and compare the obtained - result with the expected output. - """ - tgen = get_topogen() - vrf_name = "{0}-ospf-cust1".format(rname) - current = topotest.ip4_route_zebra(tgen.gears[rname], vrf_name) - ret = topotest.difflines( - current, expected, title1="Current output", title2="Expected output" - ) - return ret - - -def test_ospf_convergence(): - "Test OSPF daemon convergence" - tgen = get_topogen() - - if tgen.routers_have_failure(): - pytest.skip("skipped because of router(s) failure") - - for rname, router in tgen.routers().items(): - logger.info('Waiting for router "%s" convergence', rname) - - # Load expected results from the command - reffile = os.path.join(CWD, "{}/ospfroute.txt".format(rname)) - expected = open(reffile).read() - - # Run test function until we get an result. Wait at most 60 seconds. - test_func = partial( - topotest.router_output_cmp, - router, - "show ip ospf vrf {0}-ospf-cust1 route".format(rname), - expected, - ) - result, diff = topotest.run_and_expect(test_func, "", count=160, wait=0.5) - assertmsg = "OSPF did not converge on {}:\n{}".format(rname, diff) - assert result, assertmsg - - -def test_ospf_kernel_route(): - "Test OSPF kernel route installation" - tgen = get_topogen() - - if tgen.routers_have_failure(): - pytest.skip("skipped because of router(s) failure") - - rlist = tgen.routers().values() - for router in rlist: - logger.info('Checking OSPF IPv4 kernel routes in "%s"', router.name) - reffile = os.path.join(CWD, "{}/zebraroute.txt".format(router.name)) - expected = open(reffile).read() - # Run test function until we get an result. Wait at most 60 seconds. - test_func = partial(compare_show_ip_route_vrf, router.name, expected) - result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) - assertmsg = 'OSPF IPv4 route mismatch in router "{}": {}'.format( - router.name, diff - ) - assert result, assertmsg - - -def test_ospf_json(): - "Test 'show ip ospf json' output for coherency." - tgen = get_topogen() - - if tgen.routers_have_failure(): - pytest.skip("skipped because of router(s) failure") - - for rname, router in tgen.routers().items(): - logger.info( - 'Comparing router "%s" "show ip ospf vrf %s-ospf-cust1 json" output', - router.name, - router.name, - ) - expected = { - "{}-ospf-cust1".format(router.name): { - "vrfName": "{}-ospf-cust1".format(router.name), - "routerId": "10.0.255.{}".format(rname[1:]), - "tosRoutesOnly": True, - "rfc2328Conform": True, - "spfScheduleDelayMsecs": 0, - "holdtimeMinMsecs": 50, - "holdtimeMaxMsecs": 5000, - "lsaMinIntervalMsecs": 5000, - "lsaMinArrivalMsecs": 1000, - "writeMultiplier": 20, - "refreshTimerMsecs": 10000, - "asbrRouter": "injectingExternalRoutingInformation", - "attachedAreaCounter": 1, - "areas": {}, - } - } - # Area specific additional checks - if router.name == "r1" or router.name == "r2" or router.name == "r3": - expected["{}-ospf-cust1".format(router.name)]["areas"]["0.0.0.0"] = { - "areaIfActiveCounter": 2, - "areaIfTotalCounter": 2, - "authentication": "authenticationNone", - "backbone": True, - "lsaAsbrNumber": 0, - "lsaNetworkNumber": 1, - "lsaNssaNumber": 0, - "lsaNumber": 4, - "lsaOpaqueAreaNumber": 0, - "lsaOpaqueLinkNumber": 0, - "lsaRouterNumber": 3, - "lsaSummaryNumber": 0, - "nbrFullAdjacentCounter": 2, - } - - test_func = partial( - topotest.router_json_cmp, - router, - "show ip ospf vrf {0}-ospf-cust1 json".format(rname), - expected, - ) - _, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) - assertmsg = '"{}" JSON output mismatches'.format(rname) - assert diff is None, assertmsg - - -def test_ospf_link_down(): - "Test OSPF convergence after a link goes down" - tgen = get_topogen() - - if tgen.routers_have_failure(): - pytest.skip("skipped because of router(s) failure") - - # Simulate a network down event on router3 switch3 interface. - router3 = tgen.gears["r3"] - topotest.interface_set_status( - router3, "r3-eth0", ifaceaction=False, vrf_name="r3-ospf-cust1" - ) - - # Expect convergence on all routers - for rname, router in tgen.routers().items(): - logger.info('Waiting for router "%s" convergence after link failure', rname) - # Load expected results from the command - reffile = os.path.join(CWD, "{}/ospfroute_down.txt".format(rname)) - expected = open(reffile).read() - - # Run test function until we get an result. Wait at most 60 seconds. - test_func = partial( - topotest.router_output_cmp, - router, - "show ip ospf vrf {0}-ospf-cust1 route".format(rname), - expected, - ) - result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) - assertmsg = "OSPF did not converge on {}:\n{}".format(rname, diff) - assert result, assertmsg - - -def test_ospf_link_down_kernel_route(): - "Test OSPF kernel route installation" - tgen = get_topogen() - - if tgen.routers_have_failure(): - pytest.skip("skipped because of router(s) failure") - - rlist = tgen.routers().values() - for router in rlist: - logger.info( - 'Checking OSPF IPv4 kernel routes in "%s" after link down', router.name - ) - - str = "{0}-ospf-cust1".format(router.name) - reffile = os.path.join(CWD, "{}/zebraroutedown.txt".format(router.name)) - expected = open(reffile).read() - # Run test function until we get an result. Wait at most 60 seconds. - test_func = partial(compare_show_ip_route_vrf, router.name, expected) - result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) - assertmsg = ( - 'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format( - router.name, diff - ) - ) - assert result, assertmsg - - -def test_memory_leak(): - "Run the memory leak test and report results." - tgen = get_topogen() - if not tgen.is_memleak_enabled(): - pytest.skip("Memory leak test/report is disabled") - - tgen.report_memory_leaks() - - -if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_topo2/r1/ospf-route.json b/tests/topotests/ospf_topo2/r1/ospf-route.json deleted file mode 100644 index 6beb7e9be..000000000 --- a/tests/topotests/ospf_topo2/r1/ospf-route.json +++ /dev/null @@ -1 +0,0 @@ -{ "10.0.1.1\/32": { "routeType": "N", "cost": 10, "area": "0.0.0.0", "nexthops": [ { "ip": " ", "directly attached to": "r1-eth0" } ] }, "10.0.20.1\/32": { "routeType": "N", "cost": 20, "area": "0.0.0.0", "nexthops": [ { "ip": "10.0.3.2", "via": "r1-eth1" } ] }, "10.0.255.2": { "routeType": "R ", "cost": 10, "area": "0.0.0.0", "routerType": "asbr", "nexthops": [ { "ip": "10.0.3.2", "via": "r1-eth1" } ] } } diff --git a/tests/topotests/ospf_topo2/r1/ospfd.conf b/tests/topotests/ospf_topo2/r1/ospfd.conf deleted file mode 100644 index 65843cbb8..000000000 --- a/tests/topotests/ospf_topo2/r1/ospfd.conf +++ /dev/null @@ -1,13 +0,0 @@ -! -interface r1-eth1 - ip ospf network point-to-point - ip ospf hello-interval 2 - ip ospf dead-interval 10 -! -router ospf - ospf router-id 10.0.255.1 - redistribute kernel - redistribute connected - redistribute static - network 0.0.0.0/0 area 0 -! diff --git a/tests/topotests/ospf_topo2/r1/v4_route.json b/tests/topotests/ospf_topo2/r1/v4_route.json deleted file mode 100644 index 76c639616..000000000 --- a/tests/topotests/ospf_topo2/r1/v4_route.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "10.0.1.1\/32":[ - { - "prefix":"10.0.1.1\/32", - "protocol":"ospf", - "distance":110, - "metric":10, - "table":254, - "nexthops":[ - { - "flags":9, - "ip":"0.0.0.0", - "afi":"ipv4", - "interfaceName":"r1-eth0", - "active":true, - "onLink":true - } - ] - }, - { - "prefix":"10.0.1.1\/32", - "protocol":"connected", - "selected":true, - "destSelected":true, - "distance":0, - "metric":0, - "installed":true, - "table":254, - "nexthops":[ - { - "flags":3, - "fib":true, - "directlyConnected":true, - "interfaceName":"r1-eth0", - "active":true - } - ] - } - ], - "10.0.3.4\/32":[ - { - "prefix":"10.0.3.4\/32", - "protocol":"connected", - "selected":true, - "destSelected":true, - "distance":0, - "metric":0, - "installed":true, - "table":254, - "nexthops":[ - { - "flags":3, - "fib":true, - "directlyConnected":true, - "interfaceName":"r1-eth1", - "active":true - } - ] - } - ], - "10.0.20.1\/32":[ - { - "prefix":"10.0.20.1\/32", - "protocol":"ospf", - "selected":true, - "destSelected":true, - "distance":110, - "metric":20, - "installed":true, - "table":254, - "nexthops":[ - { - "flags":11, - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"r1-eth1", - "active":true, - "onLink":true - } - ] - } - ] -} diff --git a/tests/topotests/ospf_topo2/r1/zebra.conf b/tests/topotests/ospf_topo2/r1/zebra.conf deleted file mode 100644 index d96d9707c..000000000 --- a/tests/topotests/ospf_topo2/r1/zebra.conf +++ /dev/null @@ -1,7 +0,0 @@ -! -interface r1-eth0 - ip address 10.0.1.1/32 -! -interface r1-eth1 - ip address 10.0.3.4/32 -! diff --git a/tests/topotests/ospf_topo2/r2/ospf-route.json b/tests/topotests/ospf_topo2/r2/ospf-route.json deleted file mode 100644 index 3cfd255bf..000000000 --- a/tests/topotests/ospf_topo2/r2/ospf-route.json +++ /dev/null @@ -1 +0,0 @@ -{ "10.0.1.1\/32": { "routeType": "N", "cost": 20, "area": "0.0.0.0", "nexthops": [ { "ip": "10.0.3.4", "via": "r2-eth1" } ] }, "10.0.20.1\/32": { "routeType": "N", "cost": 10, "area": "0.0.0.0", "nexthops": [ { "ip": " ", "directly attached to": "r2-eth0" } ] }, "10.0.255.1": { "routeType": "R ", "cost": 10, "area": "0.0.0.0", "routerType": "asbr", "nexthops": [ { "ip": "10.0.3.4", "via": "r2-eth1" } ] } } diff --git a/tests/topotests/ospf_topo2/r2/ospfd.conf b/tests/topotests/ospf_topo2/r2/ospfd.conf deleted file mode 100644 index b032f1a8a..000000000 --- a/tests/topotests/ospf_topo2/r2/ospfd.conf +++ /dev/null @@ -1,13 +0,0 @@ -! -interface r2-eth1 - ip ospf network point-to-point - ip ospf hello-interval 2 - ip ospf dead-interval 10 -! -router ospf - ospf router-id 10.0.255.2 - redistribute kernel - redistribute connected - redistribute static - network 0.0.0.0/0 area 0 -! diff --git a/tests/topotests/ospf_topo2/r2/v4_route.json b/tests/topotests/ospf_topo2/r2/v4_route.json deleted file mode 100644 index 163853638..000000000 --- a/tests/topotests/ospf_topo2/r2/v4_route.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "10.0.1.1\/32":[ - { - "prefix":"10.0.1.1\/32", - "protocol":"ospf", - "selected":true, - "destSelected":true, - "distance":110, - "metric":20, - "installed":true, - "table":254, - "nexthops":[ - { - "flags":11, - "fib":true, - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"r2-eth1", - "active":true, - "onLink":true - } - ] - } - ], - "10.0.3.2\/32":[ - { - "prefix":"10.0.3.2\/32", - "protocol":"connected", - "selected":true, - "destSelected":true, - "distance":0, - "metric":0, - "installed":true, - "table":254, - "nexthops":[ - { - "flags":3, - "fib":true, - "directlyConnected":true, - "interfaceName":"r2-eth1", - "active":true - } - ] - } - ], - "10.0.20.1\/32":[ - { - "prefix":"10.0.20.1\/32", - "protocol":"ospf", - "distance":110, - "metric":10, - "table":254, - "nexthops":[ - { - "flags":9, - "ip":"0.0.0.0", - "afi":"ipv4", - "interfaceName":"r2-eth0", - "active":true, - "onLink":true - } - ] - }, - { - "prefix":"10.0.20.1\/32", - "protocol":"connected", - "selected":true, - "destSelected":true, - "distance":0, - "metric":0, - "installed":true, - "table":254, - "nexthops":[ - { - "flags":3, - "fib":true, - "directlyConnected":true, - "interfaceName":"r2-eth0", - "active":true - } - ] - } - ] -} diff --git a/tests/topotests/ospf_topo2/r2/zebra.conf b/tests/topotests/ospf_topo2/r2/zebra.conf deleted file mode 100644 index f9dd2c447..000000000 --- a/tests/topotests/ospf_topo2/r2/zebra.conf +++ /dev/null @@ -1,7 +0,0 @@ -! -interface r2-eth0 - ip address 10.0.20.1/32 -! -interface r2-eth1 - ip address 10.0.3.2/32 -! diff --git a/tests/topotests/ospf_topo2/test_ospf_topo2.py b/tests/topotests/ospf_topo2/test_ospf_topo2.py deleted file mode 100644 index 1ad62ff18..000000000 --- a/tests/topotests/ospf_topo2/test_ospf_topo2.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python - -# -# test_ospf_topo2.py -# -# Copyright (c) 2019 by -# Cumulus Networks, Inc -# Donald Sharp -# -# Permission to use, copy, modify, and/or distribute this software -# for any purpose with or without fee is hereby granted, provided -# that the above copyright notice and this permission notice appear -# in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# - -""" -test_ospf_topo2.py: Test the OSPF unnumbered. -""" - -import os -import sys -from functools import partial -import pytest -import json - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(CWD, "../")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger - -# Required to instantiate the topology builder class. - -pytestmark = [pytest.mark.ospfd] - - -CWD = os.path.dirname(os.path.realpath(__file__)) - - -def build_topo(tgen): - "Build function" - - # Create 4 routers - for routern in range(1, 3): - tgen.add_router("r{}".format(routern)) - - # Create a empty network for router 1 - switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - - # Create a empty network for router 2 - switch = tgen.add_switch("s2") - switch.add_link(tgen.gears["r2"]) - - # Interconect router 1, 2 - switch = tgen.add_switch("s3") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["r2"]) - - -def setup_module(mod): - "Sets up the pytest environment" - tgen = Topogen(build_topo, mod.__name__) - tgen.start_topology() - - router_list = tgen.routers() - for rname, router in router_list.items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) - ) - - # What is this? OSPF Unnumbered depends on the rp_filter - # being set appropriately( HA! ) - # Effectively we are putting different /32's on the interface - # the multicast packet delivery is somewhat controlled by - # the rp_filter. Setting it to '0' allows the OS to pass - # up the mcast packet not destined for the local routers - # network. - topotest.sysctl_assure(tgen.net["r1"], "net.ipv4.conf.r1-eth1.rp_filter", 0) - topotest.sysctl_assure(tgen.net["r1"], "net.ipv4.conf.all.rp_filter", 0) - topotest.sysctl_assure(tgen.net["r2"], "net.ipv4.conf.r2-eth1.rp_filter", 0) - topotest.sysctl_assure(tgen.net["r2"], "net.ipv4.conf.all.rp_filter", 0) - - # Initialize all routers. - tgen.start_router() - # tgen.mininet_cli() - - -def teardown_module(mod): - "Teardown the pytest environment" - tgen = get_topogen() - tgen.stop_topology() - - -def test_ospf_convergence(): - "Test OSPF daemon convergence and that we have received the ospf routes" - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip("skipped because of router(s) failure") - - for router, rnode in tgen.routers().items(): - logger.info('Waiting for router "%s" convergence', router) - - json_file = "{}/{}/ospf-route.json".format(CWD, router) - expected = json.loads(open(json_file).read()) - - test_func = partial( - topotest.router_json_cmp, rnode, "show ip ospf route json", expected - ) - _, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5) - assertmsg = '"{}" JSON output mismatches'.format(router) - assert result is None, assertmsg - # tgen.mininet_cli() - - -def test_ospf_kernel_route(): - "Test OSPF kernel route installation and we have the onlink success" - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip("skipped because of router(s) failure") - - rlist = tgen.routers().values() - for router in rlist: - logger.info('Checking OSPF IPv4 kernel routes in "%s"', router.name) - - json_file = "{}/{}/v4_route.json".format(CWD, router.name) - expected = json.loads(open(json_file).read()) - - test_func = partial( - topotest.router_json_cmp, router, "show ip route json", expected - ) - _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) - assertmsg = '"{}" JSON output mistmatches'.format(router) - assert result is None, assertmsg - # tgen.mininet_cli() - - -def test_memory_leak(): - "Run the memory leak test and report results." - tgen = get_topogen() - if not tgen.is_memleak_enabled(): - pytest.skip("Memory leak test/report is disabled") - - tgen.report_memory_leaks() - - -if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_unnumbered/r1/ospf-route.json b/tests/topotests/ospf_unnumbered/r1/ospf-route.json new file mode 100644 index 000000000..6beb7e9be --- /dev/null +++ b/tests/topotests/ospf_unnumbered/r1/ospf-route.json @@ -0,0 +1 @@ +{ "10.0.1.1\/32": { "routeType": "N", "cost": 10, "area": "0.0.0.0", "nexthops": [ { "ip": " ", "directly attached to": "r1-eth0" } ] }, "10.0.20.1\/32": { "routeType": "N", "cost": 20, "area": "0.0.0.0", "nexthops": [ { "ip": "10.0.3.2", "via": "r1-eth1" } ] }, "10.0.255.2": { "routeType": "R ", "cost": 10, "area": "0.0.0.0", "routerType": "asbr", "nexthops": [ { "ip": "10.0.3.2", "via": "r1-eth1" } ] } } diff --git a/tests/topotests/ospf_unnumbered/r1/ospfd.conf b/tests/topotests/ospf_unnumbered/r1/ospfd.conf new file mode 100644 index 000000000..65843cbb8 --- /dev/null +++ b/tests/topotests/ospf_unnumbered/r1/ospfd.conf @@ -0,0 +1,13 @@ +! +interface r1-eth1 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +router ospf + ospf router-id 10.0.255.1 + redistribute kernel + redistribute connected + redistribute static + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ospf_unnumbered/r1/v4_route.json b/tests/topotests/ospf_unnumbered/r1/v4_route.json new file mode 100644 index 000000000..76c639616 --- /dev/null +++ b/tests/topotests/ospf_unnumbered/r1/v4_route.json @@ -0,0 +1,84 @@ +{ + "10.0.1.1\/32":[ + { + "prefix":"10.0.1.1\/32", + "protocol":"ospf", + "distance":110, + "metric":10, + "table":254, + "nexthops":[ + { + "flags":9, + "ip":"0.0.0.0", + "afi":"ipv4", + "interfaceName":"r1-eth0", + "active":true, + "onLink":true + } + ] + }, + { + "prefix":"10.0.1.1\/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "10.0.3.4\/32":[ + { + "prefix":"10.0.3.4\/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "10.0.20.1\/32":[ + { + "prefix":"10.0.20.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "table":254, + "nexthops":[ + { + "flags":11, + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"r1-eth1", + "active":true, + "onLink":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf_unnumbered/r1/zebra.conf b/tests/topotests/ospf_unnumbered/r1/zebra.conf new file mode 100644 index 000000000..d96d9707c --- /dev/null +++ b/tests/topotests/ospf_unnumbered/r1/zebra.conf @@ -0,0 +1,7 @@ +! +interface r1-eth0 + ip address 10.0.1.1/32 +! +interface r1-eth1 + ip address 10.0.3.4/32 +! diff --git a/tests/topotests/ospf_unnumbered/r2/ospf-route.json b/tests/topotests/ospf_unnumbered/r2/ospf-route.json new file mode 100644 index 000000000..3cfd255bf --- /dev/null +++ b/tests/topotests/ospf_unnumbered/r2/ospf-route.json @@ -0,0 +1 @@ +{ "10.0.1.1\/32": { "routeType": "N", "cost": 20, "area": "0.0.0.0", "nexthops": [ { "ip": "10.0.3.4", "via": "r2-eth1" } ] }, "10.0.20.1\/32": { "routeType": "N", "cost": 10, "area": "0.0.0.0", "nexthops": [ { "ip": " ", "directly attached to": "r2-eth0" } ] }, "10.0.255.1": { "routeType": "R ", "cost": 10, "area": "0.0.0.0", "routerType": "asbr", "nexthops": [ { "ip": "10.0.3.4", "via": "r2-eth1" } ] } } diff --git a/tests/topotests/ospf_unnumbered/r2/ospfd.conf b/tests/topotests/ospf_unnumbered/r2/ospfd.conf new file mode 100644 index 000000000..b032f1a8a --- /dev/null +++ b/tests/topotests/ospf_unnumbered/r2/ospfd.conf @@ -0,0 +1,13 @@ +! +interface r2-eth1 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +router ospf + ospf router-id 10.0.255.2 + redistribute kernel + redistribute connected + redistribute static + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ospf_unnumbered/r2/v4_route.json b/tests/topotests/ospf_unnumbered/r2/v4_route.json new file mode 100644 index 000000000..163853638 --- /dev/null +++ b/tests/topotests/ospf_unnumbered/r2/v4_route.json @@ -0,0 +1,84 @@ +{ + "10.0.1.1\/32":[ + { + "prefix":"10.0.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "table":254, + "nexthops":[ + { + "flags":11, + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"r2-eth1", + "active":true, + "onLink":true + } + ] + } + ], + "10.0.3.2\/32":[ + { + "prefix":"10.0.3.2\/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "10.0.20.1\/32":[ + { + "prefix":"10.0.20.1\/32", + "protocol":"ospf", + "distance":110, + "metric":10, + "table":254, + "nexthops":[ + { + "flags":9, + "ip":"0.0.0.0", + "afi":"ipv4", + "interfaceName":"r2-eth0", + "active":true, + "onLink":true + } + ] + }, + { + "prefix":"10.0.20.1\/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "table":254, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf_unnumbered/r2/zebra.conf b/tests/topotests/ospf_unnumbered/r2/zebra.conf new file mode 100644 index 000000000..f9dd2c447 --- /dev/null +++ b/tests/topotests/ospf_unnumbered/r2/zebra.conf @@ -0,0 +1,7 @@ +! +interface r2-eth0 + ip address 10.0.20.1/32 +! +interface r2-eth1 + ip address 10.0.3.2/32 +! diff --git a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py new file mode 100644 index 000000000..a9640adca --- /dev/null +++ b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python + +# +# test_ospf_unnumbered.py +# +# Copyright (c) 2019 by +# Cumulus Networks, Inc +# Donald Sharp +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_ospf_unnumbered.py: Test the OSPF unnumbered. +""" + +import os +import sys +from functools import partial +import pytest +import json + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +pytestmark = [pytest.mark.ospfd] + + +CWD = os.path.dirname(os.path.realpath(__file__)) + + +def build_topo(tgen): + "Build function" + + # Create 4 routers + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + # Create a empty network for router 1 + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + # Create a empty network for router 2 + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + + # Interconect router 1, 2 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + + # What is this? OSPF Unnumbered depends on the rp_filter + # being set appropriately( HA! ) + # Effectively we are putting different /32's on the interface + # the multicast packet delivery is somewhat controlled by + # the rp_filter. Setting it to '0' allows the OS to pass + # up the mcast packet not destined for the local routers + # network. + topotest.sysctl_assure(tgen.net["r1"], "net.ipv4.conf.r1-eth1.rp_filter", 0) + topotest.sysctl_assure(tgen.net["r1"], "net.ipv4.conf.all.rp_filter", 0) + topotest.sysctl_assure(tgen.net["r2"], "net.ipv4.conf.r2-eth1.rp_filter", 0) + topotest.sysctl_assure(tgen.net["r2"], "net.ipv4.conf.all.rp_filter", 0) + + # Initialize all routers. + tgen.start_router() + # tgen.mininet_cli() + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_ospf_convergence(): + "Test OSPF daemon convergence and that we have received the ospf routes" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + for router, rnode in tgen.routers().items(): + logger.info('Waiting for router "%s" convergence', router) + + json_file = "{}/{}/ospf-route.json".format(CWD, router) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, rnode, "show ip ospf route json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_ospf_kernel_route(): + "Test OSPF kernel route installation and we have the onlink success" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + rlist = tgen.routers().values() + for router in rlist: + logger.info('Checking OSPF IPv4 kernel routes in "%s"', router.name) + + json_file = "{}/{}/v4_route.json".format(CWD, router.name) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, router, "show ip route json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"{}" JSON output mistmatches'.format(router) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_authentication.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_authentication.json new file mode 100644 index 000000000..08ff253b7 --- /dev/null +++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_authentication.json @@ -0,0 +1,169 @@ +{ + "address_types": [ + "ipv6" + ], + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r0": { + "links": { + "r1": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r2": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r3": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "100.1.1.0", + "neighbors": { + "r1": {}, + "r2": {}, + "r3": {} + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "r1": { + "links": { + "r0": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r2": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r3": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "100.1.1.1", + "neighbors": { + "r0": {}, + "r2": {}, + "r3": {} + } + } + }, + "r2": { + "links": { + "r0": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r1": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r3": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "100.1.1.2", + "neighbors": { + "r1": {}, + "r0": {}, + "r3": {} + } + } + }, + "r3": { + "links": { + "r0": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r1": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r2": { + "ipv6": "auto", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "100.1.1.3", + "neighbors": { + "r0": {}, + "r1": {}, + "r2": {} + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py new file mode 100644 index 000000000..baa0071f9 --- /dev/null +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py @@ -0,0 +1,1446 @@ +#!/usr/bin/python + +# +# Copyright (c) 2021 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. +# ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + + +"""OSPF Basic Functionality Automation.""" +import os +import sys +import time +import pytest +from time import sleep +from copy import deepcopy +import json +from lib.topotest import frr_unicode + +pytestmark = pytest.mark.ospf6d + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + step, + shutdown_bringup_interface, + topo_daemons, +) +from lib.topolog import logger +from lib.topojson import build_topo_from_json, build_config_from_json +from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface, clear_ospf +from ipaddress import IPv4Address + +# Global variables +topo = None +# Reading the data from JSON File for topology creation +jsonFile = "{}/ospfv3_authentication.json".format(CWD) +try: + with open(jsonFile, "r") as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) +""" +TOPOOLOGY = + Please view in a fixed-width font such as Courier. + +---+ A1 +---+ + +R1 +------------+R2 | + +-+-+- +--++ + | -- -- | + | -- A0 -- | + A0| ---- | + | ---- | A2 + | -- -- | + | -- -- | + +-+-+- +-+-+ + +R0 +-------------+R3 | + +---+ A3 +---+ + +TESTCASES = +1. OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 manual key configuration. +2. OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 manual key configuration. +3. OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 keychain configuration. +4. OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 keychain configuration. + + """ + +def setup_module(mod): + """ + Sets up the pytest environment + * `mod`: module name + """ + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/ospfv3_single_area.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # get list of daemons needs to be started for this suite. + daemons = topo_daemons(tgen, topo) + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen, daemons) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + ospf6_covergence = verify_ospf6_neighbor(tgen, topo) + assert ospf6_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf6_covergence + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment. + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +# ################################## +# Test cases start here. +# ################################## + +def test_ospf6_auth_trailer_tc1_md5(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 manual key configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Disable authentication on R2 " + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + "del_action": True + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Again On R2 enable ospf6 on interface with message-digest auth") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + + +def test_ospf6_auth_trailer_tc2_sha256(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 manual key configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Disable authentication on R2 " + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + "del_action": True + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Again On R2 enable ospf6 on interface with message-digest auth") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc3_keychain_md5(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 keychain configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm md5""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm md5""" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Disable authentication on R2 " + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + "del_action": True + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Again On R2 enable ospf6 on interface with message-digest auth") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc4_keychain_sha256(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 keychain configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm hmac-sha-256""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm hmac-sha-256""" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Disable authentication on R2 " + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + "del_action": True + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry") + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Again On R2 enable ospf6 on interface with message-digest auth") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 using" + " show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step("Shut no shut interface on R1") + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r2" + step( + "Verify that the neighbour is not FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + dut = "r1" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "Verify that the neighbour is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 manual key configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer wrong key" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6-missmatch", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is not FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + step("Verify that the neighbour is FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer correct key" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "md5", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc6_sha256_mismatch(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 manual key configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 with on R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer wrong key" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6-missmatch", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 with on R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer wrong key" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using MD5 keychain configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm md5""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm md5""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth-missmatch + key 10 + key-string ospf6-missmatch + cryptographic-algorithm md5""" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer with wrong keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth-missmatch", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer with correct keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request): + """ + OSPFv3 Authentication Trailer - Verify ospfv3 authentication trailer + using HMAC-SHA-256 keychain configuration. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + router1.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm hmac-sha-256""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth + key 10 + key-string ospf6 + cryptographic-algorithm hmac-sha-256""" + ) + + router2.vtysh_cmd( + """configure terminal + key chain auth-missmatch + key 10 + key-string ospf6-missmatch + cryptographic-algorithm hmac-sha-256""" + ) + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer wrong keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth-missmatch", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer correct keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc9_keychain_not_configured(request): + """ + OSPFv3 Neighborship without Authentication Trailer - + Verify ospfv3 neighborship when no authentication trailer is configured. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + step( + "Configure ospf6 between R1 and R2, enable ospf6 auth on R1 interface " + "connected to R2 with auth trailer" + ) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + r1_ospf6_auth = { + "r1": { + "links": { + "r2": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r1" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + step( + "Configure ospf6 between R1 and R2, enable ospf6 on R2 interface " + "connected to R1 with auth trailer non existing keychain" + ) + + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "keychain": "auth", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify that the neighbour is not FULL between R1 and R2.") + # wait for dead time expiry. + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=3 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +def test_ospf6_auth_trailer_tc10_no_auth_trailer(request): + """ + OSPFv3 Neighborship without Authentication Trailer - + Verify ospfv3 neighborship when no authentication trailer is configured. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + step( + "Verify that the neighbour is FULL between R1 and R2 " + "using show ipv6 ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error:" " {}".format( + tc_name, ospf6_covergence + ) + + write_test_footer(tc_name) + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/zebra_nht_resolution/r1/sharpd.conf b/tests/topotests/zebra_nht_resolution/r1/sharpd.conf new file mode 100644 index 000000000..e69de29bb diff --git a/tests/topotests/zebra_nht_resolution/r1/zebra.conf b/tests/topotests/zebra_nht_resolution/r1/zebra.conf new file mode 100644 index 000000000..6c35c5c4b --- /dev/null +++ b/tests/topotests/zebra_nht_resolution/r1/zebra.conf @@ -0,0 +1,5 @@ +hostname r1 +! +interface r1-eth0 + ip address 192.168.120.1/24 +! diff --git a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py new file mode 100644 index 000000000..9a8f7cc1f --- /dev/null +++ b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2022 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test is indended for validating zebra NH resolution logic +""" + +import os +import sys +import pytest + +from lib.common_config import ( + start_topology, + verify_rib, + verify_ip_nht, + step, + create_static_routes, +) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +pytestmark = [pytest.mark.sharpd] + +#GLOBAL VARIABLES +NH1 = "2.2.2.32" + +def build_topo(tgen): + tgen.add_router("r1") + + switch = tgen.add_switch("sw1") + switch.add_link(tgen.gears["r1"]) + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + router_list = tgen.routers() + for rname, router in tgen.routers().items(): + router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))) + router.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) + ) + tgen.start_router() + +def teardown_module(_mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_verify_zebra_nh_resolution(request): + tgen = get_topogen() + tc_name = request.node.name + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + logger.info("Starting Zebra NH resolution testcase") + r1 = tgen.gears["r1"] + + step("Configure static route") + input_dict_1 = { + "r1": { + "static_routes": [ + {"network": "2.2.2.0/24", "next_hop": "r1-eth0"} + ] + } + } + + result = create_static_routes(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify static routes in RIB of R1") + input_dict_2 = { + "r1": { + "static_routes": [ + {"network": "2.2.2.0/24"} + ] + } + } + + dut = "r1" + result = verify_rib(tgen, "ipv4", dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result) + + step("Set the connected flag on the NH tracking entry") + r1.vtysh_cmd("sharp watch nexthop 2.2.2.32 connected") + + step("Verify that NH 2.2.2.32 gets resolved over static route") + input_dict_nh = { + "r1": { + NH1: { + "Address": "2.2.2.0/24", + "resolvedVia": "static", + "nexthops": {"nexthop1": {"Interfcae": "r1-eth0"}}, + } + } + } + result = verify_ip_nht(tgen, input_dict_nh) + assert result is True, "Testcase {} : Failed \n" + "Error: Nexthop is missing in RIB".format( + tc_name, result) + + step("Add a .32/32 route with the NH as itself") + r1.vtysh_cmd("sharp install routes 2.2.2.32 nexthop 2.2.2.32 1") + + step("Verify that the installation of .32/32 has no effect on the NHT") + input_dict_nh = { + "r1": { + NH1: { + "Address": "2.2.2.0/24", + "resolvedVia": "static", + "nexthops": {"nexthop1": {"Interface": "r1-eth0"}}, + } + } + } + result = verify_ip_nht(tgen, input_dict_nh) + assert result is True, "Testcase {} : Failed \n" + "Error: Nexthop became unresolved".format( + tc_name, result) + + step("Add a .31/32 route with the NH as 2.2.2.32" + "to verify the NH Resolution behaviour") + r1.vtysh_cmd("sharp install routes 2.2.2.31 nexthop 2.2.2.32 1") + + step("Verify that NH 2.2.2.2/32 doesn't become unresolved") + input_dict_nh = { + "r1": { + NH1: { + "Address": "2.2.2.0/24", + "resolvedVia": "static", + "nexthops": {"nexthop1": {"Interface": "r1-eth0"}}, + } + } + } + result = verify_ip_nht(tgen, input_dict_nh) + assert result is True, "Testcase {} : Failed \n" + "Error: Nexthop became unresolved".format( + tc_name, result) + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index e223eb274..46e0625d8 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -78,6 +78,7 @@ show debugging hashtable show running-config show thread cpu show thread poll +show thread timers show daemons show version CMD_LIST_END diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 2be865351..2b76c43f7 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -517,9 +517,11 @@ class Config(object): "address-family ": { "vni ": {}, }, - "vnc ": {}, + "vnc defaults": {}, + "vnc nve-group ": {}, + "vnc l2-group ": {}, "vrf-policy ": {}, - "bmp ": {}, + "bmp targets ": {}, "segment-routing srv6": {}, }, "router rip": {}, diff --git a/tools/frrinit.sh.in b/tools/frrinit.sh.in index 539ab7d81..e41f2706e 100644 --- a/tools/frrinit.sh.in +++ b/tools/frrinit.sh.in @@ -77,6 +77,7 @@ reload) # systemd doesn't set WATCHDOG_USEC for reload commands. watchfrr_pidfile="$V_PATH/watchfrr.pid" watchfrr_pid="`cat \"$watchfrr_pidfile\"`" + watchfrr_cmdline="`strings /proc/$watchfrr_pid/cmdline`" if [ -d "/proc/$watchfrr_pid" ]; then wdt="`tr '\0' '\n' < /proc/$watchfrr_pid/environ | grep '^WATCHDOG_USEC='`" wdt="${wdt#WATCHDOG_USEC=}" @@ -86,11 +87,24 @@ reload) # restart watchfrr to pick up added daemons. # NB: This will NOT cause the other daemons to be restarted. - daemon_list daemons - watchfrr_options="$watchfrr_options $daemons" + daemon_list enabled_daemons disabled_daemons + watchfrr_options="$watchfrr_options $enabled_daemons" daemon_stop watchfrr && \ daemon_start watchfrr + # If we disable an arbitrary daemon and do reload, + # disabled daemon is still running and we should stop it. + for daemon in $disabled_daemons; do + if grep -q "$daemon" <<< "$watchfrr_cmdline"; then + daemon_stop "$daemon" & + pids="$pids $!" + fi + done + + for pid in $pids; do + wait "$pid" + done + # make systemd not kill watchfrr after ExecReload completes # 3 goats were sacrificed to restore sanity after coding this watchfrr_pid="`cat \"$watchfrr_pidfile\"`" diff --git a/tools/release_notes.py b/tools/release_notes.py index 7481cc18c..973215b57 100755 --- a/tools/release_notes.py +++ b/tools/release_notes.py @@ -10,6 +10,7 @@ import os import getopt import subprocess + def run(cmd): proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) rv = proc.communicate("")[0].decode("UTF-8") @@ -45,7 +46,7 @@ def main(argv): tag = run(["git", "describe", "--abbrev=0"]).strip("\n") chnglog = run( - ["git", "log", "--no-merges", "--pretty=format:'%s%d'", tag + ".." + branch] + ["git", "log", "--no-merges", "--pretty=format:'%s'", tag + ".." + branch] ) chnglog = chnglog.split("\n") diff --git a/tools/releasedate.py b/tools/releasedate.py index 37780501c..3df1ea48f 100644 --- a/tools/releasedate.py +++ b/tools/releasedate.py @@ -36,21 +36,23 @@ if __name__ == "__main__": print("Last release was (scheduled) on %s" % last.isoformat()) rel = upcoming.pop(0) - freeze, rc1, rc2 = rel - w2 * 3, rel - w2 * 2, rel - w2 + freeze, stabilization, rc = rel - w2 * 3, rel - w2 * 2, rel - w2 if now == rel: print("It's release day! 🎉") - elif now >= rc2: + elif now >= rc: print( - "%d days until release! (rc2 since %s)" - % ((rel - now).days, rc2.isoformat()) + "%d days until release! (RC since %s)" % ((rel - now).days, rc.isoformat()) + ) + elif now >= stabilization: + print( + "%d days until RC. (stabilization branch created since %s)" + % ((rc - now).days, stabilization.isoformat()) ) - elif now >= rc1: - print("%d days until rc2. (rc1 since %s)" % ((rc2 - now).days, rc1.isoformat())) elif now >= freeze: print( - "%d days until rc1, master is frozen since %s" - % ((rc1 - now).days, freeze.isoformat()) + "%d days until stabilization branch, master is frozen since %s" + % ((stabilization - now).days, freeze.isoformat()) ) else: print( diff --git a/vrrpd/Makefile b/vrrpd/Makefile index 027c6ee1f..0abb1a638 100644 --- a/vrrpd/Makefile +++ b/vrrpd/Makefile @@ -1,7 +1,7 @@ all: ALWAYS - @$(MAKE) -s -C .. vrrp/vrrp + @$(MAKE) -s -C .. vrrpd/vrrpd %: ALWAYS - @$(MAKE) -s -C .. vrrp/$@ + @$(MAKE) -s -C .. vrrpd/$@ Makefile: #nothing diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 5c34c66df..dae1e4894 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -405,7 +405,7 @@ static bool vrrp_has_ip(struct vrrp_vrouter *vr, struct ipaddr *ip) struct ipaddr *iter; for (ALL_LIST_ELEMENTS_RO(r->addrs, ln, iter)) - if (!memcmp(&iter->ip, &ip->ip, IPADDRSZ(ip))) + if (!ipaddr_cmp(iter, ip)) return true; return false; @@ -484,7 +484,7 @@ int vrrp_del_ip(struct vrrp_vrouter *vr, struct ipaddr *ip) return 0; for (ALL_LIST_ELEMENTS(r->addrs, ln, nn, iter)) - if (!memcmp(&iter->ip, &ip->ip, IPADDRSZ(ip))) + if (!ipaddr_cmp(iter, ip)) list_delete_node(r->addrs, ln); /* @@ -681,8 +681,8 @@ struct vrrp_vrouter *vrrp_lookup(const struct interface *ifp, uint8_t vrid) /* Forward decls */ static void vrrp_change_state(struct vrrp_router *r, int to); -static int vrrp_adver_timer_expire(struct thread *thread); -static int vrrp_master_down_timer_expire(struct thread *thread); +static void vrrp_adver_timer_expire(struct thread *thread); +static void vrrp_master_down_timer_expire(struct thread *thread); /* * Finds the first connected address of the appropriate family on a VRRP @@ -903,7 +903,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, switch (r->fsm.state) { case VRRP_STATE_MASTER: - addrcmp = memcmp(&src->ip, &r->src.ip, IPADDRSZ(src)); + addrcmp = ipaddr_cmp(src, &r->src); if (pkt->hdr.priority == 0) { vrrp_send_advertisement(r); @@ -983,7 +983,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, /* * Read and process next IPvX datagram. */ -static int vrrp_read(struct thread *thread) +static void vrrp_read(struct thread *thread) { struct vrrp_router *r = thread->arg; @@ -1045,8 +1045,6 @@ done: if (resched) thread_add_read(master, vrrp_read, r, r->sock_rx, &r->t_read); - - return 0; } /* @@ -1480,7 +1478,7 @@ static void vrrp_change_state(struct vrrp_router *r, int to) /* * Called when Adver_Timer expires. */ -static int vrrp_adver_timer_expire(struct thread *thread) +static void vrrp_adver_timer_expire(struct thread *thread) { struct vrrp_router *r = thread->arg; @@ -1503,14 +1501,12 @@ static int vrrp_adver_timer_expire(struct thread *thread) r->vr->vrid, family2str(r->family), vrrp_state_names[r->fsm.state]); } - - return 0; } /* * Called when Master_Down_Timer expires. */ -static int vrrp_master_down_timer_expire(struct thread *thread) +static void vrrp_master_down_timer_expire(struct thread *thread) { struct vrrp_router *r = thread->arg; @@ -1522,8 +1518,6 @@ static int vrrp_master_down_timer_expire(struct thread *thread) r->vr->advertisement_interval * CS2MS, &r->t_adver_timer); vrrp_change_state(r, VRRP_STATE_MASTER); - - return 0; } /* diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 334bd7aff..d940e03e1 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -91,7 +91,7 @@ sub scan_file { # $protocol is VTYSH_PROTO format for redirection of user input if ($file =~ /lib\/keychain\.c$/) { - $protocol = "VTYSH_RIPD|VTYSH_EIGRPD"; + $protocol = "VTYSH_RIPD|VTYSH_EIGRPD|VTYSH_OSPF6D"; } elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) { $protocol = "VTYSH_RMAP"; @@ -118,7 +118,7 @@ sub scan_file { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD"; } else { - $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD"; + $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD"; } } elsif ($file =~ /lib\/if_rmap\.c$/) { @@ -143,6 +143,10 @@ sub scan_file { elsif ($fabricd) { $protocol = "VTYSH_FABRICD"; } +# Enable VTYSH_PIM6D once pim6_cmd.c is merged +# elsif ($file =~ /pimd\/pim6_cmd\.c$/) { +# $protocol = "VTYSH_PIM6D"; +# } else { ($protocol) = ($file =~ /^(?:.*\/)?([a-z0-9]+)\/[a-zA-Z0-9_\-]+\.c$/); $protocol = "VTYSH_" . uc $protocol; diff --git a/vtysh/subdir.am b/vtysh/subdir.am index 5f7d85494..624361645 100644 --- a/vtysh/subdir.am +++ b/vtysh/subdir.am @@ -7,6 +7,10 @@ bin_PROGRAMS += vtysh/vtysh man1 += $(MANBUILD)/vtysh.1 endif +clippy_scan += \ + vtysh/vtysh.c \ + # end + vtysh_vtysh_SOURCES = \ vtysh/vtysh_main.c \ vtysh/vtysh.c \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 8e95aaa47..ed1f1fb5b 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -40,6 +40,7 @@ #include "linklist.h" #include "command.h" #include "memory.h" +#include "network.h" #include "filter.h" #include "vtysh/vtysh.h" #include "vtysh/vtysh_daemons.h" @@ -69,8 +70,15 @@ struct vtysh_client { int flag; char path[MAXPATHLEN]; struct vtysh_client *next; + + struct thread *log_reader; + int log_fd; + uint32_t lost_msgs; }; +static bool stderr_tty; +static bool stderr_stdout_same; + /* Some utility functions for working on vtysh-specific vty tasks */ static FILE *vty_open_pager(struct vty *vty) @@ -126,26 +134,27 @@ static void vtysh_pager_envdef(bool fallback) /* --- */ struct vtysh_client vtysh_client[] = { - {.fd = -1, .name = "zebra", .flag = VTYSH_ZEBRA, .next = NULL}, - {.fd = -1, .name = "ripd", .flag = VTYSH_RIPD, .next = NULL}, - {.fd = -1, .name = "ripngd", .flag = VTYSH_RIPNGD, .next = NULL}, - {.fd = -1, .name = "ospfd", .flag = VTYSH_OSPFD, .next = NULL}, - {.fd = -1, .name = "ospf6d", .flag = VTYSH_OSPF6D, .next = NULL}, - {.fd = -1, .name = "ldpd", .flag = VTYSH_LDPD, .next = NULL}, - {.fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .next = NULL}, - {.fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .next = NULL}, - {.fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .next = NULL}, - {.fd = -1, .name = "nhrpd", .flag = VTYSH_NHRPD, .next = NULL}, - {.fd = -1, .name = "eigrpd", .flag = VTYSH_EIGRPD, .next = NULL}, - {.fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .next = NULL}, - {.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL}, - {.fd = -1, .name = "fabricd", .flag = VTYSH_FABRICD, .next = NULL}, - {.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL}, - {.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .next = NULL}, - {.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL}, - {.fd = -1, .name = "bfdd", .flag = VTYSH_BFDD, .next = NULL}, - {.fd = -1, .name = "vrrpd", .flag = VTYSH_VRRPD, .next = NULL}, - {.fd = -1, .name = "pathd", .flag = VTYSH_PATHD, .next = NULL}, + {.name = "zebra", .flag = VTYSH_ZEBRA}, + {.name = "ripd", .flag = VTYSH_RIPD}, + {.name = "ripngd", .flag = VTYSH_RIPNGD}, + {.name = "ospfd", .flag = VTYSH_OSPFD}, + {.name = "ospf6d", .flag = VTYSH_OSPF6D}, + {.name = "ldpd", .flag = VTYSH_LDPD}, + {.name = "bgpd", .flag = VTYSH_BGPD}, + {.name = "isisd", .flag = VTYSH_ISISD}, + {.name = "pimd", .flag = VTYSH_PIMD}, + {.name = "nhrpd", .flag = VTYSH_NHRPD}, + {.name = "eigrpd", .flag = VTYSH_EIGRPD}, + {.name = "babeld", .flag = VTYSH_BABELD}, + {.name = "sharpd", .flag = VTYSH_SHARPD}, + {.name = "fabricd", .flag = VTYSH_FABRICD}, + {.name = "watchfrr", .flag = VTYSH_WATCHFRR}, + {.name = "pbrd", .flag = VTYSH_PBRD}, + {.name = "staticd", .flag = VTYSH_STATICD}, + {.name = "bfdd", .flag = VTYSH_BFDD}, + {.name = "vrrpd", .flag = VTYSH_VRRPD}, + {.name = "pathd", .flag = VTYSH_PATHD}, + {.name = "pim6d", .flag = VTYSH_PIM6D}, }; /* Searches for client by name, returns index */ @@ -181,6 +190,53 @@ static void vclient_close(struct vtysh_client *vclient) } } +static ssize_t vtysh_client_receive(struct vtysh_client *vclient, char *buf, + size_t bufsz, int *pass_fd) +{ + struct iovec iov[1] = { + { + .iov_base = buf, + .iov_len = bufsz, + }, + }; + union { + uint8_t buf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr align; + } u; + struct msghdr mh = { + .msg_iov = iov, + .msg_iovlen = array_size(iov), + .msg_control = u.buf, + .msg_controllen = sizeof(u.buf), + }; + struct cmsghdr *cmh = CMSG_FIRSTHDR(&mh); + ssize_t ret; + + cmh->cmsg_level = SOL_SOCKET; + cmh->cmsg_type = SCM_RIGHTS; + cmh->cmsg_len = CMSG_LEN(sizeof(int)); + memset(CMSG_DATA(cmh), -1, sizeof(int)); + + do { + ret = recvmsg(vclient->fd, &mh, 0); + if (ret >= 0 || (errno != EINTR && errno != EAGAIN)) + break; + } while (true); + + if (cmh->cmsg_len == CMSG_LEN(sizeof(int))) { + int fd; + + memcpy(&fd, CMSG_DATA(cmh), sizeof(int)); + if (fd != -1) { + if (pass_fd) + *pass_fd = fd; + else + close(fd); + } + } + return ret; +} + /* * Send a CLI command to a client and read the response. * @@ -204,7 +260,8 @@ static void vclient_close(struct vtysh_client *vclient) * a status code */ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, - void (*callback)(void *, const char *), void *cbarg) + void (*callback)(void *, const char *), void *cbarg, + int *pass_fd) { int ret; char stackbuf[4096]; @@ -238,8 +295,10 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, bufvalid = buf; do { - ssize_t nread = - read(vclient->fd, bufvalid, buf + bufsz - bufvalid - 1); + ssize_t nread; + + nread = vtysh_client_receive( + vclient, bufvalid, buf + bufsz - bufvalid - 1, pass_fd); if (nread < 0 && (errno == EINTR || errno == EAGAIN)) continue; @@ -381,7 +440,7 @@ static int vtysh_client_run_all(struct vtysh_client *head_client, int correct_instance = 0, wrong_instance = 0; for (client = head_client; client; client = client->next) { - rc = vtysh_client_run(client, line, callback, cbarg); + rc = vtysh_client_run(client, line, callback, cbarg, NULL); if (rc == CMD_NOT_MY_INSTANCE) { wrong_instance++; continue; @@ -818,7 +877,7 @@ int vtysh_mark_file(const char *filename) return 0; } -/* Configration make from file. */ +/* Configuration make from file. */ int vtysh_config_from_file(struct vty *vty, FILE *fp) { int ret; @@ -1578,6 +1637,8 @@ static int vtysh_end(void) return CMD_SUCCESS; } +#include "vtysh/vtysh_clippy.c" + DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end", "End current mode and change to enable mode\n") { @@ -1586,7 +1647,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end", DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd, "srv6", - "Segment-Routing SRv6 configration\n") + "Segment-Routing SRv6 configuration\n") { vty->node = SRV6_NODE; return CMD_SUCCESS; @@ -1594,7 +1655,7 @@ DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd, DEFUNSH(VTYSH_ZEBRA, srv6_locators, srv6_locators_cmd, "locators", - "Segment-Routing SRv6 locators configration\n") + "Segment-Routing SRv6 locators configuration\n") { vty->node = SRV6_LOCS_NODE; return CMD_SUCCESS; @@ -2714,6 +2775,16 @@ static int show_one_daemon(struct vty *vty, struct cmd_token **argv, int argc, return ret; } +DEFUN (vtysh_show_thread_timer, + vtysh_show_thread_timer_cmd, + "show thread timers", + SHOW_STR + "Thread information\n" + "Show all timers and how long they have in the system\n") +{ + return show_per_daemon(vty, argv, argc, "Thread timers for %s:\n"); +} + DEFUN (vtysh_show_poll, vtysh_show_poll_cmd, "show thread poll", @@ -3460,6 +3531,292 @@ DEFUN (vtysh_show_daemons, return CMD_SUCCESS; } +struct visual_prio { + /* 4 characters for nice alignment */ + const char *label; + + int c256_background; + int c256_formatarg; +}; + +/* clang-format off */ +struct visual_prio visual_prios[] = { + [LOG_EMERG] = { + .label = "\e[31;1mEMRG", + .c256_background = 53, + .c256_formatarg = 225, + }, + [LOG_ALERT] = { + .label = "\e[31;1mALRT", + .c256_background = 53, + .c256_formatarg = 225, + }, + [LOG_CRIT] = { + .label = "\e[31;1mCRIT", + .c256_background = 53, + .c256_formatarg = 225, + }, + [LOG_ERR] = { + .label = "\e[38;5;202mERR!", + .c256_background = 52, + .c256_formatarg = 224, + }, + [LOG_WARNING] = { + .label = "\e[38;5;222mWARN", + .c256_background = 58, + .c256_formatarg = 230, + }, + [LOG_NOTICE] = { + .label = "NTFY", + .c256_background = 234, + .c256_formatarg = 195, + }, + [LOG_INFO] = { + .label = "\e[38;5;192mINFO", + .c256_background = 236, + .c256_formatarg = 195, + }, + [LOG_DEBUG] = { + .label = "\e[38;5;116mDEBG", + .c256_background = 238, + .c256_formatarg = 195, + }, +}; +/* clang-format on */ + +static void vtysh_log_print(struct vtysh_client *vclient, + struct zlog_live_hdr *hdr, const char *text) +{ + size_t textlen = hdr->textlen, textpos = 0; + time_t ts = hdr->ts_sec; + struct visual_prio *vis; + struct tm tm; + char ts_buf[32]; + + if (hdr->prio >= array_size(visual_prios)) + vis = &visual_prios[LOG_CRIT]; + else + vis = &visual_prios[hdr->prio]; + + localtime_r(&ts, &tm); + strftime(ts_buf, sizeof(ts_buf), "%Y-%m-%d %H:%M:%S", &tm); + + if (!stderr_tty) { + const char *label = vis->label + strlen(vis->label) - 4; + + fprintf(stderr, "%s.%03u [%s] %s: %.*s\n", ts_buf, + hdr->ts_nsec / 1000000U, label, vclient->name, + (int)textlen, text); + return; + } + + fprintf(stderr, + "\e[48;5;%dm\e[38;5;247m%s.%03u [%s\e[38;5;247m] \e[38;5;255m%s\e[38;5;247m: \e[38;5;251m", + vis->c256_background, ts_buf, hdr->ts_nsec / 1000000U, + vis->label, vclient->name); + + for (size_t fmtpos = 0; fmtpos < hdr->n_argpos; fmtpos++) { + struct fmt_outpos *fmt = &hdr->argpos[fmtpos]; + + if (fmt->off_start < textpos || fmt->off_end < fmt->off_start || + fmt->off_end > textlen) + continue; + + while (fmt->off_end > fmt->off_start && + text[fmt->off_end - 1] == ' ') + fmt->off_end--; + + fprintf(stderr, "%.*s\e[38;5;%dm%.*s\e[38;5;251m", + (int)(fmt->off_start - textpos), text + textpos, + vis->c256_formatarg, + (int)(fmt->off_end - fmt->off_start), + text + fmt->off_start); + textpos = fmt->off_end; + } + fprintf(stderr, "%.*s\033[K\033[m\n", (int)(textlen - textpos), + text + textpos); +} + +static void vtysh_log_read(struct thread *thread) +{ + struct vtysh_client *vclient = THREAD_ARG(thread); + struct { + struct zlog_live_hdr hdr; + char text[4096]; + } buf; + const char *text; + ssize_t ret; + + thread_add_read(master, vtysh_log_read, vclient, vclient->log_fd, + &vclient->log_reader); + + ret = recv(vclient->log_fd, &buf, sizeof(buf), 0); + + if (ret < 0 && ERRNO_IO_RETRY(errno)) + return; + + if (stderr_stdout_same) { +#ifdef HAVE_RL_CLEAR_VISIBLE_LINE + rl_clear_visible_line(); +#else + puts("\r"); +#endif + fflush(stdout); + } + + if (ret <= 0) { + struct timespec ts; + + buf.text[0] = '\0'; /* coverity */ + + if (ret != 0) + snprintfrr(buf.text, sizeof(buf.text), + "log monitor connection error: %m"); + else + snprintfrr( + buf.text, sizeof(buf.text), + "log monitor connection closed unexpectedly"); + buf.hdr.textlen = strlen(buf.text); + + THREAD_OFF(vclient->log_reader); + close(vclient->log_fd); + vclient->log_fd = -1; + + clock_gettime(CLOCK_REALTIME, &ts); + buf.hdr.ts_sec = ts.tv_sec; + buf.hdr.ts_nsec = ts.tv_nsec; + buf.hdr.prio = LOG_ERR; + buf.hdr.flags = 0; + buf.hdr.texthdrlen = 0; + buf.hdr.n_argpos = 0; + } else { + int32_t lost_msgs = buf.hdr.lost_msgs - vclient->lost_msgs; + + if (lost_msgs > 0) { + vclient->lost_msgs = buf.hdr.lost_msgs; + fprintf(stderr, + "%d log messages from %s lost (vtysh reading too slowly)\n", + lost_msgs, vclient->name); + } + } + + text = buf.text + sizeof(buf.hdr.argpos[0]) * buf.hdr.n_argpos; + vtysh_log_print(vclient, &buf.hdr, text); + + if (stderr_stdout_same) + rl_forced_update_display(); + + return; +} + +#ifdef CLIPPY +/* clippy/clidef can't process the DEFPY below without some value for this */ +#define DAEMONS_LIST "daemon" +#endif + +DEFPY (vtysh_terminal_monitor, + vtysh_terminal_monitor_cmd, + "terminal monitor ["DAEMONS_LIST"]$daemon", + "Set terminal line parameters\n" + "Receive log messages to active VTY session\n" + DAEMONS_STR) +{ + static const char line[] = "terminal monitor\n"; + int ret_all = CMD_SUCCESS, ret, fd; + size_t i, ok = 0; + + for (i = 0; i < array_size(vtysh_client); i++) { + struct vtysh_client *vclient = &vtysh_client[i]; + + if (daemon && strcmp(vclient->name, daemon)) + continue; + + for (; vclient; vclient = vclient->next) { + if (vclient->log_fd != -1) { + vty_out(vty, "%% %s: already monitoring logs\n", + vclient->name); + ok++; + continue; + } + + fd = -1; + ret = vtysh_client_run(vclient, line, NULL, NULL, &fd); + if (fd != -1) { + set_nonblocking(fd); + vclient->log_fd = fd; + thread_add_read(master, vtysh_log_read, vclient, + vclient->log_fd, + &vclient->log_reader); + } + if (ret != CMD_SUCCESS) { + vty_out(vty, "%% failed to enable logs on %s\n", + vclient->name); + ret_all = CMD_WARNING; + } else + ok++; + } + } + + if (!ok && ret_all == CMD_SUCCESS) { + vty_out(vty, + "%% command had no effect, relevant daemons not connected?\n"); + ret_all = CMD_WARNING; + } + return ret_all; +} + +DEFPY (no_vtysh_terminal_monitor, + no_vtysh_terminal_monitor_cmd, + "no terminal monitor ["DAEMONS_LIST"]$daemon", + NO_STR + "Set terminal line parameters\n" + "Receive log messages to active VTY session\n" + DAEMONS_STR) +{ + static const char line[] = "no terminal monitor\n"; + int ret_all = CMD_SUCCESS, ret; + size_t i, ok = 0; + + for (i = 0; i < array_size(vtysh_client); i++) { + struct vtysh_client *vclient = &vtysh_client[i]; + + if (daemon && strcmp(vclient->name, daemon)) + continue; + + for (; vclient; vclient = vclient->next) { + /* run this even if log_fd == -1, in case something + * got desync'd + */ + ret = vtysh_client_run(vclient, line, NULL, NULL, NULL); + if (ret != CMD_SUCCESS) { + vty_out(vty, + "%% failed to disable logs on %s\n", + vclient->name); + ret_all = CMD_WARNING; + } else + ok++; + + /* with this being a datagram socket, we can't expect + * a close notification... + */ + if (vclient->log_fd != -1) { + THREAD_OFF(vclient->log_reader); + + close(vclient->log_fd); + vclient->log_fd = -1; + } + } + } + + if (!ok && ret_all == CMD_SUCCESS) { + vty_out(vty, + "%% command had no effect, relevant daemons not connected?\n"); + ret_all = CMD_WARNING; + } + return ret_all; +} + + /* Execute command in child process. */ static void execute_command(const char *command, int argc, const char *arg1, const char *arg2) @@ -3967,8 +4324,21 @@ void vtysh_uninit(void) void vtysh_init_vty(void) { + struct stat st_out, st_err; + cmd_defer_tree(true); + for (size_t i = 0; i < array_size(vtysh_client); i++) { + vtysh_client[i].fd = -1; + vtysh_client[i].log_fd = -1; + } + + stderr_tty = isatty(STDERR_FILENO); + + if (fstat(STDOUT_FILENO, &st_out) || fstat(STDERR_FILENO, &st_err) || + (st_out.st_dev == st_err.st_dev && st_out.st_ino == st_err.st_ino)) + stderr_stdout_same = true; + /* Make vty structure. */ vty = vty_new(); vty->type = VTY_SHELL; @@ -4462,6 +4832,9 @@ void vtysh_init_vty(void) install_element(VIEW_NODE, &vtysh_terminal_no_length_cmd); install_element(VIEW_NODE, &vtysh_show_daemons_cmd); + install_element(VIEW_NODE, &vtysh_terminal_monitor_cmd); + install_element(VIEW_NODE, &no_vtysh_terminal_monitor_cmd); + install_element(VIEW_NODE, &vtysh_ping_cmd); install_element(VIEW_NODE, &vtysh_ping_ip_cmd); install_element(VIEW_NODE, &vtysh_traceroute_cmd); @@ -4507,6 +4880,7 @@ void vtysh_init_vty(void) install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd); install_element(VIEW_NODE, &vtysh_show_thread_cmd); install_element(VIEW_NODE, &vtysh_show_poll_cmd); + install_element(VIEW_NODE, &vtysh_show_thread_timer_cmd); /* Logging */ install_element(VIEW_NODE, &vtysh_show_logging_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index e56d482da..6053955be 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -24,6 +24,10 @@ #include "memory.h" DECLARE_MGROUP(MVTYSH); +struct thread_master; + +extern struct thread_master *master; + #define VTYSH_ZEBRA 0x00001 #define VTYSH_RIPD 0x00002 #define VTYSH_RIPNGD 0x00004 @@ -44,6 +48,7 @@ DECLARE_MGROUP(MVTYSH); #define VTYSH_FABRICD 0x20000 #define VTYSH_VRRPD 0x40000 #define VTYSH_PATHD 0x80000 +#define VTYSH_PIM6D 0x100000 #define VTYSH_WAS_ACTIVE (-2) @@ -52,12 +57,12 @@ DECLARE_MGROUP(MVTYSH); /* watchfrr is not in ALL since library CLI functions should not be * run on it (logging & co. should stay in a fixed/frozen config, and * things like prefix lists are not even initialised) */ -#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD -#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA -#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD -#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD +#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD +#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA +#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_EIGRPD|VTYSH_FABRICD +#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD #define VTYSH_VRF VTYSH_INTERFACE|VTYSH_STATICD -#define VTYSH_KEYS VTYSH_RIPD|VTYSH_EIGRPD +#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D /* Daemons who can process nexthop-group configs */ #define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD #define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD @@ -72,6 +77,7 @@ extern enum vtysh_write_integrated vtysh_write_integrated; extern char frr_config[]; extern char vtydir[]; +extern bool vtysh_loop_exited; void vtysh_init_vty(void); void vtysh_uninit(void); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 76956574c..04eb47fee 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -84,9 +84,6 @@ static sigjmp_buf jmpbuf; /* Flag for avoid recursive siglongjmp() call. */ static int jmpflag = 0; -/* A static variable for holding the line. */ -static char *line_read; - /* Master of threads. */ struct thread_master *master; @@ -208,23 +205,22 @@ struct option longopts[] = { {"timestamp", no_argument, NULL, 't'}, {0}}; -/* Read a string, and return a pointer to it. Returns NULL on EOF. */ -static char *vtysh_rl_gets(void) +bool vtysh_loop_exited; + +static void vtysh_rl_callback(char *line_read) { HIST_ENTRY *last; - /* If the buffer has already been allocated, return the memory - * to the free pool. */ - if (line_read) { - free(line_read); - line_read = NULL; - } - /* Get a line from the user. Change prompt according to node. XXX. */ - line_read = readline(vtysh_prompt()); + rl_callback_handler_remove(); + + if (!line_read) { + vtysh_loop_exited = true; + return; + } /* If the line has any text in it, save it on the history. But only if * last command in history isn't the same one. */ - if (line_read && *line_read) { + if (*line_read) { using_history(); last = previous_history(); if (!last || strcmp(last->line, line_read) != 0) { @@ -233,7 +229,39 @@ static char *vtysh_rl_gets(void) } } - return (line_read); + vtysh_execute(line_read); + + if (!vtysh_loop_exited) + rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback); +} + +static struct thread *vtysh_rl_read_thread; + +static void vtysh_rl_read(struct thread *thread) +{ + thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO, + &vtysh_rl_read_thread); + rl_callback_read_char(); +} + +/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +static void vtysh_rl_run(void) +{ + struct thread thread; + + master = thread_master_create(NULL); + + rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback); + thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO, + &vtysh_rl_read_thread); + + while (!vtysh_loop_exited && thread_fetch(master, &thread)) + thread_call(&thread); + + if (!vtysh_loop_exited) + rl_callback_handler_remove(); + + thread_master_free(master); } static void log_it(const char *line) @@ -458,7 +486,6 @@ int main(int argc, char **argv, char **env) } /* Initialize user input buffer. */ - line_read = NULL; setlinebuf(stdout); /* Signal and others. */ @@ -587,7 +614,7 @@ int main(int argc, char **argv, char **env) * Setup history file for use by both -c and regular input * If we can't find the home directory, then don't store * the history information. - * VTYSH_HISTFILE is prefered over command line + * VTYSH_HISTFILE is preferred over command line * argument (-H/--histfile). */ if (getenv("VTYSH_HISTFILE")) { @@ -730,8 +757,7 @@ int main(int argc, char **argv, char **env) jmpflag = 1; /* Main command loop. */ - while (vtysh_rl_gets()) - vtysh_execute(line_read); + vtysh_rl_run(); vtysh_uninit(); diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index 0d9734a75..4f50da380 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -201,7 +201,7 @@ static const struct option longopts[] = { {NULL, 0, NULL, 0}}; static int try_connect(struct daemon *dmn); -static int wakeup_send_echo(struct thread *t_wakeup); +static void wakeup_send_echo(struct thread *t_wakeup); static void try_restart(struct daemon *dmn); static void phase_check(void); static void restart_done(struct daemon *dmn); @@ -350,7 +350,7 @@ static struct timeval *time_elapsed(struct timeval *result, return result; } -static int restart_kill(struct thread *t_kill) +static void restart_kill(struct thread *t_kill) { struct restart_info *restart = THREAD_ARG(t_kill); struct timeval delay; @@ -364,7 +364,6 @@ static int restart_kill(struct thread *t_kill) restart->kills++; thread_add_timer(master, restart_kill, restart, gs.restart_timeout, &restart->t_kill); - return 0; } static struct restart_info *find_child(pid_t child) @@ -546,7 +545,7 @@ static int run_job(struct restart_info *restart, const char *cmdtype, FUZZY(gs.period), &(DMN)->t_wakeup); \ } while (0); -static int wakeup_down(struct thread *t_wakeup) +static void wakeup_down(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); @@ -555,10 +554,9 @@ static int wakeup_down(struct thread *t_wakeup) SET_WAKEUP_DOWN(dmn); if ((dmn->connect_tries > 1) && (dmn->state != DAEMON_UP)) try_restart(dmn); - return 0; } -static int wakeup_init(struct thread *t_wakeup) +static void wakeup_init(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); @@ -570,7 +568,6 @@ static int wakeup_init(struct thread *t_wakeup) dmn->state = DAEMON_DOWN; } phase_check(); - return 0; } static void restart_done(struct daemon *dmn) @@ -609,7 +606,7 @@ static void daemon_down(struct daemon *dmn, const char *why) phase_check(); } -static int handle_read(struct thread *t_read) +static void handle_read(struct thread *t_read) { struct daemon *dmn = THREAD_ARG(t_read); static const char resp[sizeof(PING_TOKEN) + 4] = PING_TOKEN "\n"; @@ -624,16 +621,16 @@ static int handle_read(struct thread *t_read) if (ERRNO_IO_RETRY(errno)) { /* Pretend it never happened. */ SET_READ_HANDLER(dmn); - return 0; + return; } snprintf(why, sizeof(why), "unexpected read error: %s", safe_strerror(errno)); daemon_down(dmn, why); - return 0; + return; } if (rc == 0) { daemon_down(dmn, "read returned EOF"); - return 0; + return; } if (!dmn->echo_sent.tv_sec) { char why[sizeof(buf) + 100]; @@ -641,7 +638,7 @@ static int handle_read(struct thread *t_read) "unexpected read returns %d bytes: %.*s", (int)rc, (int)rc, buf); daemon_down(dmn, why); - return 0; + return; } /* We are expecting an echo response: is there any chance that the @@ -653,7 +650,7 @@ static int handle_read(struct thread *t_read) "read returned bad echo response of %d bytes (expecting %u): %.*s", (int)rc, (unsigned int)sizeof(resp), (int)rc, buf); daemon_down(dmn, why); - return 0; + return; } time_elapsed(&delay, &dmn->echo_sent); @@ -677,8 +674,6 @@ static int handle_read(struct thread *t_read) SET_READ_HANDLER(dmn); thread_cancel(&dmn->t_wakeup); SET_WAKEUP_ECHO(dmn); - - return 0; } /* @@ -732,7 +727,7 @@ static void daemon_up(struct daemon *dmn, const char *why) phase_check(); } -static int check_connect(struct thread *t_write) +static void check_connect(struct thread *t_write) { struct daemon *dmn = THREAD_ARG(t_write); int sockerr; @@ -745,7 +740,7 @@ static int check_connect(struct thread *t_write) safe_strerror(errno)); daemon_down(dmn, "getsockopt failed checking connection success"); - return 0; + return; } if ((reslen == sizeof(sockerr)) && sockerr) { char why[100]; @@ -754,14 +749,13 @@ static int check_connect(struct thread *t_write) "getsockopt reports that connection attempt failed: %s", safe_strerror(sockerr)); daemon_down(dmn, why); - return 0; + return; } daemon_up(dmn, "delayed connect succeeded"); - return 0; } -static int wakeup_connect_hanging(struct thread *t_wakeup) +static void wakeup_connect_hanging(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); char why[100]; @@ -770,7 +764,6 @@ static int wakeup_connect_hanging(struct thread *t_wakeup) snprintf(why, sizeof(why), "connection attempt timed out after %ld seconds", gs.timeout); daemon_down(dmn, why); - return 0; } /* Making connection to protocol daemon. */ @@ -846,14 +839,13 @@ static int try_connect(struct daemon *dmn) return 1; } -static int phase_hanging(struct thread *t_hanging) +static void phase_hanging(struct thread *t_hanging) { gs.t_phase_hanging = NULL; flog_err(EC_WATCHFRR_CONNECTION, "Phase [%s] hanging for %ld seconds, aborting phased restart", phase_str[gs.phase], PHASE_TIMEOUT); gs.phase = PHASE_NONE; - return 0; } static void set_phase(restart_phase_t new_phase) @@ -971,7 +963,7 @@ static void try_restart(struct daemon *dmn) run_job(&gs.restart, "restart", gs.restart_command, 0, 1); } -static int wakeup_unresponsive(struct thread *t_wakeup) +static void wakeup_unresponsive(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); @@ -984,26 +976,24 @@ static int wakeup_unresponsive(struct thread *t_wakeup) SET_WAKEUP_UNRESPONSIVE(dmn); try_restart(dmn); } - return 0; } -static int wakeup_no_answer(struct thread *t_wakeup) +static void wakeup_no_answer(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; dmn->state = DAEMON_UNRESPONSIVE; if (dmn->ignore_timeout) - return 0; + return; flog_err(EC_WATCHFRR_CONNECTION, "%s state -> unresponsive : no response yet to ping sent %ld seconds ago", dmn->name, gs.timeout); SET_WAKEUP_UNRESPONSIVE(dmn); try_restart(dmn); - return 0; } -static int wakeup_send_echo(struct thread *t_wakeup) +static void wakeup_send_echo(struct thread *t_wakeup) { static const char echocmd[] = "echo " PING_TOKEN; ssize_t rc; @@ -1022,7 +1012,6 @@ static int wakeup_send_echo(struct thread *t_wakeup) thread_add_timer(master, wakeup_no_answer, dmn, gs.timeout, &dmn->t_wakeup); } - return 0; } bool check_all_up(void) @@ -1099,10 +1088,9 @@ static char *translate_blanks(const char *cmd, const char *blankstr) return res; } -static int startup_timeout(struct thread *t_wakeup) +static void startup_timeout(struct thread *t_wakeup) { daemon_send_ready(1); - return 0; } #ifdef GNU_LINUX diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index 9bd26043a..74008bc07 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -532,6 +532,16 @@ module frr-bgp-route-map { description "Prefix route"; } + enum "ead" { + value 3; + description + "Ethernet Auto-Discovery route"; + } + enum "es" { + value 4; + description + "Ethernet Segment route"; + } } } } diff --git a/yang/frr-pathd.yang b/yang/frr-pathd.yang index 30f9875a6..5beda769c 100644 --- a/yang/frr-pathd.yang +++ b/yang/frr-pathd.yang @@ -414,7 +414,7 @@ module frr-pathd { container objective-function { presence "If the candidate has an objective function constraint"; description - "Define objective function constraint as a list of prefered functions"; + "Define objective function constraint as a list of preferred functions"; leaf required { type boolean; default "true"; diff --git a/yang/frr-route-types.yang b/yang/frr-route-types.yang index aeb52a652..ffc671c99 100644 --- a/yang/frr-route-types.yang +++ b/yang/frr-route-types.yang @@ -162,9 +162,7 @@ module frr-route-types { typedef ipv6-multicast-group-prefix { type inet:ipv6-prefix { pattern - '(((FF|ff)[0-9a-fA-F]{2}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(/((1[6-9])|([2-9][0-9])|(1[0-1][0-9])|(12[0-8])))'; - pattern - '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)(/.+)'; + '(([fF]{2}[0-9a-fA-F]{2}):).*'; } description "This type represents an IPv6 multicast group prefix, diff --git a/zebra/connected.c b/zebra/connected.c index b261ddb79..4f4e8be34 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -290,10 +290,12 @@ void connected_up(struct interface *ifp, struct connected *ifc) } rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0); + flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, + false); rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0); + flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, + false); /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c index 0e0ccccb6..260ba30b3 100644 --- a/zebra/debug_nl.c +++ b/zebra/debug_nl.c @@ -20,10 +20,12 @@ #include +#include #include #include #include #include +#include #include #include @@ -89,6 +91,11 @@ const char *nlmsg_type2str(uint16_t type) case RTM_GETNEXTHOP: return "GETNEXTHOP"; + case RTM_NEWNETCONF: + return "RTM_NEWNETCONF"; + case RTM_DELNETCONF: + return "RTM_DELNETCONF"; + default: return "UNKNOWN"; } @@ -576,6 +583,117 @@ const char *nhm_rta2str(int type) } } +const char *frh_rta2str(int type) +{ + switch (type) { + case FRA_DST: + return "DST"; + case FRA_SRC: + return "SRC"; + case FRA_IIFNAME: + return "IIFNAME"; + case FRA_GOTO: + return "GOTO"; + case FRA_UNUSED2: + return "UNUSED2"; + case FRA_PRIORITY: + return "PRIORITY"; + case FRA_UNUSED3: + return "UNUSED3"; + case FRA_UNUSED4: + return "UNUSED4"; + case FRA_UNUSED5: + return "UNUSED5"; + case FRA_FWMARK: + return "FWMARK"; + case FRA_FLOW: + return "FLOW"; + case FRA_TUN_ID: + return "TUN_ID"; + case FRA_SUPPRESS_IFGROUP: + return "SUPPRESS_IFGROUP"; + case FRA_SUPPRESS_PREFIXLEN: + return "SUPPRESS_PREFIXLEN"; + case FRA_TABLE: + return "TABLE"; + case FRA_FWMASK: + return "FWMASK"; + case FRA_OIFNAME: + return "OIFNAME"; + case FRA_PAD: + return "PAD"; + case FRA_L3MDEV: + return "L3MDEV"; + case FRA_UID_RANGE: + return "UID_RANGE"; + case FRA_PROTOCOL: + return "PROTOCOL"; + case FRA_IP_PROTO: + return "IP_PROTO"; + case FRA_SPORT_RANGE: + return "SPORT_RANGE"; + case FRA_DPORT_RANGE: + return "DPORT_RANGE"; + default: + return "UNKNOWN"; + } +} + +const char *frh_action2str(uint8_t action) +{ + switch (action) { + case FR_ACT_TO_TBL: + return "TO_TBL"; + case FR_ACT_GOTO: + return "GOTO"; + case FR_ACT_NOP: + return "NOP"; + case FR_ACT_RES3: + return "RES3"; + case FR_ACT_RES4: + return "RES4"; + case FR_ACT_BLACKHOLE: + return "BLACKHOLE"; + case FR_ACT_UNREACHABLE: + return "UNREACHABLE"; + case FR_ACT_PROHIBIT: + return "PROHIBIT"; + default: + return "UNKNOWN"; + } +} + +static const char *ncm_rta2str(int type) +{ + switch (type) { + case NETCONFA_UNSPEC: + return "UNSPEC"; + case NETCONFA_IFINDEX: + return "IFINDEX"; + case NETCONFA_FORWARDING: + return "FORWARDING"; + case NETCONFA_RP_FILTER: + return "RP_FILTER"; + case NETCONFA_MC_FORWARDING: + return "MCAST"; + case NETCONFA_PROXY_NEIGH: + return "PROXY_NEIGH"; + case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN: + return "IGNORE_LINKDOWN"; + case NETCONFA_INPUT: + return "MPLS"; + case NETCONFA_BC_FORWARDING: + return "BCAST"; + default: + return "UNKNOWN"; + } +} + +static void dump_on_off(uint32_t ival, const char *prefix) +{ + zlog_debug("%s%s", prefix, (ival != 0) ? "on" : "off"); +} + static inline void flag_write(int flags, int flag, const char *flagstr, char *buf, size_t buflen) { @@ -1037,6 +1155,7 @@ static void nlnh_dump(struct nhmsg *nhm, size_t msglen) struct nexthop_grp *nhgrp; rta = RTM_NHA(nhm); + next_rta: /* Check the header for valid length and for outbound access. */ if (RTA_OK(rta, msglen) == 0) @@ -1110,6 +1229,157 @@ next_rta: goto next_rta; } +static void nlrule_dump(struct fib_rule_hdr *frh, size_t msglen) +{ + struct rtattr *rta; + size_t plen; + uint8_t u8v; + uint32_t u32v; + int32_t s32v; + uint64_t u64v; + char dbuf[128]; + struct fib_rule_uid_range *u_range; + struct fib_rule_port_range *p_range; + + /* Get the first attribute and go from there. */ + rta = RTM_RTA(frh); +next_rta: + /* Check the header for valid length and for outbound access. */ + if (RTA_OK(rta, msglen) == 0) + return; + + plen = RTA_PAYLOAD(rta); + zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, + plen, rta->rta_type, frh_rta2str(rta->rta_type)); + switch (rta->rta_type) { + case FRA_DST: + case FRA_SRC: + switch (plen) { + case sizeof(struct in_addr): + zlog_debug(" %pI4", + (struct in_addr *)RTA_DATA(rta)); + break; + case sizeof(struct in6_addr): + zlog_debug(" %pI6", + (struct in6_addr *)RTA_DATA(rta)); + break; + default: + break; + } + break; + + case FRA_IIFNAME: + case FRA_OIFNAME: + snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta)); + zlog_debug(" %s", dbuf); + break; + + case FRA_GOTO: + case FRA_UNUSED2: + case FRA_PRIORITY: + case FRA_UNUSED3: + case FRA_UNUSED4: + case FRA_UNUSED5: + case FRA_FWMARK: + case FRA_FLOW: + case FRA_TABLE: + case FRA_FWMASK: + u32v = *(uint32_t *)RTA_DATA(rta); + zlog_debug(" %u", u32v); + break; + + case FRA_SUPPRESS_IFGROUP: + case FRA_SUPPRESS_PREFIXLEN: + s32v = *(int32_t *)RTA_DATA(rta); + zlog_debug(" %d", s32v); + break; + + case FRA_TUN_ID: + u64v = *(uint64_t *)RTA_DATA(rta); + zlog_debug(" %" PRIu64, u64v); + break; + + case FRA_L3MDEV: + case FRA_PROTOCOL: + case FRA_IP_PROTO: + u8v = *(uint8_t *)RTA_DATA(rta); + zlog_debug(" %u", u8v); + break; + + case FRA_UID_RANGE: + u_range = (struct fib_rule_uid_range *)RTA_DATA(rta); + if (u_range->start == u_range->end) + zlog_debug(" %u", u_range->start); + else + zlog_debug(" %u-%u", u_range->start, u_range->end); + break; + + case FRA_SPORT_RANGE: + case FRA_DPORT_RANGE: + p_range = (struct fib_rule_port_range *)RTA_DATA(rta); + if (p_range->start == p_range->end) + zlog_debug(" %u", p_range->start); + else + zlog_debug(" %u-%u", p_range->start, p_range->end); + break; + + case FRA_PAD: /* fallthrough */ + default: + /* NOTHING: unhandled. */ + break; + } + + /* Get next pointer and start iteration again. */ + rta = RTA_NEXT(rta, msglen); + goto next_rta; +} + +static void nlncm_dump(const struct netconfmsg *ncm, size_t msglen) +{ + const struct rtattr *rta; + size_t plen; + uint32_t ival; + + rta = (void *)((const char *)ncm + + NLMSG_ALIGN(sizeof(struct netconfmsg))); + +next_rta: + /* Check the attr header for valid length. */ + if (RTA_OK(rta, msglen) == 0) + return; + + plen = RTA_PAYLOAD(rta); + + zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, + plen, rta->rta_type, ncm_rta2str(rta->rta_type)); + + switch (rta->rta_type) { + case NETCONFA_IFINDEX: + ival = *(uint32_t *)RTA_DATA(rta); + zlog_debug(" %d", (int32_t)ival); + break; + + /* Most attrs are just on/off. */ + case NETCONFA_FORWARDING: + case NETCONFA_RP_FILTER: + case NETCONFA_MC_FORWARDING: + case NETCONFA_PROXY_NEIGH: + case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN: + case NETCONFA_INPUT: + case NETCONFA_BC_FORWARDING: + ival = *(uint32_t *)RTA_DATA(rta); + dump_on_off(ival, " "); + break; + default: + /* NOTHING: unhandled. */ + break; + } + + /* Get next pointer and start iteration again. */ + rta = RTA_NEXT(rta, msglen); + goto next_rta; +} + void nl_dump(void *msg, size_t msglen) { struct nlmsghdr *nlmsg = msg; @@ -1119,7 +1389,9 @@ void nl_dump(void *msg, size_t msglen) struct ndmsg *ndm; struct rtmsg *rtm; struct nhmsg *nhm; + struct netconfmsg *ncm; struct ifinfomsg *ifi; + struct fib_rule_hdr *frh; char fbuf[128]; char ibuf[128]; @@ -1151,8 +1423,7 @@ next_header: case RTM_SETLINK: ifi = NLMSG_DATA(nlmsg); zlog_debug( - " ifinfomsg [family=%d type=(%d) %s " - "index=%d flags=0x%04x {%s}]", + " ifinfomsg [family=%d type=(%d) %s index=%d flags=0x%04x {%s}]", ifi->ifi_family, ifi->ifi_type, ifi_type2str(ifi->ifi_type), ifi->ifi_index, ifi->ifi_flags, @@ -1170,9 +1441,7 @@ next_header: case RTM_GETROUTE: rtm = NLMSG_DATA(nlmsg); zlog_debug( - " rtmsg [family=(%d) %s dstlen=%d srclen=%d tos=%d " - "table=%d protocol=(%d) %s scope=(%d) %s " - "type=(%d) %s flags=0x%04x {%s}]", + " rtmsg [family=(%d) %s dstlen=%d srclen=%d tos=%d table=%d protocol=(%d) %s scope=(%d) %s type=(%d) %s flags=0x%04x {%s}]", rtm->rtm_family, af_type2str(rtm->rtm_family), rtm->rtm_dst_len, rtm->rtm_src_len, rtm->rtm_tos, rtm->rtm_table, rtm->rtm_protocol, @@ -1188,8 +1457,7 @@ next_header: case RTM_DELNEIGH: ndm = NLMSG_DATA(nlmsg); zlog_debug( - " ndm [family=%d (%s) ifindex=%d state=0x%04x {%s} " - "flags=0x%04x {%s} type=%d (%s)]", + " ndm [family=%d (%s) ifindex=%d state=0x%04x {%s} flags=0x%04x {%s} type=%d (%s)]", ndm->ndm_family, af_type2str(ndm->ndm_family), ndm->ndm_ifindex, ndm->ndm_state, neigh_state2str(ndm->ndm_state, ibuf, sizeof(ibuf)), @@ -1200,12 +1468,24 @@ next_header: nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ndm))); break; + case RTM_NEWRULE: + case RTM_DELRULE: + frh = NLMSG_DATA(nlmsg); + zlog_debug( + " frh [family=%d (%s) dst_len=%d src_len=%d tos=%d table=%d res1=%d res2=%d action=%d (%s) flags=0x%x]", + frh->family, af_type2str(frh->family), frh->dst_len, + frh->src_len, frh->tos, frh->table, frh->res1, + frh->res2, frh->action, frh_action2str(frh->action), + frh->flags); + nlrule_dump(frh, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*frh))); + break; + + case RTM_NEWADDR: case RTM_DELADDR: ifa = NLMSG_DATA(nlmsg); zlog_debug( - " ifa [family=(%d) %s prefixlen=%d " - "flags=0x%04x {%s} scope=%d index=%u]", + " ifa [family=(%d) %s prefixlen=%d flags=0x%04x {%s} scope=%d index=%u]", ifa->ifa_family, af_type2str(ifa->ifa_family), ifa->ifa_prefixlen, ifa->ifa_flags, if_flags2str(ifa->ifa_flags, fbuf, sizeof(fbuf)), @@ -1218,8 +1498,7 @@ next_header: case RTM_GETNEXTHOP: nhm = NLMSG_DATA(nlmsg); zlog_debug( - " nhm [family=(%d) %s scope=(%d) %s " - "protocol=(%d) %s flags=0x%08x {%s}]", + " nhm [family=(%d) %s scope=(%d) %s protocol=(%d) %s flags=0x%08x {%s}]", nhm->nh_family, af_type2str(nhm->nh_family), nhm->nh_scope, rtm_scope2str(nhm->nh_scope), nhm->nh_protocol, rtm_protocol2str(nhm->nh_protocol), @@ -1228,6 +1507,14 @@ next_header: nlnh_dump(nhm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*nhm))); break; + case RTM_NEWNETCONF: + case RTM_DELNETCONF: + ncm = NLMSG_DATA(nlmsg); + zlog_debug(" ncm [family=%s (%d)]", + af_type2str(ncm->ncm_family), ncm->ncm_family); + nlncm_dump(ncm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ncm))); + break; + default: break; } diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 3b02128c9..8c8004190 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -176,16 +176,16 @@ enum fpm_nl_events { /* * Prototypes. */ -static int fpm_process_event(struct thread *t); +static void fpm_process_event(struct thread *t); static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx); -static int fpm_lsp_send(struct thread *t); -static int fpm_lsp_reset(struct thread *t); -static int fpm_nhg_send(struct thread *t); -static int fpm_nhg_reset(struct thread *t); -static int fpm_rib_send(struct thread *t); -static int fpm_rib_reset(struct thread *t); -static int fpm_rmac_send(struct thread *t); -static int fpm_rmac_reset(struct thread *t); +static void fpm_lsp_send(struct thread *t); +static void fpm_lsp_reset(struct thread *t); +static void fpm_nhg_send(struct thread *t); +static void fpm_nhg_reset(struct thread *t); +static void fpm_rib_send(struct thread *t); +static void fpm_rib_reset(struct thread *t); +static void fpm_rmac_send(struct thread *t); +static void fpm_rmac_reset(struct thread *t); /* * CLI. @@ -419,7 +419,7 @@ static struct cmd_node fpm_node = { /* * FPM functions. */ -static int fpm_connect(struct thread *t); +static void fpm_connect(struct thread *t); static void fpm_reconnect(struct fpm_nl_ctx *fnc) { @@ -458,7 +458,7 @@ static void fpm_reconnect(struct fpm_nl_ctx *fnc) &fnc->t_connect); } -static int fpm_read(struct thread *t) +static void fpm_read(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); ssize_t rv; @@ -471,7 +471,7 @@ static int fpm_read(struct thread *t) /* Schedule next read. */ thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket, &fnc->t_read); - return 0; + return; } if (rv == 0) { atomic_fetch_add_explicit(&fnc->counters.connection_closes, 1, @@ -481,7 +481,7 @@ static int fpm_read(struct thread *t) zlog_debug("%s: connection closed", __func__); FPM_RECONNECT(fnc); - return 0; + return; } if (rv == -1) { atomic_fetch_add_explicit(&fnc->counters.connection_errors, 1, @@ -489,7 +489,7 @@ static int fpm_read(struct thread *t) zlog_warn("%s: connection failure: %s", __func__, strerror(errno)); FPM_RECONNECT(fnc); - return 0; + return; } stream_reset(fnc->ibuf); @@ -499,11 +499,9 @@ static int fpm_read(struct thread *t) thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket, &fnc->t_read); - - return 0; } -static int fpm_write(struct thread *t) +static void fpm_write(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); socklen_t statuslen; @@ -530,7 +528,7 @@ static int fpm_write(struct thread *t) memory_order_relaxed); FPM_RECONNECT(fnc); - return 0; + return; } fnc->connecting = false; @@ -584,7 +582,7 @@ static int fpm_write(struct thread *t) strerror(errno)); FPM_RECONNECT(fnc); - return 0; + return; } /* Account all bytes sent. */ @@ -603,13 +601,11 @@ static int fpm_write(struct thread *t) stream_pulldown(fnc->obuf); thread_add_write(fnc->fthread->master, fpm_write, fnc, fnc->socket, &fnc->t_write); - return 0; + return; } - - return 0; } -static int fpm_connect(struct thread *t) +static void fpm_connect(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); struct sockaddr_in *sin = (struct sockaddr_in *)&fnc->addr; @@ -624,7 +620,7 @@ static int fpm_connect(struct thread *t) strerror(errno)); thread_add_timer(fnc->fthread->master, fpm_connect, fnc, 3, &fnc->t_connect); - return 0; + return; } set_nonblocking(sock); @@ -650,7 +646,7 @@ static int fpm_connect(struct thread *t) strerror(errno)); thread_add_timer(fnc->fthread->master, fpm_connect, fnc, 3, &fnc->t_connect); - return 0; + return; } fnc->connecting = (errno == EINPROGRESS); @@ -670,8 +666,6 @@ static int fpm_connect(struct thread *t) if (!fnc->connecting) thread_add_timer(zrouter.master, fpm_lsp_reset, fnc, 0, &fnc->t_lspreset); - - return 0; } /** @@ -786,6 +780,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) nl_buf_len += (size_t)rv; break; + /* Un-handled by FPM at this time. */ case DPLANE_OP_PW_INSTALL: case DPLANE_OP_PW_UNINSTALL: case DPLANE_OP_ADDR_INSTALL: @@ -799,15 +794,27 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_SYS_ROUTE_DELETE: case DPLANE_OP_ROUTE_NOTIFY: case DPLANE_OP_LSP_NOTIFY: + case DPLANE_OP_RULE_ADD: + case DPLANE_OP_RULE_DELETE: + case DPLANE_OP_RULE_UPDATE: + case DPLANE_OP_NEIGH_DISCOVER: + case DPLANE_OP_BR_PORT_UPDATE: + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: case DPLANE_OP_NONE: break; - default: - if (IS_ZEBRA_DEBUG_FPM) - zlog_debug("%s: unhandled data plane message (%d) %s", - __func__, dplane_ctx_get_op(ctx), - dplane_op2str(dplane_ctx_get_op(ctx))); - break; } /* Skip empty enqueues. */ @@ -893,7 +900,7 @@ static int fpm_lsp_send_cb(struct hash_bucket *bucket, void *arg) return HASHWALK_CONTINUE; } -static int fpm_lsp_send(struct thread *t) +static void fpm_lsp_send(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -918,8 +925,6 @@ static int fpm_lsp_send(struct thread *t) thread_add_timer(zrouter.master, fpm_lsp_send, fnc, 0, &fnc->t_lspwalk); } - - return 0; } /* @@ -955,7 +960,7 @@ static int fpm_nhg_send_cb(struct hash_bucket *bucket, void *arg) return HASHWALK_CONTINUE; } -static int fpm_nhg_send(struct thread *t) +static void fpm_nhg_send(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); struct fpm_nhg_arg fna; @@ -979,14 +984,12 @@ static int fpm_nhg_send(struct thread *t) } else /* Otherwise reschedule next hop group again. */ thread_add_timer(zrouter.master, fpm_nhg_send, fnc, 0, &fnc->t_nhgwalk); - - return 0; } /** * Send all RIB installed routes to the connected data plane. */ -static int fpm_rib_send(struct thread *t) +static void fpm_rib_send(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); rib_dest_t *dest; @@ -1020,7 +1023,7 @@ static int fpm_rib_send(struct thread *t) thread_add_timer(zrouter.master, fpm_rib_send, fnc, 1, &fnc->t_ribwalk); - return 0; + return; } /* Mark as sent. */ @@ -1037,8 +1040,6 @@ static int fpm_rib_send(struct thread *t) /* Schedule next event: RMAC reset. */ thread_add_event(zrouter.master, fpm_rmac_reset, fnc, 0, &fnc->t_rmacreset); - - return 0; } /* @@ -1092,7 +1093,7 @@ static void fpm_enqueue_l3vni_table(struct hash_bucket *bucket, void *arg) hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, zl3vni); } -static int fpm_rmac_send(struct thread *t) +static void fpm_rmac_send(struct thread *t) { struct fpm_rmac_arg fra; @@ -1105,8 +1106,6 @@ static int fpm_rmac_send(struct thread *t) /* RMAC walk completed. */ if (fra.complete) WALK_FINISH(fra.fnc, FNE_RMAC_FINISHED); - - return 0; } /* @@ -1120,7 +1119,7 @@ static void fpm_nhg_reset_cb(struct hash_bucket *bucket, void *arg) UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_FPM); } -static int fpm_nhg_reset(struct thread *t) +static void fpm_nhg_reset(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); @@ -1128,8 +1127,6 @@ static int fpm_nhg_reset(struct thread *t) /* Schedule next step: send next hop groups. */ thread_add_event(zrouter.master, fpm_nhg_send, fnc, 0, &fnc->t_nhgwalk); - - return 0; } /* @@ -1142,7 +1139,7 @@ static void fpm_lsp_reset_cb(struct hash_bucket *bucket, void *arg) UNSET_FLAG(lsp->flags, LSP_FLAG_FPM); } -static int fpm_lsp_reset(struct thread *t) +static void fpm_lsp_reset(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -1151,14 +1148,12 @@ static int fpm_lsp_reset(struct thread *t) /* Schedule next step: send LSPs */ thread_add_event(zrouter.master, fpm_lsp_send, fnc, 0, &fnc->t_lspwalk); - - return 0; } /** * Resets the RIB FPM flags so we send all routes again. */ -static int fpm_rib_reset(struct thread *t) +static void fpm_rib_reset(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); rib_dest_t *dest; @@ -1180,8 +1175,6 @@ static int fpm_rib_reset(struct thread *t) /* Schedule next step: send RIB routes. */ thread_add_event(zrouter.master, fpm_rib_send, fnc, 0, &fnc->t_ribwalk); - - return 0; } /* @@ -1201,7 +1194,7 @@ static void fpm_unset_l3vni_table(struct hash_bucket *bucket, void *arg) hash_iterate(zl3vni->rmac_table, fpm_unset_rmac_table, zl3vni); } -static int fpm_rmac_reset(struct thread *t) +static void fpm_rmac_reset(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); @@ -1210,11 +1203,9 @@ static int fpm_rmac_reset(struct thread *t) /* Schedule next event: send RMAC entries. */ thread_add_event(zrouter.master, fpm_rmac_send, fnc, 0, &fnc->t_rmacwalk); - - return 0; } -static int fpm_process_queue(struct thread *t) +static void fpm_process_queue(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); struct zebra_dplane_ctx *ctx; @@ -1269,14 +1260,12 @@ static int fpm_process_queue(struct thread *t) */ if (dplane_provider_out_ctx_queue_len(fnc->prov) > 0) dplane_provider_work_ready(); - - return 0; } /** * Handles external (e.g. CLI, data plane or others) events. */ -static int fpm_process_event(struct thread *t) +static void fpm_process_event(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); int event = THREAD_VAL(t); @@ -1338,8 +1327,6 @@ static int fpm_process_event(struct thread *t) zlog_debug("%s: unhandled event %d", __func__, event); break; } - - return 0; } /* diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 141e4074d..a75b16527 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -74,6 +74,7 @@ #include "zebra/zebra_vxlan.h" #include "zebra/zebra_evpn_mh.h" #include "zebra/zebra_l2.h" +#include "zebra/netconf_netlink.h" extern struct zebra_privs_t zserv_privs; @@ -1001,6 +1002,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Hardware type and address. */ ifp->ll_type = netlink_to_zebra_link_type(ifi->ifi_type); + netlink_interface_update_hw_addr(tb, ifp); if_add_update(ifp); @@ -1874,6 +1876,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } else { bool was_bridge_slave, was_bond_slave; uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; + zif = ifp->info; /* Interface update. */ if (IS_ZEBRA_DEBUG_KERNEL) @@ -1907,9 +1910,21 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) netlink_to_zebra_link_type(ifi->ifi_type); netlink_interface_update_hw_addr(tb, ifp); + if (tb[IFLA_PROTO_DOWN]) { + uint8_t protodown; + + protodown = *(uint8_t *)RTA_DATA( + tb[IFLA_PROTO_DOWN]); + netlink_proc_dplane_if_protodown(zif, + !!protodown); + } + if (if_is_no_ptm_operative(ifp)) { + bool is_up = if_is_operative(ifp); ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (!if_is_no_ptm_operative(ifp)) { + if (!if_is_no_ptm_operative(ifp) || + CHECK_FLAG(zif->flags, + ZIF_FLAG_PROTODOWN)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "Intf %s(%u) has gone DOWN", @@ -1925,7 +1940,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) zlog_debug( "Intf %s(%u) PTM up, notifying clients", name, ifp->ifindex); - zebra_interface_up_update(ifp); + if_up(ifp, !is_up); /* Update EVPN VNI when SVI MAC change */ @@ -1954,12 +1969,14 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (if_is_operative(ifp)) { + if (if_is_operative(ifp) && + !CHECK_FLAG(zif->flags, + ZIF_FLAG_PROTODOWN)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "Intf %s(%u) has come UP", name, ifp->ifindex); - if_up(ifp); + if_up(ifp, true); if (IS_ZEBRA_IF_BRIDGE(ifp)) chgflags = ZEBRA_BRIDGE_MASTER_UP; @@ -1988,15 +2005,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); - - if (tb[IFLA_PROTO_DOWN]) { - uint8_t protodown; - - protodown = *(uint8_t *)RTA_DATA( - tb[IFLA_PROTO_DOWN]); - netlink_proc_dplane_if_protodown(ifp->info, - !!protodown); - } } zif = ifp->info; diff --git a/zebra/interface.c b/zebra/interface.c index e4e80ec4e..a76f8741e 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -64,7 +64,7 @@ DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), static void if_down_del_nbr_connected(struct interface *ifp); -static int if_zebra_speed_update(struct thread *thread) +static void if_zebra_speed_update(struct thread *thread) { struct interface *ifp = THREAD_ARG(thread); struct zebra_if *zif = ifp->info; @@ -72,8 +72,6 @@ static int if_zebra_speed_update(struct thread *thread) bool changed = false; int error = 0; - zif->speed_update = NULL; - new_speed = kernel_get_speed(ifp, &error); /* error may indicate vrf not available or @@ -81,7 +79,7 @@ static int if_zebra_speed_update(struct thread *thread) * note that loopback & virtual interfaces can return 0 as speed */ if (error < 0) - return 1; + return; if (new_speed != ifp->speed) { zlog_info("%s: %s old speed: %u new speed: %u", __func__, @@ -92,12 +90,29 @@ static int if_zebra_speed_update(struct thread *thread) } if (changed || new_speed == UINT32_MAX) { - thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 5, - &zif->speed_update); +#define SPEED_UPDATE_SLEEP_TIME 5 +#define SPEED_UPDATE_COUNT_MAX (4 * 60 / SPEED_UPDATE_SLEEP_TIME) + /* + * Some interfaces never actually have an associated speed + * with them ( I am looking at you bridges ). + * So instead of iterating forever, let's give the + * system 4 minutes to try to figure out the speed + * if after that it it's probably never going to become + * useful. + * Since I don't know all the wonderful types of interfaces + * that may come into existence in the future I am going + * to not update the system to keep track of that. This + * is far simpler to just stop trying after 4 minutes + */ + if (new_speed == UINT32_MAX && + zif->speed_update_count == SPEED_UPDATE_COUNT_MAX) + return; + + zif->speed_update_count++; + thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, + SPEED_UPDATE_SLEEP_TIME, &zif->speed_update); thread_ignore_late_timer(zif->speed_update); } - - return 1; } static void zebra_if_node_destroy(route_table_delegate_t *delegate, @@ -158,6 +173,16 @@ static int if_zebra_new_hook(struct interface *ifp) rtadv->AdvReachableTime = 0; rtadv->AdvRetransTimer = 0; rtadv->AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT; + memset(&rtadv->lastadvcurhoplimit, 0, + sizeof(rtadv->lastadvcurhoplimit)); + memset(&rtadv->lastadvmanagedflag, 0, + sizeof(rtadv->lastadvmanagedflag)); + memset(&rtadv->lastadvotherconfigflag, 0, + sizeof(rtadv->lastadvotherconfigflag)); + memset(&rtadv->lastadvreachabletime, 0, + sizeof(rtadv->lastadvreachabletime)); + memset(&rtadv->lastadvretranstimer, 0, + sizeof(rtadv->lastadvretranstimer)); rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */ rtadv->HomeAgentPreference = 0; @@ -188,6 +213,7 @@ static int if_zebra_new_hook(struct interface *ifp) * of seconds and ask again. Hopefully it's all settled * down upon startup. */ + zebra_if->speed_update_count = 0; thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 15, &zebra_if->speed_update); thread_ignore_late_timer(zebra_if->speed_update); @@ -198,9 +224,13 @@ static int if_zebra_new_hook(struct interface *ifp) static void if_nhg_dependents_check_valid(struct nhg_hash_entry *nhe) { zebra_nhg_check_valid(nhe); - if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) - /* Assuming uninstalled as well here */ - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { + /* If we're in shutdown, this interface event needs to clean + * up installed NHGs, so don't clear that flag directly. + */ + if (!zrouter.in_shutdown) + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } } static void if_down_nhg_dependents(const struct interface *ifp) @@ -491,7 +521,7 @@ void if_flags_update(struct interface *ifp, uint64_t newflags) /* inoperative -> operative? */ ifp->flags = newflags; if (if_is_operative(ifp)) - if_up(ifp); + if_up(ifp, true); } } @@ -1019,7 +1049,7 @@ bool if_nhg_dependents_is_empty(const struct interface *ifp) } /* Interface is up. */ -void if_up(struct interface *ifp) +void if_up(struct interface *ifp, bool install_connected) { struct zebra_if *zif; struct interface *link_if; @@ -1051,7 +1081,8 @@ void if_up(struct interface *ifp) #endif /* Install connected routes to the kernel. */ - if_install_connected(ifp); + if (install_connected) + if_install_connected(ifp); /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces * are checked to see if (remote) neighbor entries need to be installed @@ -1310,6 +1341,56 @@ done: dplane_ctx_fini(&ctx); } +/* + * Handle netconf change from a dplane context object; runs in the main + * pthread so it can update zebra data structs. + */ +int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx) +{ + struct zebra_ns *zns; + struct interface *ifp; + struct zebra_if *zif; + enum dplane_netconf_status_e mpls; + int ret = 0; + + zns = zebra_ns_lookup(dplane_ctx_get_netconf_ns_id(ctx)); + if (zns == NULL) { + ret = -1; + goto done; + } + + ifp = if_lookup_by_index_per_ns(zns, + dplane_ctx_get_netconf_ifindex(ctx)); + if (ifp == NULL) { + ret = -1; + goto done; + } + + zif = ifp->info; + if (zif == NULL) { + ret = -1; + goto done; + } + + mpls = dplane_ctx_get_netconf_mpls(ctx); + + if (mpls == DPLANE_NETCONF_STATUS_ENABLED) + zif->mpls = true; + else if (mpls == DPLANE_NETCONF_STATUS_DISABLED) + zif->mpls = false; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: if %s, ifindex %d, mpls %s", + __func__, ifp->name, ifp->ifindex, + (zif->mpls ? "ON" : "OFF")); + +done: + /* Free the context */ + dplane_ctx_fini(&ctx); + + return ret; +} + /* Dump if address information to vty. */ static void connected_dump_vty(struct vty *vty, json_object *json, struct connected *connected) @@ -1662,6 +1743,9 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) vty_out(vty, "mtu6 %d ", ifp->mtu6); vty_out(vty, "\n flags: %s\n", if_flag_dump(ifp->flags)); + if (zebra_if->mpls) + vty_out(vty, " MPLS enabled\n"); + /* Hardware address. */ vty_out(vty, " Type: %s\n", if_link_type_str(ifp->ll_type)); if (ifp->hw_addr_len != 0) { @@ -1982,6 +2066,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, json_object_string_add(json_if, "OsDescription", zebra_if->desc); + json_object_boolean_add(json_if, "mplsEnabled", zebra_if->mpls); + if (ifp->ifindex == IFINDEX_INTERNAL) { json_object_boolean_add(json_if, "pseudoInterface", true); return; @@ -2697,7 +2783,7 @@ int if_linkdetect(struct interface *ifp, bool detect) /* Interface may come up after disabling link detection */ if (if_is_operative(ifp) && !if_was_operative) - if_up(ifp); + if_up(ifp, true); } /* FIXME: Will defer status change forwarding if interface does not come down! */ diff --git a/zebra/interface.h b/zebra/interface.h index 771398b54..315a3170d 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -81,6 +81,7 @@ struct rtadvconf { Default: false */ int AdvManagedFlag; + struct timeval lastadvmanagedflag; /* The true/false value to be placed in the "Other stateful @@ -89,6 +90,7 @@ struct rtadvconf { Default: false */ int AdvOtherConfigFlag; + struct timeval lastadvotherconfigflag; /* The value to be placed in MTU options sent by the router. A value of zero indicates that no MTU options are sent. @@ -105,6 +107,7 @@ struct rtadvconf { Default: 0 */ uint32_t AdvReachableTime; #define RTADV_MAX_REACHABLE_TIME 3600000 + struct timeval lastadvreachabletime; /* The value to be placed in the Retrans Timer field in the Router Advertisement messages sent by the router. The value zero means @@ -112,6 +115,7 @@ struct rtadvconf { Default: 0 */ int AdvRetransTimer; + struct timeval lastadvretranstimer; /* The default value to be placed in the Cur Hop Limit field in the Router Advertisement messages sent by the router. The value @@ -121,6 +125,8 @@ struct rtadvconf { Default: The value specified in the "Assigned Numbers" RFC [ASSIGNED] that was in effect at the time of implementation. */ int AdvCurHopLimit; + struct timeval lastadvcurhoplimit; + #define RTADV_DEFAULT_HOPLIMIT 64 /* 64 hops */ /* The value to be placed in the Router Lifetime field of Router @@ -323,6 +329,9 @@ struct zebra_if { /* Multicast configuration. */ uint8_t multicast; + /* MPLS status. */ + bool mpls; + /* Router advertise configuration. */ uint8_t rtadv_enable; @@ -403,6 +412,7 @@ struct zebra_if { ifindex_t link_ifindex; struct interface *link; + uint8_t speed_update_count; struct thread *speed_update; /* @@ -476,7 +486,7 @@ extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp, extern void if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(struct interface *ifp); extern void if_delete_update(struct interface *ifp); extern void if_add_update(struct interface *ifp); -extern void if_up(struct interface *); +extern void if_up(struct interface *ifp, bool install_connected); extern void if_down(struct interface *); extern void if_refresh(struct interface *); extern void if_flags_update(struct interface *, uint64_t); @@ -514,6 +524,7 @@ extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif); extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc, char *pd_buf, uint32_t pd_buf_len); void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx); +int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx); #ifdef HAVE_PROC_NET_DEV extern void ifstat_update_proc(void); diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 8b30eea9f..9b6aaf1d8 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -410,11 +410,14 @@ int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx) void if_get_flags(struct interface *ifp) { int ret; - struct ifreq ifreq; + struct ifreq ifreqflags; + struct ifreq ifreqdata; - ifreq_set_name(&ifreq, ifp); + ifreq_set_name(&ifreqflags, ifp); + ifreq_set_name(&ifreqdata, ifp); - ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); + ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreqflags, + ifp->vrf->vrf_id); if (ret < 0) { flog_err_sys(EC_LIB_SYSTEM_CALL, "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s", @@ -448,8 +451,8 @@ void if_get_flags(struct interface *ifp) struct if_data ifd = {.ifi_link_state = 0}; struct if_data *ifdata = &ifd; - ifreq.ifr_data = (caddr_t)ifdata; - ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreq, ifp->vrf->vrf_id); + ifreqdata.ifr_data = (caddr_t)ifdata; + ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreqdata, ifp->vrf->vrf_id); #endif if (ret == -1) @@ -459,12 +462,12 @@ void if_get_flags(struct interface *ifp) safe_strerror(errno)); else { if (ifdata->ifi_link_state >= LINK_STATE_UP) - SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); else if (ifdata->ifi_link_state == LINK_STATE_UNKNOWN) /* BSD traditionally treats UNKNOWN as UP */ - SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); else - UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); } #elif defined(HAVE_BSD_LINK_DETECT) @@ -489,14 +492,14 @@ void if_get_flags(struct interface *ifp) ifp->name, safe_strerror(errno)); } else if (ifmr.ifm_status & IFM_AVALID) { /* media state is valid */ if (ifmr.ifm_status & IFM_ACTIVE) /* media is active */ - SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); else - UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING); } #endif /* HAVE_BSD_LINK_DETECT */ out: - if_flags_update(ifp, (ifreq.ifr_flags & 0x0000ffff)); + if_flags_update(ifp, (ifreqflags.ifr_flags & 0x0000ffff)); } /* Set interface flags */ diff --git a/zebra/irdp.h b/zebra/irdp.h index c1ea34f3a..19f549cc5 100644 --- a/zebra/irdp.h +++ b/zebra/irdp.h @@ -144,10 +144,10 @@ struct Adv { extern void irdp_if_init(void); extern int irdp_sock_init(void); extern int irdp_config_write(struct vty *, struct interface *); -extern int irdp_send_thread(struct thread *t_advert); +extern void irdp_send_thread(struct thread *t_advert); extern void irdp_advert_off(struct interface *ifp); extern void process_solicit(struct interface *ifp); -extern int irdp_read_raw(struct thread *r); +extern void irdp_read_raw(struct thread *r); extern void send_packet(struct interface *ifp, struct stream *s, uint32_t dst, struct prefix *p, uint32_t ttl); diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index f141b7271..43478c98f 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -205,7 +205,7 @@ static void irdp_advertisement(struct interface *ifp, struct prefix *p) stream_free(s); } -int irdp_send_thread(struct thread *t_advert) +void irdp_send_thread(struct thread *t_advert) { uint32_t timer, tmp; struct interface *ifp = THREAD_ARG(t_advert); @@ -216,7 +216,7 @@ int irdp_send_thread(struct thread *t_advert) struct connected *ifc; if (!irdp) - return 0; + return; irdp->flags &= ~IF_SOLICIT; @@ -246,7 +246,6 @@ int irdp_send_thread(struct thread *t_advert) irdp->t_advertise = NULL; thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer, &irdp->t_advertise); - return 0; } void irdp_advert_off(struct interface *ifp) diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 5601b13a9..c27d97ba7 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -224,7 +224,7 @@ static int irdp_recvmsg(int sock, uint8_t *buf, int size, int *ifindex) return ret; } -int irdp_read_raw(struct thread *r) +void irdp_read_raw(struct thread *r) { struct interface *ifp; struct zebra_if *zi; @@ -243,22 +243,22 @@ int irdp_read_raw(struct thread *r) ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); if (!ifp) - return ret; + return; zi = ifp->info; if (!zi) - return ret; + return; irdp = zi->irdp; if (!irdp) - return ret; + return; if (!(irdp->flags & IF_ACTIVE)) { if (irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: RX ICMP for disabled interface %s", ifp->name); - return 0; + return; } if (irdp->flags & IF_DEBUG_PACKET) { @@ -269,8 +269,6 @@ int irdp_read_raw(struct thread *r) } parse_irdp_packet(buf, ret, ifp); - - return ret; } void send_packet(struct interface *ifp, struct stream *s, uint32_t dst, diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index d614aa26d..d84b0c132 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -36,8 +36,8 @@ #include "vrf.h" #include "mpls.h" #include "lib_errors.h" +#include "hash.h" -//#include "zebra/zserv.h" #include "zebra/zebra_router.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" @@ -47,6 +47,7 @@ #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" #include "zebra/rule_netlink.h" +#include "zebra/netconf_netlink.h" #include "zebra/zebra_errors.h" #ifndef SO_RCVBUFFORCE @@ -89,8 +90,6 @@ */ #define NL_DEFAULT_BATCH_SEND_THRESHOLD (15 * NL_PKT_BUF_SIZE) -#define NL_BATCH_RX_BUFSIZE NL_RCV_PKT_BUF_SIZE - static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_DELROUTE, "RTM_DELROUTE"}, {RTM_GETROUTE, "RTM_GETROUTE"}, @@ -109,6 +108,8 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP"}, {RTM_DELNEXTHOP, "RTM_DELNEXTHOP"}, {RTM_GETNEXTHOP, "RTM_GETNEXTHOP"}, + {RTM_NEWNETCONF, "RTM_NEWNETCONF"}, + {RTM_DELNETCONF, "RTM_DELNETCONF"}, {0}}; static const struct message rtproto_str[] = { @@ -154,17 +155,25 @@ static const struct message rttype_str[] = {{RTN_UNSPEC, "none"}, {0}}; extern struct thread_master *master; -extern uint32_t nl_rcvbufsize; extern struct zebra_privs_t zserv_privs; DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers"); +/* Hashtable and mutex to allow lookup of nlsock structs by socket/fd value. + * We have both the main and dplane pthreads using these structs, so we have + * to protect the hash with a lock. + */ +static struct hash *nlsock_hash; +pthread_mutex_t nlsock_mutex; + +/* Lock and unlock wrappers for nlsock hash */ +#define NLSOCK_LOCK() pthread_mutex_lock(&nlsock_mutex) +#define NLSOCK_UNLOCK() pthread_mutex_unlock(&nlsock_mutex) + size_t nl_batch_tx_bufsize; char *nl_batch_tx_buf; -char nl_batch_rx_buf[NL_BATCH_RX_BUFSIZE]; - _Atomic uint32_t nl_batch_bufsize = NL_DEFAULT_BATCH_BUFSIZE; _Atomic uint32_t nl_batch_send_threshold = NL_DEFAULT_BATCH_SEND_THRESHOLD; @@ -251,12 +260,11 @@ static int netlink_recvbuf(struct nlsock *nl, uint32_t newsize) /* Try force option (linux >= 2.6.14) and fall back to normal set */ frr_with_privs(&zserv_privs) { ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, - &nl_rcvbufsize, - sizeof(nl_rcvbufsize)); + &rcvbufsize, sizeof(rcvbufsize)); } if (ret < 0) - ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, - &nl_rcvbufsize, sizeof(nl_rcvbufsize)); + ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsize, + sizeof(rcvbufsize)); if (ret < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't set %s receive buffer size: %s", nl->name, @@ -318,6 +326,9 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups, nl->snl = snl; nl->sock = sock; + nl->buflen = NL_RCV_PKT_BUF_SIZE; + nl->buf = XMALLOC(MTYPE_NL_BUF, nl->buflen); + return ret; } @@ -362,6 +373,8 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, /* Messages handled in the dplane thread */ case RTM_NEWADDR: case RTM_DELADDR: + case RTM_NEWNETCONF: + case RTM_DELNETCONF: return 0; default: @@ -396,7 +409,12 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELADDR: return netlink_interface_addr_dplane(h, ns_id, startup); - /* TODO */ + case RTM_NEWNETCONF: + case RTM_DELNETCONF: + return netlink_netconf_change(h, ns_id, startup); + + /* TODO -- other messages for the dplane socket and pthread */ + case RTM_NEWLINK: case RTM_DELLINK: @@ -407,7 +425,7 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; } -static int kernel_read(struct thread *thread) +static void kernel_read(struct thread *thread) { struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread); struct zebra_dplane_info dp_info; @@ -420,8 +438,6 @@ static int kernel_read(struct thread *thread) thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); - - return 0; } /* @@ -429,8 +445,10 @@ static int kernel_read(struct thread *thread) */ int kernel_dplane_read(struct zebra_dplane_info *info) { - netlink_parse_info(dplane_netlink_information_fetch, &info->nls, info, - 5, false); + struct nlsock *nl = kernel_netlink_nlsock_lookup(info->sock); + + netlink_parse_info(dplane_netlink_information_fetch, nl, info, 5, + false); return 0; } @@ -445,8 +463,8 @@ int kernel_dplane_read(struct zebra_dplane_info *info) * then the normal course of operations). We are intentionally * allowing some messages from ourselves through * ( I'm looking at you Interface based netlink messages ) - * so that we only had to write one way to handle incoming - * address add/delete changes. + * so that we only have to write one way to handle incoming + * address add/delete and xxxNETCONF changes. */ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) { @@ -462,7 +480,8 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) * if (nlmsg_pid == pid || * nlmsg_pid == dplane_pid) { * if (the incoming nlmsg_type == - * RTM_NEWADDR | RTM_DELADDR) + * RTM_NEWADDR || RTM_DELADDR || RTM_NEWNETCONF || + * RTM_DELNETCONF) * keep this message * else * skip this message @@ -481,7 +500,7 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) /* * 2: Compare to dplane pid */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 4), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 6), /* * 3: Load the nlmsg_type into BPF register */ @@ -490,17 +509,27 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) /* * 4: Compare to RTM_NEWADDR */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 2, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 4, 0), /* * 5: Compare to RTM_DELADDR */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 1, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 3, 0), /* - * 6: This is the end state of we want to skip the + * 6: Compare to RTM_NEWNETCONF + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWNETCONF), 2, + 0), + /* + * 7: Compare to RTM_DELNETCONF + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELNETCONF), 1, + 0), + /* + * 8: This is the end state of we want to skip the * message */ BPF_STMT(BPF_RET | BPF_K, 0), - /* 7: This is the end state of we want to keep + /* 9: This is the end state of we want to keep * the message */ BPF_STMT(BPF_RET | BPF_K, 0xffff), @@ -781,19 +810,29 @@ static ssize_t netlink_send_msg(const struct nlsock *nl, void *buf, * * Returns -1 on error, 0 if read would block or the number of bytes received. */ -static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg, - void *buf, size_t buflen) +static int netlink_recv_msg(struct nlsock *nl, struct msghdr *msg) { struct iovec iov; int status; - iov.iov_base = buf; - iov.iov_len = buflen; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + iov.iov_base = nl->buf; + iov.iov_len = nl->buflen; + msg->msg_iov = &iov; + msg->msg_iovlen = 1; do { - status = recvmsg(nl->sock, &msg, 0); + int bytes; + + bytes = recv(nl->sock, NULL, 0, MSG_PEEK | MSG_TRUNC); + + if (bytes >= 0 && (size_t)bytes > nl->buflen) { + nl->buf = XREALLOC(MTYPE_NL_BUF, nl->buf, bytes); + nl->buflen = bytes; + iov.iov_base = nl->buf; + iov.iov_len = nl->buflen; + } + + status = recvmsg(nl->sock, msg, 0); } while (status == -1 && errno == EINTR); if (status == -1) { @@ -813,19 +852,19 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg, return -1; } - if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { + if (msg->msg_namelen != sizeof(struct sockaddr_nl)) { flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR, "%s sender address length error: length %d", nl->name, - msg.msg_namelen); + msg->msg_namelen); return -1; } if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV) { zlog_debug("%s: << netlink message dump [recv]", __func__); #ifdef NETLINK_DEBUG - nl_dump(buf, status); + nl_dump(nl->buf, status); #else - zlog_hexdump(buf, status); + zlog_hexdump(nl->buf, status); #endif /* NETLINK_DEBUG */ } @@ -928,8 +967,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h, * the filter. */ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), - const struct nlsock *nl, - const struct zebra_dplane_info *zns, + struct nlsock *nl, const struct zebra_dplane_info *zns, int count, bool startup) { int status; @@ -938,7 +976,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), int read_in = 0; while (1) { - char buf[NL_RCV_PKT_BUF_SIZE]; struct sockaddr_nl snl; struct msghdr msg = {.msg_name = (void *)&snl, .msg_namelen = sizeof(snl)}; @@ -947,14 +984,14 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), if (count && read_in >= count) return 0; - status = netlink_recv_msg(nl, msg, buf, sizeof(buf)); + status = netlink_recv_msg(nl, &msg); if (status == -1) return -1; else if (status == 0) break; read_in++; - for (h = (struct nlmsghdr *)buf; + for (h = (struct nlmsghdr *)nl->buf; (status >= 0 && NLMSG_OK(h, (unsigned int)status)); h = NLMSG_NEXT(h, status)) { /* Finish of reading. */ @@ -1030,15 +1067,15 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), * startup -> Are we reading in under startup conditions * This is passed through eventually to filter. */ -static int -netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), - struct nlmsghdr *n, const struct zebra_dplane_info *dp_info, - bool startup) +static int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, + int startup), + struct nlmsghdr *n, + struct zebra_dplane_info *dp_info, bool startup) { - const struct nlsock *nl; + struct nlsock *nl; - nl = &(dp_info->nls); - n->nlmsg_seq = nl->seq; + nl = kernel_netlink_nlsock_lookup(dp_info->sock); + n->nlmsg_seq = dp_info->seq; n->nlmsg_pid = nl->snl.nl_pid; if (IS_ZEBRA_DEBUG_KERNEL) @@ -1109,11 +1146,11 @@ static int nl_batch_read_resp(struct nl_batch *bth) struct sockaddr_nl snl; struct msghdr msg = {}; int status, seq; - const struct nlsock *nl; + struct nlsock *nl; struct zebra_dplane_ctx *ctx; bool ignore_msg; - nl = &(bth->zns->nls); + nl = kernel_netlink_nlsock_lookup(bth->zns->sock); msg.msg_name = (void *)&snl; msg.msg_namelen = sizeof(snl); @@ -1123,12 +1160,28 @@ static int nl_batch_read_resp(struct nl_batch *bth) * message at a time. */ while (true) { - status = netlink_recv_msg(nl, msg, nl_batch_rx_buf, - sizeof(nl_batch_rx_buf)); - if (status == -1 || status == 0) + status = netlink_recv_msg(nl, &msg); + /* + * status == -1 is a full on failure somewhere + * since we don't know where the problem happened + * we must mark all as failed + * + * Else we mark everything as worked + * + */ + if (status == -1 || status == 0) { + while ((ctx = dplane_ctx_dequeue(&(bth->ctx_list))) != + NULL) { + if (status == -1) + dplane_ctx_set_status( + ctx, + ZEBRA_DPLANE_REQUEST_FAILURE); + dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); + } return status; + } - h = (struct nlmsghdr *)nl_batch_rx_buf; + h = (struct nlmsghdr *)nl->buf; ignore_msg = false; seq = h->nlmsg_seq; /* @@ -1138,22 +1191,25 @@ static int nl_batch_read_resp(struct nl_batch *bth) * requests at same time. */ while (true) { - ctx = dplane_ctx_dequeue(&(bth->ctx_list)); - if (ctx == NULL) - break; - - dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); - - /* We have found corresponding context object. */ - if (dplane_ctx_get_ns(ctx)->nls.seq == seq) + ctx = dplane_ctx_get_head(&(bth->ctx_list)); + if (ctx == NULL) { + /* + * This is a situation where we have gotten + * into a bad spot. We need to know that + * this happens( does it? ) + */ + zlog_err( + "%s:WARNING Received netlink Response for an error and no Contexts to associate with it", + __func__); break; + } /* * 'update' context objects take two consecutive * sequence numbers. */ - if (dplane_ctx_is_update(ctx) - && dplane_ctx_get_ns(ctx)->nls.seq + 1 == seq) { + if (dplane_ctx_is_update(ctx) && + dplane_ctx_get_ns(ctx)->seq + 1 == seq) { /* * This is the situation where we get a response * to a message that should be ignored. @@ -1161,10 +1217,35 @@ static int nl_batch_read_resp(struct nl_batch *bth) ignore_msg = true; break; } + + ctx = dplane_ctx_dequeue(&(bth->ctx_list)); + dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); + + /* We have found corresponding context object. */ + if (dplane_ctx_get_ns(ctx)->seq == seq) + break; + + if (dplane_ctx_get_ns(ctx)->seq > seq) + zlog_warn( + "%s:WARNING Received %u is less than any context on the queue ctx->seq %u", + __func__, seq, + dplane_ctx_get_ns(ctx)->seq); } - if (ignore_msg) + if (ignore_msg) { + /* + * If we ignore the message due to an update + * above we should still fricking decode the + * message for our operator to understand + * what is going on + */ + int err = netlink_parse_error(nl, h, bth->zns->is_cmd, + false); + + zlog_debug("%s: netlink error message seq=%d %d", + __func__, h->nlmsg_seq, err); continue; + } /* * We received a message with the sequence number that isn't @@ -1250,13 +1331,15 @@ static void nl_batch_send(struct nl_batch *bth) bool err = false; if (bth->curlen != 0 && bth->zns != NULL) { + struct nlsock *nl = + kernel_netlink_nlsock_lookup(bth->zns->sock); + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: %s, batch size=%zu, msg cnt=%zu", - __func__, bth->zns->nls.name, bth->curlen, + __func__, nl->name, bth->curlen, bth->msgcnt); - if (netlink_send_msg(&(bth->zns->nls), bth->buf, bth->curlen) - == -1) + if (netlink_send_msg(nl, bth->buf, bth->curlen) == -1) err = true; if (!err) { @@ -1289,6 +1372,7 @@ enum netlink_msg_status netlink_batch_add_msg( int seq; ssize_t size; struct nlmsghdr *msgh; + struct nlsock *nl; size = (*msg_encoder)(ctx, bth->buf_head, bth->bufsiz - bth->curlen); @@ -1315,13 +1399,15 @@ enum netlink_msg_status netlink_batch_add_msg( return FRR_NETLINK_ERROR; } - seq = dplane_ctx_get_ns(ctx)->nls.seq; + seq = dplane_ctx_get_ns(ctx)->seq; + nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); + if (ignore_res) seq++; msgh = (struct nlmsghdr *)bth->buf_head; msgh->nlmsg_seq = seq; - msgh->nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; + msgh->nlmsg_pid = nl->snl.nl_pid; bth->zns = dplane_ctx_get_ns(ctx); bth->buf_head = ((char *)bth->buf_head) + size; @@ -1402,6 +1488,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: case DPLANE_OP_NONE: return FRR_NETLINK_ERROR; } @@ -1451,11 +1538,58 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list) dplane_ctx_list_append(ctx_list, &handled_list); } +struct nlsock *kernel_netlink_nlsock_lookup(int sock) +{ + struct nlsock lookup, *retval; + + lookup.sock = sock; + + NLSOCK_LOCK(); + retval = hash_lookup(nlsock_hash, &lookup); + NLSOCK_UNLOCK(); + + return retval; +} + +/* Insert nlsock entry into hash */ +static void kernel_netlink_nlsock_insert(struct nlsock *nls) +{ + NLSOCK_LOCK(); + (void)hash_get(nlsock_hash, nls, hash_alloc_intern); + NLSOCK_UNLOCK(); +} + +/* Remove nlsock entry from hash */ +static void kernel_netlink_nlsock_remove(struct nlsock *nls) +{ + NLSOCK_LOCK(); + (void)hash_release(nlsock_hash, nls); + NLSOCK_UNLOCK(); +} + +static uint32_t kernel_netlink_nlsock_key(const void *arg) +{ + const struct nlsock *nl = arg; + + return nl->sock; +} + +static bool kernel_netlink_nlsock_hash_equal(const void *arg1, const void *arg2) +{ + const struct nlsock *nl1 = arg1; + const struct nlsock *nl2 = arg2; + + if (nl1->sock == nl2->sock) + return true; + + return false; +} + /* Exported interface function. This function simply calls netlink_socket (). */ void kernel_init(struct zebra_ns *zns) { - uint32_t groups; + uint32_t groups, dplane_groups; #if defined SOL_NETLINK int one, ret; #endif @@ -1480,6 +1614,14 @@ void kernel_init(struct zebra_ns *zns) ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) | ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)); + dplane_groups = (RTMGRP_LINK | + RTMGRP_IPV4_IFADDR | + RTMGRP_IPV6_IFADDR | + ((uint32_t) 1 << (RTNLGRP_IPV4_NETCONF - 1)) | + ((uint32_t) 1 << (RTNLGRP_IPV6_NETCONF - 1)) | + ((uint32_t) 1 << (RTNLGRP_MPLS_NETCONF - 1))); + + snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); zns->netlink.sock = -1; @@ -1489,6 +1631,8 @@ void kernel_init(struct zebra_ns *zns) exit(-1); } + kernel_netlink_nlsock_insert(&zns->netlink); + snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name), "netlink-cmd (NS %u)", zns->ns_id); zns->netlink_cmd.sock = -1; @@ -1498,6 +1642,8 @@ void kernel_init(struct zebra_ns *zns) exit(-1); } + kernel_netlink_nlsock_insert(&zns->netlink_cmd); + /* Outbound socket for dplane programming of the host OS. */ snprintf(zns->netlink_dplane_out.name, sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)", @@ -1509,17 +1655,22 @@ void kernel_init(struct zebra_ns *zns) exit(-1); } + kernel_netlink_nlsock_insert(&zns->netlink_dplane_out); + /* Inbound socket for OS events coming to the dplane. */ snprintf(zns->netlink_dplane_in.name, sizeof(zns->netlink_dplane_in.name), "netlink-dp-in (NS %u)", zns->ns_id); zns->netlink_dplane_in.sock = -1; - if (netlink_socket(&zns->netlink_dplane_in, groups, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, + zns->ns_id) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_in.name); exit(-1); } + kernel_netlink_nlsock_insert(&zns->netlink_dplane_in); + /* * SOL_NETLINK is not available on all platforms yet * apparently. It's in bits/socket.h which I am not @@ -1579,11 +1730,11 @@ void kernel_init(struct zebra_ns *zns) errno); /* Set receive buffer size if it's set from command line */ - if (nl_rcvbufsize) { - netlink_recvbuf(&zns->netlink, nl_rcvbufsize); - netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize); - netlink_recvbuf(&zns->netlink_dplane_out, nl_rcvbufsize); - netlink_recvbuf(&zns->netlink_dplane_in, nl_rcvbufsize); + if (rcvbufsize) { + netlink_recvbuf(&zns->netlink, rcvbufsize); + netlink_recvbuf(&zns->netlink_cmd, rcvbufsize); + netlink_recvbuf(&zns->netlink_dplane_out, rcvbufsize); + netlink_recvbuf(&zns->netlink_dplane_in, rcvbufsize); } /* Set filter for inbound sockets, to exclude events we've generated @@ -1604,33 +1755,56 @@ void kernel_init(struct zebra_ns *zns) rt_netlink_init(); } +/* Helper to clean up an nlsock */ +static void kernel_nlsock_fini(struct nlsock *nls) +{ + if (nls && nls->sock >= 0) { + kernel_netlink_nlsock_remove(nls); + close(nls->sock); + nls->sock = -1; + XFREE(MTYPE_NL_BUF, nls->buf); + nls->buflen = 0; + } +} + void kernel_terminate(struct zebra_ns *zns, bool complete) { thread_cancel(&zns->t_netlink); - if (zns->netlink.sock >= 0) { - close(zns->netlink.sock); - zns->netlink.sock = -1; - } + kernel_nlsock_fini(&zns->netlink); - if (zns->netlink_cmd.sock >= 0) { - close(zns->netlink_cmd.sock); - zns->netlink_cmd.sock = -1; - } + kernel_nlsock_fini(&zns->netlink_cmd); - if (zns->netlink_dplane_in.sock >= 0) { - close(zns->netlink_dplane_in.sock); - zns->netlink_dplane_in.sock = -1; - } + kernel_nlsock_fini(&zns->netlink_dplane_in); /* During zebra shutdown, we need to leave the dataplane socket * around until all work is done. */ - if (complete) { - if (zns->netlink_dplane_out.sock >= 0) { - close(zns->netlink_dplane_out.sock); - zns->netlink_dplane_out.sock = -1; - } - } + if (complete) + kernel_nlsock_fini(&zns->netlink_dplane_out); } + +/* + * Global init for platform-/OS-specific things + */ +void kernel_router_init(void) +{ + /* Init nlsock hash and lock */ + pthread_mutex_init(&nlsock_mutex, NULL); + nlsock_hash = hash_create_size(8, kernel_netlink_nlsock_key, + kernel_netlink_nlsock_hash_equal, + "Netlink Socket Hash"); +} + +/* + * Global deinit for platform-/OS-specific things + */ +void kernel_router_terminate(void) +{ + pthread_mutex_destroy(&nlsock_mutex); + + hash_free(nlsock_hash); + nlsock_hash = NULL; +} + #endif /* HAVE_NETLINK */ diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index cf8b8c785..9421ea1c6 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -96,7 +96,7 @@ extern const char *nl_family_to_str(uint8_t family); extern const char *nl_rttype_to_str(uint8_t rttype); extern int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), - const struct nlsock *nl, + struct nlsock *nl, const struct zebra_dplane_info *dp_info, int count, bool startup); extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup); @@ -146,6 +146,7 @@ extern int netlink_config_write_helper(struct vty *vty); extern void netlink_set_batch_buffer_size(uint32_t size, uint32_t threshold, bool set); +extern struct nlsock *kernel_netlink_nlsock_lookup(int sock); #endif /* HAVE_NETLINK */ #ifdef __cplusplus diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 5ff66f7c6..ce1f17111 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1011,6 +1011,8 @@ void rtm_read(struct rt_msghdr *rtm) ifindex_t ifindex = 0; afi_t afi; char fbuf[64]; + int32_t proto = ZEBRA_ROUTE_KERNEL; + uint8_t distance = 0; zebra_flags = 0; @@ -1042,8 +1044,11 @@ void rtm_read(struct rt_msghdr *rtm) if (!(flags & RTF_GATEWAY)) return; - if (flags & RTF_PROTO1) + if (flags & RTF_PROTO1) { SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE); + proto = ZEBRA_ROUTE_STATIC; + distance = 255; + } memset(&nh, 0, sizeof(nh)); @@ -1111,13 +1116,13 @@ void rtm_read(struct rt_msghdr *rtm) 0, true); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) - rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, - zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, - 0, 0, 0, 0); + rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, proto, 0, zebra_flags, + &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, 0, distance, 0, + false); else - rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, - 0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, - 0, true); + rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, proto, 0, + zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, + distance, true); } /* Interface function for the kernel routing table updates. Support @@ -1292,7 +1297,7 @@ static void rtmsg_debug(struct rt_msghdr *rtm) #endif /* RTAX_MAX */ /* Kernel routing table and interface updates via routing socket. */ -static int kernel_read(struct thread *thread) +static void kernel_read(struct thread *thread) { int sock; int nbytes; @@ -1356,11 +1361,11 @@ static int kernel_read(struct thread *thread) if (errno != EAGAIN && errno != EWOULDBLOCK) flog_err_sys(EC_LIB_SOCKET, "routing socket error: %s", safe_strerror(errno)); - return 0; + return; } if (nbytes == 0) - return 0; + return; thread_add_read(zrouter.master, kernel_read, NULL, sock, NULL); @@ -1377,7 +1382,7 @@ static int kernel_read(struct thread *thread) zlog_debug( "kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d", rtm->rtm_msglen, nbytes, rtm->rtm_type); - return -1; + return; } switch (rtm->rtm_type) { @@ -1403,12 +1408,14 @@ static int kernel_read(struct thread *thread) zlog_debug("Unprocessed RTM_type: %d", rtm->rtm_type); break; } - return 0; } /* Make routing socket. */ static void routing_socket(struct zebra_ns *zns) { + uint32_t default_rcvbuf; + socklen_t optlen; + frr_with_privs(&zserv_privs) { routing_sock = ns_socket(AF_ROUTE, SOCK_RAW, 0, zns->ns_id); @@ -1443,6 +1450,23 @@ static void routing_socket(struct zebra_ns *zns) /*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) zlog_warn ("Can't set O_NONBLOCK to routing socket");*/ + /* + * Attempt to set a more useful receive buffer size + */ + optlen = sizeof(default_rcvbuf); + if (getsockopt(routing_sock, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf, + &optlen) == -1) + flog_err_sys(EC_LIB_SOCKET, + "routing_sock sockopt SOL_SOCKET SO_RCVBUF"); + else { + for (; rcvbufsize > default_rcvbuf && + setsockopt(routing_sock, SOL_SOCKET, SO_RCVBUF, + &rcvbufsize, sizeof(rcvbufsize)) == -1 && + errno == ENOBUFS; + rcvbufsize /= 2) + ; + } + /* kernel_read needs rewrite. */ thread_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL); } @@ -1459,6 +1483,20 @@ void kernel_terminate(struct zebra_ns *zns, bool complete) return; } +/* + * Global init for platform-/OS-specific things + */ +void kernel_router_init(void) +{ +} + +/* + * Global deinit for platform-/OS-specific things + */ +void kernel_router_terminate(void) +{ +} + /* * Called by the dplane pthread to read incoming OS messages and dispatch them. */ diff --git a/zebra/main.c b/zebra/main.c index 079751af0..7ef30d1d4 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -78,10 +78,12 @@ int graceful_restart; bool v6_rr_semantics = false; +/* Receive buffer size for kernel control sockets */ #ifdef HAVE_NETLINK -/* Receive buffer size for netlink socket */ -uint32_t nl_rcvbufsize = 4194304; -#endif /* HAVE_NETLINK */ +uint32_t rcvbufsize = 4194304; +#else +uint32_t rcvbufsize = 128 * 1024; +#endif #define OPTION_V6_RR_SEMANTICS 2000 #define OPTION_ASIC_OFFLOAD 2001 @@ -213,7 +215,7 @@ static void sigint(void) * Final shutdown step for the zebra main thread. This is run after all * async update processing has completed. */ -int zebra_finalize(struct thread *dummy) +void zebra_finalize(struct thread *dummy) { zlog_info("Zebra final shutdown"); @@ -294,9 +296,9 @@ int main(int argc, char **argv) frr_preinit(&zebra_di, argc, argv); frr_opt_add( - "baz:e:rK:" + "baz:e:rK:s:" #ifdef HAVE_NETLINK - "s:n" + "n" #endif , longopts, @@ -308,9 +310,11 @@ int main(int argc, char **argv) " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" #ifdef HAVE_NETLINK - " -n, --vrfwnetns Use NetNS as VRF backend\n" " -s, --nl-bufsize Set netlink receive buffer size\n" + " -n, --vrfwnetns Use NetNS as VRF backend\n" " --v6-rr-semantics Use v6 RR semantics\n" +#else + " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ ); @@ -359,10 +363,10 @@ int main(int argc, char **argv) case 'K': graceful_restart = atoi(optarg); break; -#ifdef HAVE_NETLINK case 's': - nl_rcvbufsize = atoi(optarg); + rcvbufsize = atoi(optarg); break; +#ifdef HAVE_NETLINK case 'n': vrf_configure_backend(VRF_BACKEND_NETNS); break; diff --git a/zebra/netconf_netlink.c b/zebra/netconf_netlink.c new file mode 100644 index 000000000..587f6c749 --- /dev/null +++ b/zebra/netconf_netlink.c @@ -0,0 +1,175 @@ +/* + * netconf_netlink.c - netconf interaction with the kernel using + * netlink + * Copyright (C) 2021 Nvidia, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include + +#ifdef HAVE_NETLINK /* Netlink OSes only */ + +#include + +#include "linux/netconf.h" + +#include "zebra/zebra_ns.h" +#include "zebra/zebra_dplane.h" +#include "zebra/kernel_netlink.h" +#include "zebra/netconf_netlink.h" +#include "zebra/debug.h" + +static struct rtattr *netconf_rta(struct netconfmsg *ncm) +{ + return (struct rtattr *)((char *)ncm + + NLMSG_ALIGN(sizeof(struct netconfmsg))); +} + +/* + * Handle netconf update about a single interface: create dplane + * context, and enqueue for processing in the main zebra pthread. + */ +static int netlink_netconf_dplane_update(ns_id_t ns_id, ifindex_t ifindex, + enum dplane_netconf_status_e mpls_on, + enum dplane_netconf_status_e mcast_on) +{ + struct zebra_dplane_ctx *ctx; + + ctx = dplane_ctx_alloc(); + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_NETCONFIG); + dplane_ctx_set_netconf_ns_id(ctx, ns_id); + dplane_ctx_set_netconf_ifindex(ctx, ifindex); + + dplane_ctx_set_netconf_mpls(ctx, mpls_on); + dplane_ctx_set_netconf_mcast(ctx, mcast_on); + + /* Enqueue ctx for main pthread to process */ + dplane_provider_enqueue_to_zebra(ctx); + + return 0; +} + +/* + * Parse and process an incoming netlink netconf update. + */ +int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +{ + struct netconfmsg *ncm; + struct rtattr *tb[NETCONFA_MAX + 1] = {}; + int len; + ifindex_t ifindex; + uint32_t ival; + enum dplane_netconf_status_e mpls_on = DPLANE_NETCONF_STATUS_UNKNOWN; + enum dplane_netconf_status_e mcast_on = DPLANE_NETCONF_STATUS_UNKNOWN; + + if (h->nlmsg_type != RTM_NEWNETCONF && h->nlmsg_type != RTM_DELNETCONF) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct netconfmsg)); + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size: %d, min %zu", + __func__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct netconfmsg))); + return -1; + } + + ncm = NLMSG_DATA(h); + + netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len); + + if (!tb[NETCONFA_IFINDEX]) { + zlog_err("NETCONF message received from netlink without an ifindex"); + return 0; + } + + ifindex = *(ifindex_t *)RTA_DATA(tb[NETCONFA_IFINDEX]); + + switch (ifindex) { + case NETCONFA_IFINDEX_ALL: + case NETCONFA_IFINDEX_DEFAULT: + /* + * We need the ability to handle netlink messages intended + * for all and default interfaces. I am not 100% sure + * what that is yet, or where we would store it. + */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Ignoring global ifindex %d", + __func__, ifindex); + + return 0; + default: + break; + } + + if (tb[NETCONFA_INPUT]) { + ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_INPUT]); + if (ival != 0) + mpls_on = DPLANE_NETCONF_STATUS_ENABLED; + else + mpls_on = DPLANE_NETCONF_STATUS_DISABLED; + } + + if (tb[NETCONFA_MC_FORWARDING]) { + ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]); + if (ival != 0) + mcast_on = DPLANE_NETCONF_STATUS_ENABLED; + else + mcast_on = DPLANE_NETCONF_STATUS_DISABLED; + } + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: interface %u is mpls on: %d multicast on: %d", + __func__, ifindex, mpls_on, mcast_on); + + /* Create a dplane context and pass it along for processing */ + netlink_netconf_dplane_update(ns_id, ifindex, mpls_on, mcast_on); + + return 0; +} + +/* + * Request info from the host OS. This only sends the request; any replies + * are processed asynchronously. + */ +int netlink_request_netconf(int sockfd) +{ + struct nlsock *nls; + struct { + struct nlmsghdr n; + struct netconfmsg ncm; + char buf[1024]; + } req = {}; + + nls = kernel_netlink_nlsock_lookup(sockfd); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: nlsock %s", __func__, nls ? nls->name : "NULL"); + + if (nls == NULL) + return -1; + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)); + req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETNETCONF; + req.ncm.ncm_family = AF_UNSPEC; + + return netlink_request(nls, &req); +} + +#endif /* HAVE_NETLINK */ diff --git a/zebra/netconf_netlink.h b/zebra/netconf_netlink.h new file mode 100644 index 000000000..3f2e7af76 --- /dev/null +++ b/zebra/netconf_netlink.h @@ -0,0 +1,48 @@ +/* + * netconf_netlink.h - netconf interaction with the kernel using + * netlink + * Copyright (C) 2021 Nvidia, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef __NETCONF_NETLINK_H__ +#define __NETCONF_NETLINK_H__ + +#ifdef HAVE_NETLINK /* Netlink-only module */ + +#include "zebra/zebra_ns.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Parse and handle a NETCONF message. */ +extern int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, + int startup); +/* Request info from the host OS. */ +int netlink_request_netconf(int sockfd); + + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_NETLINK */ + +#endif /* NETCONF_NETLINK_H */ diff --git a/zebra/redistribute.c b/zebra/redistribute.c index fdd2c8405..1a28f8cee 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -698,7 +698,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, ng = nexthop_group_new(); copy_nexthops(&ng->nexthop, re->nhe->nhg.nexthop, NULL); - rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre, ng); + rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre, ng, false); return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index c1aeb7f07..c8abfaf02 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -54,8 +54,7 @@ struct rnh { #define ZEBRA_NHT_CONNECTED 0x1 #define ZEBRA_NHT_DELETED 0x2 -#define ZEBRA_NHT_EXACT_MATCH 0x4 -#define ZEBRA_NHT_RESOLVE_VIA_DEFAULT 0x8 +#define ZEBRA_NHT_RESOLVE_VIA_DEFAULT 0x4 /* VRF identifier. */ vrf_id_t vrf_id; @@ -394,13 +393,14 @@ extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, uint32_t flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, - uint32_t mtu, uint8_t distance, route_tag_t tag); + uint32_t mtu, uint8_t distance, route_tag_t tag, + bool startup); /* * Multipath route apis. */ extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re, - struct nexthop_group *ng); + struct nexthop_group *ng, bool startup); /* * -1 -> some sort of error * 0 -> an add @@ -409,7 +409,7 @@ extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re, - struct nhg_hash_entry *nhe); + struct nhg_hash_entry *nhe, bool startup); extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, uint32_t flags, @@ -431,7 +431,7 @@ extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, extern void rib_update(enum rib_update_event event); extern void rib_update_table(struct route_table *table, enum rib_update_event event, int rtype); -extern int rib_sweep_route(struct thread *t); +extern void rib_sweep_route(struct thread *t); extern void rib_sweep_table(struct route_table *table); extern void rib_close_table(struct route_table *table); extern void rib_init(void); diff --git a/zebra/rt.h b/zebra/rt.h index 90148d2c0..5e626928d 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -78,6 +78,10 @@ extern int kernel_interface_set_master(struct interface *master, extern int mpls_kernel_init(void); +/* Global init and deinit for platform-/OS-specific things */ +void kernel_router_init(void); +void kernel_router_terminate(void); + extern uint32_t kernel_get_speed(struct interface *ifp, int *error); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 24c01b7f5..c6423dce9 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -438,6 +438,10 @@ parse_encap_seg6local(struct rtattr *tb, if (tb_encap[SEG6_LOCAL_TABLE]) ctx->table = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_TABLE]); + if (tb_encap[SEG6_LOCAL_VRFTABLE]) + ctx->table = + *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_VRFTABLE]); + return act; } @@ -920,7 +924,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, } rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, &nh, nhe_id, table, metric, mtu, - distance, tag); + distance, tag, startup); } else { /* This is a multipath route */ struct route_entry *re; @@ -964,7 +968,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (nhe_id || ng) rib_add_multipath(afi, SAFI_UNICAST, &p, - &src_p, re, ng); + &src_p, re, ng, startup); else XFREE(MTYPE_RE, re); } @@ -1467,6 +1471,16 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, ctx->table)) return false; break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DT4)) + return false; + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_VRFTABLE, + ctx->table)) + return false; + break; default: zlog_err("%s: unsupport seg6local behaviour action=%u", __func__, @@ -1884,6 +1898,7 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, union g_addr src; const struct prefix *p, *src_p; uint32_t table_id; + struct nlsock *nl; struct { struct nlmsghdr n; @@ -1897,6 +1912,8 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, if (datalen < sizeof(*req)) return 0; + nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); + memset(req, 0, sizeof(*req)); bytelen = (p->family == AF_INET ? 4 : 16); @@ -1910,7 +1927,7 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, req->n.nlmsg_type = cmd; - req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; + req->n.nlmsg_pid = nl->snl.nl_pid; req->r.rtm_family = p->family; req->r.rtm_dst_len = p->prefixlen; @@ -2346,6 +2363,8 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, int type = dplane_ctx_get_nhe_type(ctx); struct rtattr *nest; uint16_t encap; + struct nlsock *nl = + kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); if (!id) { flog_err( @@ -2388,7 +2407,7 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, req->n.nlmsg_flags |= NLM_F_REPLACE; req->n.nlmsg_type = cmd; - req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; + req->n.nlmsg_pid = nl->snl.nl_pid; req->nhm.nh_family = AF_UNSPEC; /* TODO: Scope? */ @@ -2570,6 +2589,18 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, ctx->table)) return 0; break; + case SEG6_LOCAL_ACTION_END_DT4: + if (!nl_attr_put32( + &req->n, buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DT4)) + return 0; + if (!nl_attr_put32( + &req->n, buflen, + SEG6_LOCAL_VRFTABLE, + ctx->table)) + return 0; + break; default: zlog_err("%s: unsupport seg6local behaviour action=%u", __func__, action); @@ -3027,11 +3058,12 @@ int netlink_nexthop_read(struct zebra_ns *zns) * this kernel must support them. */ supports_nh = true; - if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG) zlog_debug("Nexthop objects %ssupported on this kernel", supports_nh ? "" : "not "); + zebra_router_set_supports_nhgs(supports_nh); + return ret; } @@ -4256,6 +4288,8 @@ ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, const char *routedesc; int route_type; struct prefix p = {0}; + struct nlsock *nl = + kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); struct { struct nlmsghdr n; @@ -4298,7 +4332,7 @@ ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req->n.nlmsg_type = cmd; - req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; + req->n.nlmsg_pid = nl->snl.nl_pid; req->r.rtm_family = AF_MPLS; req->r.rtm_table = RT_TABLE_MAIN; diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 93c06e555..0a7977170 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -134,6 +134,8 @@ const char *rtm_rta2str(int type); const char *neigh_rta2str(int type); const char *ifa_rta2str(int type); const char *nhm_rta2str(int type); +const char *frh_rta2str(int type); +const char *frh_action2str(uint8_t action); const char *nlmsg_flags2str(uint16_t flags, char *buf, size_t buflen); const char *if_flags2str(uint32_t flags, char *buf, size_t buflen); const char *rtm_flags2str(uint32_t flags, char *buf, size_t buflen); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 350b97cc5..2ce507294 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -47,6 +47,8 @@ extern struct zebra_privs_t zserv_privs; +static uint32_t interfaces_configured_for_ra_from_bgp; + #if defined(HAVE_RTADV) #ifndef VTYSH_EXTRACT_PL @@ -469,7 +471,7 @@ no_more_opts: zif->ra_sent++; } -static int rtadv_timer(struct thread *thread) +static void rtadv_timer(struct thread *thread) { struct zebra_vrf *zvrf = THREAD_ARG(thread); struct vrf *vrf; @@ -532,8 +534,6 @@ static int rtadv_timer(struct thread *thread) } } } - - return 0; } static void rtadv_process_solicit(struct interface *ifp) @@ -632,45 +632,66 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len, radvert = (struct nd_router_advert *)msg; - if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit) - && (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit)) { +#define SIXHOUR2USEC (int64_t)6 * 60 * 60 * 1000000 + + if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit) && + (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit) && + (monotime_since(&zif->rtadv.lastadvcurhoplimit, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvcurhoplimit.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvcurhoplimit); } - if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) - && !zif->rtadv.AdvManagedFlag) { + if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && + !zif->rtadv.AdvManagedFlag && + (monotime_since(&zif->rtadv.lastadvmanagedflag, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvmanagedflag.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvmanagedflag); } - if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) - && !zif->rtadv.AdvOtherConfigFlag) { + if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && + !zif->rtadv.AdvOtherConfigFlag && + (monotime_since(&zif->rtadv.lastadvotherconfigflag, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvotherconfigflag.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvotherconfigflag); } - if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime) - && (ntohl(radvert->nd_ra_reachable) - != zif->rtadv.AdvReachableTime)) { + if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime) && + (ntohl(radvert->nd_ra_reachable) != zif->rtadv.AdvReachableTime) && + (monotime_since(&zif->rtadv.lastadvreachabletime, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvreachabletime.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvreachabletime); } - if ((ntohl(radvert->nd_ra_retransmit) - != (unsigned int)zif->rtadv.AdvRetransTimer)) { + if ((ntohl(radvert->nd_ra_retransmit) != + (unsigned int)zif->rtadv.AdvRetransTimer) && + (monotime_since(&zif->rtadv.lastadvretranstimer, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvretranstimer.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvretranstimer); } /* Create entry for neighbor if not known. */ @@ -751,7 +772,7 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len, return; } -static int rtadv_read(struct thread *thread) +static void rtadv_read(struct thread *thread) { int sock; int len; @@ -774,12 +795,10 @@ static int rtadv_read(struct thread *thread) flog_err_sys(EC_LIB_SOCKET, "RA/RS recv failed, socket %u error %s", sock, safe_strerror(errno)); - return len; + return; } rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zvrf); - - return 0; } static int rtadv_make_socket(ns_id_t ns_id) @@ -1282,6 +1301,9 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) zif = ifp->info; if (enable) { + if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) + interfaces_configured_for_ra_from_bgp++; + SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED); ipv6_nd_suppress_ra_set(ifp, RA_ENABLE); if (ra_interval @@ -1290,6 +1312,9 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) VTY_RA_INTERVAL_CONFIGURED)) zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000; } else { + if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) + interfaces_configured_for_ra_from_bgp--; + UNSET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED); if (!CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) @@ -2766,6 +2791,8 @@ void rtadv_vrf_terminate(struct zebra_vrf *zvrf) void rtadv_cmd_init(void) { + interfaces_configured_for_ra_from_bgp = 0; + hook_register(zebra_if_extra_info, nd_dump_vty); hook_register(zebra_if_config_wr, rtadv_config_write); @@ -2865,6 +2892,11 @@ static int if_leave_all_router(int sock, struct interface *ifp) return 0; } +bool rtadv_compiled_in(void) +{ + return true; +} + #else void rtadv_vrf_init(struct zebra_vrf *zvrf) { @@ -2920,4 +2952,14 @@ void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS) return; } +bool rtadv_compiled_in(void) +{ + return false; +} + #endif /* HAVE_RTADV */ + +uint32_t rtadv_get_interfaces_configured_from_bgp(void) +{ + return interfaces_configured_for_ra_from_bgp; +} diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 7b71ee45a..a95174b22 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -22,6 +22,7 @@ #ifndef _ZEBRA_RTADV_H #define _ZEBRA_RTADV_H +#include "zebra.h" #include "vty.h" #include "zebra/interface.h" @@ -161,6 +162,8 @@ extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS); extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); extern void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p); extern void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p); +extern uint32_t rtadv_get_interfaces_configured_from_bgp(void); +extern bool rtadv_compiled_in(void); #ifdef __cplusplus } diff --git a/zebra/subdir.am b/zebra/subdir.am index f0cc6ce71..77e0898d8 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -69,6 +69,7 @@ zebra_zebra_SOURCES = \ zebra/kernel_socket.c \ zebra/label_manager.c \ zebra/main.c \ + zebra/netconf_netlink.c \ zebra/redistribute.c \ zebra/router-id.c \ zebra/rt_netlink.c \ @@ -148,6 +149,7 @@ noinst_HEADERS += \ zebra/kernel_netlink.h \ zebra/kernel_socket.h \ zebra/label_manager.h \ + zebra/netconf_netlink.h \ zebra/redistribute.h \ zebra/rib.h \ zebra/router-id.h \ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index b69200d96..1b6f37ec6 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2127,7 +2127,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) nhe.backup_info = bnhg; } ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p, - re, &nhe); + re, &nhe, false); /* * rib_add_multipath_nhe only fails in a couple spots diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index bf34fb54a..6de2be3ab 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -28,6 +28,7 @@ #include "lib/memory.h" #include "lib/queue.h" #include "lib/zebra.h" +#include "zebra/netconf_netlink.h" #include "zebra/zebra_router.h" #include "zebra/zebra_dplane.h" #include "zebra/zebra_vxlan_private.h" @@ -290,6 +291,19 @@ struct dplane_gre_ctx { unsigned int mtu; struct zebra_l2info_gre info; }; + + +/* + * Network interface configuration info - aligned with netlink's NETCONF + * info. The flags values are public, in the dplane.h file... + */ +struct dplane_netconf_info { + ns_id_t ns_id; + ifindex_t ifindex; + enum dplane_netconf_status_e mpls_val; + enum dplane_netconf_status_e mcast_val; +}; + /* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the @@ -347,6 +361,7 @@ struct zebra_dplane_ctx { } ipset_entry; struct dplane_neigh_table neightable; struct dplane_gre_ctx gre; + struct dplane_netconf_info netconf; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -416,6 +431,9 @@ PREDECL_DLIST(zns_info_list); struct dplane_zns_info { struct zebra_dplane_info info; + /* Request data from the OS */ + struct thread *t_request; + /* Read event */ struct thread *t_read; @@ -539,9 +557,7 @@ DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link); #define DPLANE_PROV_UNLOCK(p) pthread_mutex_unlock(&((p)->dp_mutex)) /* Prototypes */ -static int dplane_thread_loop(struct thread *event); -static void dplane_info_from_zns(struct zebra_dplane_info *ns_info, - struct zebra_ns *zns); +static void dplane_thread_loop(struct thread *event); static enum zebra_dplane_result lsp_update_internal(struct zebra_lsp *lsp, enum dplane_op_e op); static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw, @@ -722,7 +738,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) /* Maybe free label string, if allocated */ if (ctx->u.intf.label != NULL && ctx->u.intf.label != ctx->u.intf.label_buf) { - free(ctx->u.intf.label); + XFREE(MTYPE_DP_CTX, ctx->u.intf.label); ctx->u.intf.label = NULL; } break; @@ -769,6 +785,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) } break; case DPLANE_OP_GRE_SET: + case DPLANE_OP_INTF_NETCONFIG: break; } } @@ -833,6 +850,13 @@ void dplane_ctx_list_append(struct dplane_ctx_q *to_list, } } +struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_q *q) +{ + struct zebra_dplane_ctx *ctx = TAILQ_FIRST(q); + + return ctx; +} + /* Dequeue a context block from the head of a list */ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_q *q) { @@ -1046,6 +1070,9 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_INTF_ADDR_DEL: return "INTF_ADDR_DEL"; + + case DPLANE_OP_INTF_NETCONFIG: + return "INTF_NETCONFIG"; } return ret; @@ -1458,6 +1485,17 @@ const struct zebra_dplane_info *dplane_ctx_get_ns( return &(ctx->zd_ns_info); } +int dplane_ctx_get_ns_sock(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + +#ifdef HAVE_NETLINK + return ctx->zd_ns_info.sock; +#else + return -1; +#endif +} + /* Accessors for nexthop information */ uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx) { @@ -1836,7 +1874,7 @@ void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label) DPLANE_CTX_VALID(ctx); if (ctx->u.intf.label && ctx->u.intf.label != ctx->u.intf.label_buf) - free(ctx->u.intf.label); + XFREE(MTYPE_DP_CTX, ctx->u.intf.label); ctx->u.intf.label = NULL; @@ -1851,7 +1889,7 @@ void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label) sizeof(ctx->u.intf.label_buf)); ctx->u.intf.label = ctx->u.intf.label_buf; } else { - ctx->u.intf.label = strdup(label); + ctx->u.intf.label = XSTRDUP(MTYPE_DP_CTX, label); } } else { ctx->u.intf.flags &= ~DPLANE_INTF_HAS_LABEL; @@ -2221,6 +2259,10 @@ uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr) return ptr->status; } +/* + * End of interface extra info accessors + */ + uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2252,9 +2294,66 @@ dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx) return ctx->u.neightable.mcast_probes; } -/* - * End of interface extra info accessors - */ +ifindex_t dplane_ctx_get_netconf_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.netconf.ifindex; +} + +ns_id_t dplane_ctx_get_netconf_ns_id(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.netconf.ns_id; +} + +void dplane_ctx_set_netconf_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t ifindex) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.netconf.ifindex = ifindex; +} + +void dplane_ctx_set_netconf_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t ns_id) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.netconf.ns_id = ns_id; +} + +enum dplane_netconf_status_e +dplane_ctx_get_netconf_mpls(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.netconf.mpls_val; +} + +enum dplane_netconf_status_e +dplane_ctx_get_netconf_mcast(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.netconf.mcast_val; +} + +void dplane_ctx_set_netconf_mpls(struct zebra_dplane_ctx *ctx, + enum dplane_netconf_status_e val) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.netconf.mpls_val = val; +} + +void dplane_ctx_set_netconf_mcast(struct zebra_dplane_ctx *ctx, + enum dplane_netconf_status_e val) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.netconf.mcast_val = val; +} /* * Retrieve the limit on the number of pending, unprocessed updates. @@ -2287,6 +2386,22 @@ uint32_t dplane_get_in_queue_len(void) memory_order_seq_cst); } +/* + * Internal helper that copies information from a zebra ns object; this is + * called in the zebra main pthread context as part of dplane ctx init. + */ +static void ctx_info_from_zns(struct zebra_dplane_info *ns_info, + struct zebra_ns *zns) +{ + ns_info->ns_id = zns->ns_id; + +#if defined(HAVE_NETLINK) + ns_info->is_cmd = true; + ns_info->sock = zns->netlink_dplane_out.sock; + ns_info->seq = zns->netlink_dplane_out.seq; +#endif /* NETLINK */ +} + /* * Common dataplane context init with zebra namespace info. */ @@ -2294,7 +2409,9 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx, struct zebra_ns *zns, bool is_update) { - dplane_info_from_zns(&(ctx->zd_ns_info), zns); + ctx_info_from_zns(&(ctx->zd_ns_info), zns); /* */ + + ctx->zd_is_update = is_update; #if defined(HAVE_NETLINK) /* Increment message counter after copying to context struct - may need @@ -2514,7 +2631,6 @@ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, * it probably won't require two messages */ dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE)); - ctx->zd_is_update = (op == DPLANE_OP_NH_UPDATE); ret = AOK; @@ -2537,7 +2653,6 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, /* Capture namespace info */ dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), (op == DPLANE_OP_LSP_UPDATE)); - ctx->zd_is_update = (op == DPLANE_OP_LSP_UPDATE); memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp)); @@ -2813,7 +2928,6 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx, dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), op == DPLANE_OP_RULE_UPDATE); - ctx->zd_is_update = (op == DPLANE_OP_RULE_UPDATE); ctx->zd_vrf_id = new_rule->vrf_id; strlcpy(ctx->zd_ifname, new_rule->ifname, sizeof(ctx->zd_ifname)); @@ -2859,7 +2973,6 @@ static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx, ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); - ctx->zd_is_update = false; ctx->zd_vrf_id = iptable->vrf_id; memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable)); @@ -2899,7 +3012,6 @@ static int dplane_ctx_ipset_init(struct zebra_dplane_ctx *ctx, ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); - ctx->zd_is_update = false; ctx->zd_vrf_id = ipset->vrf_id; @@ -2934,7 +3046,6 @@ dplane_ctx_ipset_entry_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); - ctx->zd_is_update = false; ctx->zd_vrf_id = ipset->vrf_id; @@ -3015,7 +3126,6 @@ dplane_route_update_internal(struct route_node *rn, */ if ((op == DPLANE_OP_ROUTE_UPDATE) && old_re && (old_re != re)) { - ctx->zd_is_update = true; old_re->dplane_sequence = zebra_router_get_next_sequence(); @@ -3692,7 +3802,7 @@ static enum zebra_dplane_result intf_addr_update_internal( sizeof(ctx->u.intf.label_buf)); ctx->u.intf.label = ctx->u.intf.label_buf; } else { - ctx->u.intf.label = strdup(ifc->label); + ctx->u.intf.label = XSTRDUP(MTYPE_DP_CTX, ifc->label); } } @@ -4831,27 +4941,12 @@ bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov) return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED); } -/* - * Internal helper that copies information from a zebra ns object; this is - * called in the zebra main pthread context as part of dplane ctx init. - */ -static void dplane_info_from_zns(struct zebra_dplane_info *ns_info, - struct zebra_ns *zns) -{ - ns_info->ns_id = zns->ns_id; - -#if defined(HAVE_NETLINK) - ns_info->is_cmd = true; - ns_info->nls = zns->netlink_dplane_out; -#endif /* NETLINK */ -} - #ifdef HAVE_NETLINK /* * Callback when an OS (netlink) incoming event read is ready. This runs * in the dplane pthread. */ -static int dplane_incoming_read(struct thread *event) +static void dplane_incoming_read(struct thread *event) { struct dplane_zns_info *zi = THREAD_ARG(event); @@ -4859,10 +4954,42 @@ static int dplane_incoming_read(struct thread *event) /* Re-start read task */ thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi, - zi->info.nls.sock, &zi->t_read); + zi->info.sock, &zi->t_read); +} - return 0; +/* + * Callback in the dataplane pthread that requests info from the OS and + * initiates netlink reads. + */ +static void dplane_incoming_request(struct thread *event) +{ + struct dplane_zns_info *zi = THREAD_ARG(event); + + /* Start read task */ + thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi, + zi->info.sock, &zi->t_read); + + /* Send requests */ + netlink_request_netconf(zi->info.sock); +} + +/* + * Initiate requests for existing info from the OS. This is called by the + * main pthread, but we want all activity on the dplane netlink socket to + * take place on the dplane pthread, so we schedule an event to accomplish + * that. + */ +static void dplane_kernel_info_request(struct dplane_zns_info *zi) +{ + /* If we happen to encounter an enabled zns before the dplane + * pthread is running, we'll initiate this later on. + */ + if (zdplane_info.dg_master) + thread_add_event(zdplane_info.dg_master, + dplane_incoming_request, zi, 0, + &zi->t_request); } + #endif /* HAVE_NETLINK */ /* @@ -4904,13 +5031,12 @@ void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled) /* Make sure we're up-to-date with the zns object */ #if defined(HAVE_NETLINK) zi->info.is_cmd = false; - zi->info.nls = zns->netlink_dplane_in; + zi->info.sock = zns->netlink_dplane_in.sock; - /* Start read task for the dplane pthread. */ - if (zdplane_info.dg_master) - thread_add_read(zdplane_info.dg_master, - dplane_incoming_read, zi, - zi->info.nls.sock, &zi->t_read); + /* Initiate requests for existing info from the OS, and + * begin reading from the netlink socket. + */ + dplane_kernel_info_request(zi); #endif } else if (zi) { if (IS_ZEBRA_DEBUG_DPLANE) @@ -4920,9 +5046,14 @@ void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled) /* Stop reading, free memory */ zns_info_list_del(&zdplane_info.dg_zns_list, zi); - if (zdplane_info.dg_master) + /* Stop any outstanding tasks */ + if (zdplane_info.dg_master) { + thread_cancel_async(zdplane_info.dg_master, + &zi->t_request, NULL); + thread_cancel_async(zdplane_info.dg_master, &zi->t_read, NULL); + } XFREE(MTYPE_DP_NS, zi); } @@ -5102,6 +5233,14 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_ctx_get_ifname(ctx), dplane_ctx_get_intf_addr(ctx)); break; + + case DPLANE_OP_INTF_NETCONFIG: + zlog_debug("%s: ifindex %d, mpls %d, mcast %d", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_netconf_ifindex(ctx), + dplane_ctx_get_netconf_mpls(ctx), + dplane_ctx_get_netconf_mcast(ctx)); + break; } } @@ -5247,6 +5386,7 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) /* TODO -- error counters for incoming events? */ case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: break; case DPLANE_OP_NONE: @@ -5582,7 +5722,7 @@ done: * final zebra shutdown. * This runs in the dplane pthread context. */ -static int dplane_check_shutdown_status(struct thread *event) +static void dplane_check_shutdown_status(struct thread *event) { struct dplane_zns_info *zi; @@ -5593,8 +5733,10 @@ static int dplane_check_shutdown_status(struct thread *event) frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) { zns_info_list_del(&zdplane_info.dg_zns_list, zi); - if (zdplane_info.dg_master) + if (zdplane_info.dg_master) { thread_cancel(&zi->t_read); + thread_cancel(&zi->t_request); + } XFREE(MTYPE_DP_NS, zi); } @@ -5614,8 +5756,6 @@ static int dplane_check_shutdown_status(struct thread *event) */ thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL); } - - return 0; } /* @@ -5649,7 +5789,7 @@ void zebra_dplane_finish(void) * pthread can look for other pending work - such as i/o work on behalf of * providers. */ -static int dplane_thread_loop(struct thread *event) +static void dplane_thread_loop(struct thread *event) { struct dplane_ctx_q work_list; struct dplane_ctx_q error_list; @@ -5669,7 +5809,7 @@ static int dplane_thread_loop(struct thread *event) /* Check for zebra shutdown */ if (!zdplane_info.dg_run) - goto done; + return; /* Dequeue some incoming work from zebra (if any) onto the temporary * working list. @@ -5835,9 +5975,6 @@ static int dplane_thread_loop(struct thread *event) (zdplane_info.dg_results_cb)(&work_list); TAILQ_INIT(&work_list); - -done: - return 0; } /* @@ -5929,11 +6066,12 @@ void zebra_dplane_start(void) thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0, &zdplane_info.dg_t_update); - /* Enqueue reads if necessary */ + /* Enqueue requests and reads if necessary */ frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) { #if defined(HAVE_NETLINK) thread_add_read(zdplane_info.dg_master, dplane_incoming_read, - zi, zi->info.nls.sock, &zi->t_read); + zi, zi->info.sock, &zi->t_read); + dplane_kernel_info_request(zi); #endif } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 977f00bd2..29555d5b5 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -41,7 +41,8 @@ struct zebra_dplane_info { ns_id_t ns_id; #if defined(HAVE_NETLINK) - struct nlsock nls; + int sock; + int seq; bool is_cmd; #endif }; @@ -56,9 +57,11 @@ zebra_dplane_info_from_zns(struct zebra_dplane_info *zns_info, #if defined(HAVE_NETLINK) zns_info->is_cmd = is_cmd; if (is_cmd) { - zns_info->nls = zns->netlink_cmd; + zns_info->sock = zns->netlink_cmd.sock; + zns_info->seq = zns->netlink_cmd.seq; } else { - zns_info->nls = zns->netlink; + zns_info->sock = zns->netlink.sock; + zns_info->seq = zns->netlink.seq; } #endif /* NETLINK */ } @@ -182,6 +185,9 @@ enum dplane_op_e { /* Incoming interface address events */ DPLANE_OP_INTF_ADDR_ADD, DPLANE_OP_INTF_ADDR_DEL, + + /* Incoming interface config events */ + DPLANE_OP_INTF_NETCONFIG, }; /* @@ -219,6 +225,22 @@ enum dplane_op_e { #define DPLANE_BR_PORT_NON_DF (1 << 0) +/* Definitions for the dplane 'netconf' apis, corresponding to the netlink + * NETCONF api. + * Sadly, netlink sends incremental updates, so its messages may contain + * just a single changed attribute, and not necessarily + * a complete snapshot of the attributes. + */ +enum dplane_netconf_status_e { + DPLANE_NETCONF_STATUS_UNKNOWN = 0, + DPLANE_NETCONF_STATUS_ENABLED, + DPLANE_NETCONF_STATUS_DISABLED +}; + +/* Some special ifindex values that may be part of the dplane netconf api. */ +#define DPLANE_NETCONF_IFINDEX_ALL -1 +#define DPLANE_NETCONF_IFINDEX_DEFAULT -2 + /* Enable system route notifications */ void dplane_enable_sys_route_notifs(void); @@ -274,6 +296,7 @@ void dplane_ctx_list_append(struct dplane_ctx_q *to_list, /* Dequeue a context block from the head of caller's tailq */ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_q *q); +struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_q *q); /* * Accessors for information from the context object @@ -560,9 +583,25 @@ dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx); const struct zebra_l2info_gre * dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx); -/* Namespace info - esp. for netlink communication */ +/* Interface netconf info */ +ifindex_t dplane_ctx_get_netconf_ifindex(const struct zebra_dplane_ctx *ctx); +ns_id_t dplane_ctx_get_netconf_ns_id(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_netconf_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t ifindex); +void dplane_ctx_set_netconf_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t ns_id); +enum dplane_netconf_status_e +dplane_ctx_get_netconf_mpls(const struct zebra_dplane_ctx *ctx); +enum dplane_netconf_status_e +dplane_ctx_get_netconf_mcast(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_netconf_mpls(struct zebra_dplane_ctx *ctx, + enum dplane_netconf_status_e val); +void dplane_ctx_set_netconf_mcast(struct zebra_dplane_ctx *ctx, + enum dplane_netconf_status_e val); + +/* Namespace fd info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( const struct zebra_dplane_ctx *ctx); +int dplane_ctx_get_ns_sock(const struct zebra_dplane_ctx *ctx); /* Indicates zebra shutdown/exit is in progress. Some operations may be * simplified or skipped during shutdown processing. diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 13b9cc200..21fb5299b 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -344,10 +344,10 @@ int zebra_evpn_add_macip_for_intf(struct interface *ifp, for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { struct ipaddr ip; - memset(&ip, 0, sizeof(struct ipaddr)); if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) continue; + memset(&ip, 0, sizeof(struct ipaddr)); if (c->address->family == AF_INET) { ip.ipa_type = IPADDR_V4; memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index d3791f3e5..74043e521 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -383,7 +383,7 @@ static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *buf, return buf; } -static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) +static void zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) { struct zebra_vrf *zvrf = NULL; struct zebra_mac *mac = NULL; @@ -396,15 +396,15 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) /* since this is asynchronous we need sanity checks*/ zvrf = vrf_info_lookup(mac->zevpn->vrf_id); if (!zvrf) - return 0; + return; zevpn = zebra_evpn_lookup(mac->zevpn->vni); if (!zevpn) - return 0; + return; mac = zebra_evpn_mac_lookup(zevpn, &mac->macaddr); if (!mac) - return 0; + return; if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; @@ -445,7 +445,7 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr, mac->flags, mac->loc_seq, mac->es)) - return -1; + return; /* Process all neighbors associated with this MAC. */ zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, @@ -457,8 +457,6 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) /* Install the entry. */ zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */); } - - return 0; } static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, @@ -1143,14 +1141,6 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) sizeof(mac_buf))); } - /* If the MAC is freed before the neigh we will end up - * with a stale pointer against the neigh - */ - if (!list_isempty(mac->neigh_list)) - zlog_warn("%s: MAC %pEA flags 0x%x neigh list not empty %d", - __func__, &mac->macaddr, mac->flags, - listcount(mac->neigh_list)); - /* force de-ref any ES entry linked to the MAC */ zebra_evpn_es_mac_deref_entry(mac); @@ -1163,6 +1153,26 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) /* Cancel auto recovery */ THREAD_OFF(mac->dad_mac_auto_recovery_timer); + /* If the MAC is freed before the neigh we will end up + * with a stale pointer against the neigh. + * The situation can arise when a MAC is in remote state + * and its associated neigh is local state. + * zebra_evpn_cfg_cleanup() cleans up remote neighs and MACs. + * Instead of deleting remote MAC, if its neigh list is non-empty + * (associated to local neighs), mark the MAC as AUTO. + */ + if (!list_isempty(mac->neigh_list)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list " + "count %u, mark MAC as AUTO", + &mac->macaddr, mac->flags, zevpn->vni, + listcount(mac->neigh_list)); + + SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + return 0; + } + list_delete(&mac->neigh_list); /* Free the VNI hash entry and allocated memory. */ @@ -1470,7 +1480,7 @@ void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac, * external neighmgr daemon to probe existing hosts to independently * establish their presence on the ES. */ -static int zebra_evpn_mac_hold_exp_cb(struct thread *t) +static void zebra_evpn_mac_hold_exp_cb(struct thread *t) { struct zebra_mac *mac; bool old_bgp_ready; @@ -1483,7 +1493,7 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t) * flag */ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) - return 0; + return; old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); old_static = zebra_evpn_mac_is_static(mac); @@ -1514,8 +1524,6 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t) if (old_bgp_ready != new_bgp_ready) zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); - - return 0; } static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac) diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index af4629e41..50eecd31d 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -2131,7 +2131,7 @@ static void zebra_evpn_mh_advertise_svi_mac(void) zebra_evpn_acc_vl_adv_svi_mac_all(); } -static int zebra_evpn_es_df_delay_exp_cb(struct thread *t) +static void zebra_evpn_es_df_delay_exp_cb(struct thread *t) { struct zebra_evpn_es *es; @@ -2141,8 +2141,6 @@ static int zebra_evpn_es_df_delay_exp_cb(struct thread *t) zlog_debug("es %s df-delay expired", es->esi_str); zebra_evpn_es_run_df_election(es, __func__); - - return 0; } /* currently there is no global config to turn on MH instead we use @@ -3860,15 +3858,13 @@ void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif) new_protodown); } -static int zebra_evpn_mh_startup_delay_exp_cb(struct thread *t) +static void zebra_evpn_mh_startup_delay_exp_cb(struct thread *t) { if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("startup-delay expired"); zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, false /* set */); - - return 0; } static void zebra_evpn_mh_startup_delay_timer_start(const char *rc) diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 7299391ef..ed224151b 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -72,7 +72,7 @@ static bool neigh_cmp(const void *p1, const void *p2) if (n1 == NULL || n2 == NULL) return false; - return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0); + return ipaddr_cmp(&n1->ip, &n2->ip) == 0; } int neigh_list_cmp(void *p1, void *p2) @@ -80,7 +80,7 @@ int neigh_list_cmp(void *p1, void *p2) const struct zebra_neigh *n1 = p1; const struct zebra_neigh *n2 = p2; - return memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)); + return ipaddr_cmp(&n1->ip, &n2->ip); } struct hash *zebra_neigh_db_create(const char *desc) @@ -411,7 +411,7 @@ void zebra_evpn_sync_neigh_static_chg(struct zebra_neigh *n, bool old_n_static, * external neighmgr daemon to probe existing hosts to independently * establish their presence on the ES. */ -static int zebra_evpn_neigh_hold_exp_cb(struct thread *t) +static void zebra_evpn_neigh_hold_exp_cb(struct thread *t) { struct zebra_neigh *n; bool old_bgp_ready; @@ -424,7 +424,7 @@ static int zebra_evpn_neigh_hold_exp_cb(struct thread *t) * flag */ if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) - return 0; + return; old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); old_n_static = zebra_evpn_neigh_is_static(n); @@ -448,8 +448,6 @@ static int zebra_evpn_neigh_hold_exp_cb(struct thread *t) if (old_bgp_ready != new_bgp_ready) zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready, new_bgp_ready); - - return 0; } static inline void zebra_evpn_neigh_start_hold_timer(struct zebra_neigh *n) @@ -1092,7 +1090,7 @@ static int zebra_evpn_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf, return 0; } -static int zebra_evpn_dad_ip_auto_recovery_exp(struct thread *t) +static void zebra_evpn_dad_ip_auto_recovery_exp(struct thread *t) { struct zebra_vrf *zvrf = NULL; struct zebra_neigh *nbr = NULL; @@ -1103,15 +1101,15 @@ static int zebra_evpn_dad_ip_auto_recovery_exp(struct thread *t) /* since this is asynchronous we need sanity checks*/ zvrf = vrf_info_lookup(nbr->zevpn->vrf_id); if (!zvrf) - return 0; + return; zevpn = zebra_evpn_lookup(nbr->zevpn->vni); if (!zevpn) - return 0; + return; nbr = zebra_evpn_neigh_lookup(zevpn, &nbr->ip); if (!nbr) - return 0; + return; if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( @@ -1135,8 +1133,6 @@ static int zebra_evpn_dad_ip_auto_recovery_exp(struct thread *t) } else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) { zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/); } - - return 0; } static void zebra_evpn_dup_addr_detect_for_neigh( @@ -1315,14 +1311,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, if (!n) { /* New neighbor - create */ n = zebra_evpn_neigh_add(zevpn, ip, macaddr, zmac, 0); - if (!n) { - flog_err( - EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add neighbor %pIA MAC %pEA intf %s(%u) -> VNI %u", - ip, macaddr, ifp->name, ifp->ifindex, - zevpn->vni); - return -1; - } + /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); n->ifindex = ifp->ifindex; @@ -2074,14 +2063,6 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn, if (!n) { n = zebra_evpn_neigh_add(zevpn, ipaddr, &mac->macaddr, mac, 0); - if (!n) { - zlog_warn( - "Failed to add Neigh %pIA MAC %pEA VNI %u Remote VTEP %pI4", - ipaddr, &mac->macaddr, zevpn->vni, - &vtep_ip); - return; - } - } else { /* When host moves but changes its (MAC,IP) * binding, BGP may install a MACIP entry that @@ -2186,17 +2167,8 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, assert(mac); n = zebra_evpn_neigh_lookup(zevpn, ip); - if (!n) { + if (!n) n = zebra_evpn_neigh_add(zevpn, ip, &mac->macaddr, mac, 0); - if (!n) { - flog_err( - EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add neighbor %pIA MAC %pEA intf %s(%u) -> VNI %u", - ip, &mac->macaddr, - ifp->name, ifp->ifindex, zevpn->vni); - return -1; - } - } /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); @@ -2207,7 +2179,6 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, /* Only advertise in BGP if the knob is enabled */ if (advertise_gw_macip_enabled(zevpn)) { - SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW); /* Set Router flag (R-bit) */ if (ip->ipa_type == IPADDR_V6) diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 43958fdfd..6766c752a 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -284,8 +284,8 @@ static struct zfpm_glob *zfpm_g = &zfpm_glob_space; static int zfpm_trigger_update(struct route_node *rn, const char *reason); -static int zfpm_read_cb(struct thread *thread); -static int zfpm_write_cb(struct thread *thread); +static void zfpm_read_cb(struct thread *thread); +static void zfpm_write_cb(struct thread *thread); static void zfpm_set_state(enum zfpm_state state, const char *reason); static void zfpm_start_connect_timer(const char *reason); @@ -518,7 +518,7 @@ static inline void zfpm_connect_off(void) * Callback for actions to be taken when the connection to the FPM * comes up. */ -static int zfpm_conn_up_thread_cb(struct thread *thread) +static void zfpm_conn_up_thread_cb(struct thread *thread) { struct route_node *rnode; struct zfpm_rnodes_iter *iter; @@ -559,14 +559,13 @@ static int zfpm_conn_up_thread_cb(struct thread *thread) zfpm_rnodes_iter_pause(iter); thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb, NULL, 0, &zfpm_g->t_conn_up); - return 0; + return; } zfpm_g->stats.t_conn_up_finishes++; done: zfpm_rnodes_iter_cleanup(iter); - return 0; } /* @@ -635,7 +634,7 @@ static void zfpm_connect_check(void) * Callback that is invoked to clean up state after the TCP connection * to the FPM goes down. */ -static int zfpm_conn_down_thread_cb(struct thread *thread) +static void zfpm_conn_down_thread_cb(struct thread *thread) { struct route_node *rnode; struct zfpm_rnodes_iter *iter; @@ -686,7 +685,7 @@ static int zfpm_conn_down_thread_cb(struct thread *thread) zfpm_g->t_conn_down = NULL; thread_add_timer_msec(zfpm_g->master, zfpm_conn_down_thread_cb, NULL, 0, &zfpm_g->t_conn_down); - return 0; + return; } zfpm_g->stats.t_conn_down_finishes++; @@ -696,7 +695,6 @@ static int zfpm_conn_down_thread_cb(struct thread *thread) * Start the process of connecting to the FPM again. */ zfpm_start_connect_timer("cleanup complete"); - return 0; } /* @@ -740,7 +738,7 @@ static void zfpm_connection_down(const char *detail) /* * zfpm_read_cb */ -static int zfpm_read_cb(struct thread *thread) +static void zfpm_read_cb(struct thread *thread) { size_t already; struct stream *ibuf; @@ -754,7 +752,7 @@ static int zfpm_read_cb(struct thread *thread) */ if (zfpm_g->state == ZFPM_STATE_CONNECTING) { zfpm_connect_check(); - return 0; + return; } assert(zfpm_g->state == ZFPM_STATE_ESTABLISHED); @@ -778,7 +776,7 @@ static int zfpm_read_cb(struct thread *thread) zfpm_connection_down(buffer); } else zfpm_connection_down("closed socket in read"); - return 0; + return; } if (nbyte != (ssize_t)(FPM_MSG_HDR_LEN - already)) @@ -793,7 +791,7 @@ static int zfpm_read_cb(struct thread *thread) if (!fpm_msg_hdr_ok(hdr)) { zfpm_connection_down("invalid message header"); - return 0; + return; } msg_len = fpm_msg_len(hdr); @@ -816,7 +814,7 @@ static int zfpm_read_cb(struct thread *thread) zfpm_connection_down(buffer); } else zfpm_connection_down("failed to read message"); - return 0; + return; } if (nbyte != (ssize_t)(msg_len - already)) @@ -830,7 +828,6 @@ static int zfpm_read_cb(struct thread *thread) done: zfpm_read_on(); - return 0; } static bool zfpm_updates_pending(void) @@ -1171,7 +1168,7 @@ static void zfpm_build_updates(void) /* * zfpm_write_cb */ -static int zfpm_write_cb(struct thread *thread) +static void zfpm_write_cb(struct thread *thread) { struct stream *s; int num_writes; @@ -1183,7 +1180,7 @@ static int zfpm_write_cb(struct thread *thread) */ if (zfpm_g->state == ZFPM_STATE_CONNECTING) { zfpm_connect_check(); - return 0; + return; } assert(zfpm_g->state == ZFPM_STATE_ESTABLISHED); @@ -1217,7 +1214,7 @@ static int zfpm_write_cb(struct thread *thread) break; zfpm_connection_down("failed to write to socket"); - return 0; + return; } if (bytes_written != bytes_to_write) { @@ -1248,14 +1245,12 @@ static int zfpm_write_cb(struct thread *thread) if (zfpm_writes_pending()) zfpm_write_on(); - - return 0; } /* * zfpm_connect_cb */ -static int zfpm_connect_cb(struct thread *t) +static void zfpm_connect_cb(struct thread *t) { int sock, ret; struct sockaddr_in serv; @@ -1267,7 +1262,7 @@ static int zfpm_connect_cb(struct thread *t) zlog_err("Failed to create socket for connect(): %s", strerror(errno)); zfpm_g->stats.connect_no_sock++; - return 0; + return; } set_nonblocking(sock); @@ -1295,7 +1290,7 @@ static int zfpm_connect_cb(struct thread *t) if (ret >= 0) { zfpm_g->sock = sock; zfpm_connection_up("connect succeeded"); - return 1; + return; } if (errno == EINPROGRESS) { @@ -1304,7 +1299,7 @@ static int zfpm_connect_cb(struct thread *t) zfpm_write_on(); zfpm_set_state(ZFPM_STATE_CONNECTING, "async connect in progress"); - return 0; + return; } zlog_info("can't connect to FPM %d: %s", sock, safe_strerror(errno)); @@ -1314,7 +1309,6 @@ static int zfpm_connect_cb(struct thread *t) * Restart timer for retrying connection. */ zfpm_start_connect_timer("connect() failed"); - return 0; } /* @@ -1663,7 +1657,7 @@ static void zfpm_iterate_rmac_table(struct hash_bucket *bucket, void *args) /* * struct zfpm_statsimer_cb */ -static int zfpm_stats_timer_cb(struct thread *t) +static void zfpm_stats_timer_cb(struct thread *t) { zfpm_g->t_stats = NULL; @@ -1685,8 +1679,6 @@ static int zfpm_stats_timer_cb(struct thread *t) zfpm_stats_reset(&zfpm_g->stats); zfpm_start_stats_timer(); - - return 0; } /* diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 168e36ac9..ec22c5dd4 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -116,6 +116,8 @@ struct fpm_nh_encap_info_t { * data structures for convenience. */ struct netlink_nh_info { + /* Weight of the nexthop ( for unequal cost ECMP ) */ + uint8_t weight; uint32_t if_index; union g_addr *gateway; @@ -179,6 +181,7 @@ static int netlink_route_info_add_nh(struct netlink_route_info *ri, nhi.recursive = nexthop->rparent ? 1 : 0; nhi.type = nexthop->type; nhi.if_index = nexthop->ifindex; + nhi.weight = nexthop->weight; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { @@ -480,6 +483,8 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, rtnh->rtnh_ifindex = nhi->if_index; } + rtnh->rtnh_hops = nhi->weight; + encap = nhi->encap_info.encap_type; switch (encap) { case FPM_NH_ENCAP_NONE: diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index b153ac1d8..56d0df569 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -51,7 +51,7 @@ * Forward declaration. */ static struct zserv *zebra_gr_find_stale_client(struct zserv *client); -static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread); +static void zebra_gr_route_stale_delete_timer_expiry(struct thread *thread); static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info); static void zebra_gr_process_client_stale_routes(struct zserv *client, vrf_id_t vrf_id); @@ -444,7 +444,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) * Delete all the stale routes that have not been refreshed * post restart. */ -static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread) +static void zebra_gr_route_stale_delete_timer_expiry(struct thread *thread) { struct client_gr_info *info; int32_t cnt = 0; @@ -478,7 +478,6 @@ static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread) info->current_afi = 0; zebra_gr_delete_stale_client(info); } - return 0; } diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c index 40a2c94e2..2042f9403 100644 --- a/zebra/zebra_mlag.c +++ b/zebra/zebra_mlag.c @@ -52,8 +52,8 @@ uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT]; static bool test_mlag_in_progress; static int zebra_mlag_signal_write_thread(void); -static int zebra_mlag_terminate_pthread(struct thread *event); -static int zebra_mlag_post_data_from_main_thread(struct thread *thread); +static void zebra_mlag_terminate_pthread(struct thread *event); +static void zebra_mlag_post_data_from_main_thread(struct thread *thread); static void zebra_mlag_publish_process_state(struct zserv *client, zebra_message_types_t msg_type); @@ -148,7 +148,7 @@ void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len) * This thread reads the clients data from the Global queue and encodes with * protobuf and pass on to the MLAG socket. */ -static int zebra_mlag_client_msg_handler(struct thread *event) +static void zebra_mlag_client_msg_handler(struct thread *event) { struct stream *s; uint32_t wr_count = 0; @@ -209,7 +209,6 @@ static int zebra_mlag_client_msg_handler(struct thread *event) */ if (wr_count >= ZEBRA_MLAG_POST_LIMIT) zebra_mlag_signal_write_thread(); - return 0; } /* @@ -309,7 +308,7 @@ static void zebra_mlag_publish_process_state(struct zserv *client, * main thread, because for that access was needed for clients list. * so instead of forcing the locks, messages will be posted from main thread. */ -static int zebra_mlag_post_data_from_main_thread(struct thread *thread) +static void zebra_mlag_post_data_from_main_thread(struct thread *thread) { struct stream *s = THREAD_ARG(thread); struct stream *zebra_s = NULL; @@ -319,7 +318,7 @@ static int zebra_mlag_post_data_from_main_thread(struct thread *thread) uint32_t msg_len = 0; if (!s) - return -1; + return; STREAM_GETL(s, msg_type); if (IS_ZEBRA_DEBUG_MLAG) @@ -356,12 +355,11 @@ static int zebra_mlag_post_data_from_main_thread(struct thread *thread) } stream_free(s); - return 0; + return; stream_failure: stream_free(s); if (zebra_s) stream_free(zebra_s); - return 0; } /* @@ -394,7 +392,7 @@ static void zebra_mlag_spawn_pthread(void) * all clients are un-registered for MLAG Updates, terminate the * MLAG write thread */ -static int zebra_mlag_terminate_pthread(struct thread *event) +static void zebra_mlag_terminate_pthread(struct thread *event) { if (IS_ZEBRA_DEBUG_MLAG) zlog_debug("Zebra MLAG write thread terminate called"); @@ -403,7 +401,7 @@ static int zebra_mlag_terminate_pthread(struct thread *event) if (IS_ZEBRA_DEBUG_MLAG) zlog_debug( "Zebra MLAG: still some clients are interested"); - return 0; + return; } frr_pthread_stop(zrouter.mlag_info.zebra_pth_mlag, NULL); @@ -419,7 +417,6 @@ static int zebra_mlag_terminate_pthread(struct thread *event) * Send Notification to clean private data */ hook_call(zebra_mlag_private_cleanup_data); - return 0; } /* diff --git a/zebra/zebra_mlag_private.c b/zebra/zebra_mlag_private.c index b1bba831d..50a290b9e 100644 --- a/zebra/zebra_mlag_private.c +++ b/zebra/zebra_mlag_private.c @@ -48,8 +48,8 @@ static struct thread_master *zmlag_master; static int mlag_socket; -static int zebra_mlag_connect(struct thread *thread); -static int zebra_mlag_read(struct thread *thread); +static void zebra_mlag_connect(struct thread *thread); +static void zebra_mlag_read(struct thread *thread); /* * Write the data to MLAGD @@ -72,7 +72,7 @@ static void zebra_mlag_sched_read(void) &zrouter.mlag_info.t_read); } -static int zebra_mlag_read(struct thread *thread) +static void zebra_mlag_read(struct thread *thread) { static uint32_t mlag_rd_buf_offset; uint32_t *msglen; @@ -98,13 +98,13 @@ static int zebra_mlag_read(struct thread *thread) mlag_socket); close(mlag_socket); zebra_mlag_handle_process_state(MLAG_DOWN); - return -1; + return; } mlag_rd_buf_offset += data_len; if (data_len != (ssize_t)(ZEBRA_MLAG_LEN_SIZE - curr_len)) { /* Try again later */ zebra_mlag_sched_read(); - return 0; + return; } curr_len = ZEBRA_MLAG_LEN_SIZE; } @@ -136,13 +136,13 @@ static int zebra_mlag_read(struct thread *thread) mlag_socket); close(mlag_socket); zebra_mlag_handle_process_state(MLAG_DOWN); - return -1; + return; } mlag_rd_buf_offset += data_len; if (data_len != (ssize_t)(tot_len - curr_len)) { /* Try again later */ zebra_mlag_sched_read(); - return 0; + return; } } @@ -162,10 +162,9 @@ static int zebra_mlag_read(struct thread *thread) zebra_mlag_reset_read_buffer(); mlag_rd_buf_offset = 0; zebra_mlag_sched_read(); - return 0; } -static int zebra_mlag_connect(struct thread *thread) +static void zebra_mlag_connect(struct thread *thread) { struct sockaddr_un svr = {0}; @@ -178,7 +177,7 @@ static int zebra_mlag_connect(struct thread *thread) mlag_socket = socket(svr.sun_family, SOCK_STREAM, 0); if (mlag_socket < 0) - return -1; + return; if (connect(mlag_socket, (struct sockaddr *)&svr, sizeof(svr)) == -1) { if (IS_ZEBRA_DEBUG_MLAG) @@ -189,7 +188,7 @@ static int zebra_mlag_connect(struct thread *thread) zrouter.mlag_info.timer_running = true; thread_add_timer(zmlag_master, zebra_mlag_connect, NULL, 10, &zrouter.mlag_info.t_read); - return 0; + return; } set_nonblocking(mlag_socket); @@ -204,7 +203,6 @@ static int zebra_mlag_connect(struct thread *thread) * Connection is established with MLAGD, post to clients */ zebra_mlag_handle_process_state(MLAG_UP); - return 0; } /* diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c index 81d610940..739ba3303 100644 --- a/zebra/zebra_netns_id.c +++ b/zebra/zebra_netns_id.c @@ -136,7 +136,6 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf) ns_id_t ns_id = NS_UNKNOWN; int offset = NETLINK_ALIGN(sizeof(struct nlmsghdr)) + NETLINK_ALIGN(sizeof(struct rtgenmsg)); - int curr_length = offset; void *tail = (void *)((char *)nlh + NETLINK_ALIGN(nlh->nlmsg_len)); struct nlattr *attr; @@ -145,7 +144,6 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf) && attr->nla_len >= sizeof(struct nlattr) && attr->nla_len <= NETLINK_NLATTR_LEN(tail, attr); attr += NETLINK_ALIGN(attr->nla_len)) { - curr_length += attr->nla_len; if ((attr->nla_type & NLA_TYPE_MASK) == NETNSA_NSID) { uint32_t *ptr = (uint32_t *)(attr); diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index 8cc7724f0..7cb190689 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -61,11 +61,11 @@ struct zebra_netns_info { unsigned int retries; }; -static int zebra_ns_ready_read(struct thread *t); +static void zebra_ns_ready_read(struct thread *t); static void zebra_ns_notify_create_context_from_entry_name(const char *name); static int zebra_ns_continue_read(struct zebra_netns_info *zns_info, int stop_retry); -static int zebra_ns_notify_read(struct thread *t); +static void zebra_ns_notify_read(struct thread *t); static struct vrf *vrf_handler_create(struct vty *vty, const char *vrfname) { @@ -231,17 +231,17 @@ static bool zebra_ns_notify_is_default_netns(const char *name) return false; } -static int zebra_ns_ready_read(struct thread *t) +static void zebra_ns_ready_read(struct thread *t) { struct zebra_netns_info *zns_info = THREAD_ARG(t); const char *netnspath; int err, stop_retry = 0; if (!zns_info) - return 0; + return; if (!zns_info->netnspath) { XFREE(MTYPE_NETNS_MISC, zns_info); - return 0; + return; } netnspath = zns_info->netnspath; if (--zns_info->retries == 0) @@ -249,34 +249,40 @@ static int zebra_ns_ready_read(struct thread *t) frr_with_privs(&zserv_privs) { err = ns_switch_to_netns(netnspath); } - if (err < 0) - return zebra_ns_continue_read(zns_info, stop_retry); + if (err < 0) { + zebra_ns_continue_read(zns_info, stop_retry); + return; + } /* go back to default ns */ frr_with_privs(&zserv_privs) { err = ns_switchback_to_initial(); } - if (err < 0) - return zebra_ns_continue_read(zns_info, stop_retry); + if (err < 0) { + zebra_ns_continue_read(zns_info, stop_retry); + return; + } /* check default name is not already set */ if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) { zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath)); - return zebra_ns_continue_read(zns_info, 1); + zebra_ns_continue_read(zns_info, 1); + return; } if (zebra_ns_notify_is_default_netns(basename(netnspath))) { zlog_warn( "NS notify : NS %s is default VRF. Ignore VRF creation", basename(netnspath)); - return zebra_ns_continue_read(zns_info, 1); + zebra_ns_continue_read(zns_info, 1); + return; } /* success : close fd and create zns context */ zebra_ns_notify_create_context_from_entry_name(basename(netnspath)); - return zebra_ns_continue_read(zns_info, 1); + zebra_ns_continue_read(zns_info, 1); } -static int zebra_ns_notify_read(struct thread *t) +static void zebra_ns_notify_read(struct thread *t) { int fd_monitor = THREAD_FD(t); struct inotify_event *event; @@ -290,7 +296,7 @@ static int zebra_ns_notify_read(struct thread *t) flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ, "NS notify read: failed to read (%s)", safe_strerror(errno)); - return 0; + return; } for (event = (struct inotify_event *)buf; (char *)event < &buf[len]; event = (struct inotify_event *)((char *)event + sizeof(*event) @@ -329,7 +335,6 @@ static int zebra_ns_notify_read(struct thread *t) thread_add_timer_msec(zrouter.master, zebra_ns_ready_read, (void *)netnsinfo, 0, NULL); } - return 0; } void zebra_ns_notify_parse(void) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index aa015992d..469a94a65 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1966,7 +1966,7 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop, */ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, const struct prefix *top, int type, uint32_t flags, - uint32_t *pmtu) + uint32_t *pmtu, vrf_id_t vrf_id) { struct prefix p; struct route_table *table; @@ -2061,13 +2061,13 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, return 1; } - if (top - && ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN - && nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) - || (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN - && memcmp(&nexthop->gate.ipv6, &top->u.prefix6, - IPV6_MAX_BYTELEN) - == 0))) { + if (top && + ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN && + nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) || + (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN && + memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) == + 0)) && + nexthop->vrf_id == vrf_id) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( " :%s: Attempting to install a max prefixlength route through itself", @@ -2361,6 +2361,7 @@ static unsigned nexthop_active_check(struct route_node *rn, const struct prefix *p, *src_p; struct zebra_vrf *zvrf; uint32_t mtu = 0; + vrf_id_t vrf_id; srcdest_rnode_prefixes(rn, &p, &src_p); @@ -2369,7 +2370,7 @@ static unsigned nexthop_active_check(struct route_node *rn, else if (rn->p.family == AF_INET6) family = AFI_IP6; else - family = 0; + family = AF_UNSPEC; if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop); @@ -2389,10 +2390,12 @@ static unsigned nexthop_active_check(struct route_node *rn, goto skip_check; } + + vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn))); switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - if (nexthop_active(nexthop, nhe, &rn->p, re->type, - re->flags, &mtu)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, + &mtu, vrf_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2400,16 +2403,16 @@ static unsigned nexthop_active_check(struct route_node *rn, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - if (nexthop_active(nexthop, nhe, &rn->p, re->type, - re->flags, &mtu)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, + &mtu, vrf_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_IPV6: family = AFI_IP6; - if (nexthop_active(nexthop, nhe, &rn->p, re->type, - re->flags, &mtu)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, + &mtu, vrf_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2419,8 +2422,8 @@ static unsigned nexthop_active_check(struct route_node *rn, if (rn->p.family != AF_INET) family = AFI_IP6; - if (nexthop_active(nexthop, nhe, &rn->p, re->type, - re->flags, &mtu)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, + &mtu, vrf_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2475,7 +2478,7 @@ skip_check: memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr)); - zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id); + zvrf = zebra_vrf_lookup_by_id(re->vrf_id); if (!zvrf) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug(" %s: zvrf is NULL", __func__); @@ -2989,13 +2992,14 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_GRE_SET: case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: break; } dplane_ctx_fini(&ctx); } -static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) +static int zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) { struct nhg_hash_entry *nhe = NULL; @@ -3009,7 +3013,7 @@ static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) * from an upper level proto. */ if (zrouter.startup_time < nhe->uptime) - return; + return HASHWALK_CONTINUE; /* * If it's proto-owned and not being used by a route, remove it since @@ -3019,20 +3023,41 @@ static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) */ if (PROTO_OWNED(nhe) && nhe->refcnt == 1) { zebra_nhg_decrement_ref(nhe); - return; + return HASHWALK_ABORT; } /* * If its being ref'd by routes, just let it be uninstalled via a route * removal. */ - if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) + if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) { zebra_nhg_uninstall_kernel(nhe); + return HASHWALK_ABORT; + } + + return HASHWALK_CONTINUE; } void zebra_nhg_sweep_table(struct hash *hash) { - hash_iterate(hash, zebra_nhg_sweep_entry, NULL); + uint32_t count; + + /* + * Yes this is extremely odd. Effectively nhg's have + * other nexthop groups that depend on them and when you + * remove them, you can have other entries blown up. + * our hash code does not work with deleting multiple + * entries at a time and will possibly cause crashes + * So what to do? Whenever zebra_nhg_sweep_entry + * deletes an entry it will return HASHWALK_ABORT, + * cause that deletion might have triggered more. + * then we can just keep sweeping this table + * until nothing more is found to do. + */ + do { + count = hashcount(hash); + hash_walk(hash, zebra_nhg_sweep_entry, NULL); + } while (count != hashcount(hash)); } static void zebra_nhg_mark_keep_entry(struct hash_bucket *bucket, void *arg) diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 0519e1d5b..7a0ffbc1e 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -39,6 +39,9 @@ struct nlsock { int seq; struct sockaddr_nl snl; char name[64]; + + uint8_t *buf; + size_t buflen; }; #endif diff --git a/zebra/zebra_opaque.c b/zebra/zebra_opaque.c index 244f16302..0a98194ac 100644 --- a/zebra/zebra_opaque.c +++ b/zebra/zebra_opaque.c @@ -106,7 +106,7 @@ static const char LOG_NAME[] = "Zebra Opaque"; /* Prototypes */ /* Main event loop, processing incoming message queue */ -static int process_messages(struct thread *event); +static void process_messages(struct thread *event); static int handle_opq_registration(const struct zmsghdr *hdr, struct stream *msg); static int handle_opq_unregistration(const struct zmsghdr *hdr, @@ -270,7 +270,7 @@ uint32_t zebra_opaque_enqueue_batch(struct stream_fifo *batch) /* * Pthread event loop, process the incoming message queue. */ -static int process_messages(struct thread *event) +static void process_messages(struct thread *event) { struct stream_fifo fifo; struct stream *msg; @@ -335,8 +335,6 @@ done: /* This will also free any leftover messages, in the shutdown case */ stream_fifo_deinit(&fifo); - - return 0; } /* diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 32edb78c7..c28e251e3 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -100,7 +100,7 @@ static ptm_lib_handle_t *ptm_hdl; struct zebra_ptm_cb ptm_cb; static int zebra_ptm_socket_init(void); -int zebra_ptm_sock_read(struct thread *); +void zebra_ptm_sock_read(struct thread *thread); static void zebra_ptm_install_commands(void); static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt); void zebra_bfd_peer_replay_req(void); @@ -168,12 +168,12 @@ void zebra_ptm_finish(void) close(ptm_cb.ptm_sock); } -static int zebra_ptm_flush_messages(struct thread *thread) +static void zebra_ptm_flush_messages(struct thread *thread) { ptm_cb.t_write = NULL; if (ptm_cb.ptm_sock == -1) - return -1; + return; errno = 0; @@ -187,7 +187,7 @@ static int zebra_ptm_flush_messages(struct thread *thread) ptm_cb.t_timer = NULL; thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); - return -1; + return; case BUFFER_PENDING: ptm_cb.t_write = NULL; thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL, @@ -196,8 +196,6 @@ static int zebra_ptm_flush_messages(struct thread *thread) case BUFFER_EMPTY: break; } - - return 0; } static int zebra_ptm_send_message(char *data, int size) @@ -226,7 +224,7 @@ static int zebra_ptm_send_message(char *data, int size) return 0; } -int zebra_ptm_connect(struct thread *t) +void zebra_ptm_connect(struct thread *t) { int init = 0; @@ -255,8 +253,6 @@ int zebra_ptm_connect(struct thread *t) } else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX) { ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL; } - - return (errno); } DEFUN (zebra_ptm_enable, @@ -354,7 +350,7 @@ DEFUN (no_zebra_ptm_enable_if, if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("%s: Bringing up interface %s", __func__, ifp->name); - if_up(ifp); + if_up(ifp, true); } } @@ -557,7 +553,7 @@ static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt, ifp->ptm_status = ZEBRA_PTM_STATUS_UP; if (ifp->ptm_enable && if_is_no_ptm_operative(ifp) && send_linkup) - if_up(ifp); + if_up(ifp, true); } else if (!strcmp(cbl_str, ZEBRA_PTM_FAIL_STR) && (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) { ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN; @@ -649,7 +645,7 @@ static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt) } } -int zebra_ptm_sock_read(struct thread *thread) +void zebra_ptm_sock_read(struct thread *thread) { int sock; int rc; @@ -658,7 +654,7 @@ int zebra_ptm_sock_read(struct thread *thread) sock = THREAD_FD(thread); if (sock == -1) - return -1; + return; /* PTM communicates in CSV format */ do { @@ -679,14 +675,12 @@ int zebra_ptm_sock_read(struct thread *thread) thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); - return -1; + return; } ptm_cb.t_read = NULL; thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL, ptm_cb.ptm_sock, &ptm_cb.t_read); - - return 0; } /* BFD peer/dst register/update */ @@ -1169,7 +1163,7 @@ void zebra_ptm_reset_status(int ptm_disable) zlog_debug( "%s: Bringing up interface %s", __func__, ifp->name); - if_up(ifp); + if_up(ifp, true); } } } diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index 88c9bccb4..f8e843cc7 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -74,7 +74,7 @@ struct zebra_ptm_cb { void zebra_ptm_init(void); void zebra_ptm_finish(void); -int zebra_ptm_connect(struct thread *t); +void zebra_ptm_connect(struct thread *t); void zebra_ptm_write(struct vty *vty); int zebra_ptm_get_enable_state(void); diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 57276974c..7d1153f21 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -47,7 +47,7 @@ DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)); static int zebra_pw_enabled(struct zebra_pw *); static void zebra_pw_install(struct zebra_pw *); static void zebra_pw_uninstall(struct zebra_pw *); -static int zebra_pw_install_retry(struct thread *); +static void zebra_pw_install_retry(struct thread *thread); static int zebra_pw_check_reachability(const struct zebra_pw *); static void zebra_pw_update_status(struct zebra_pw *, int); @@ -226,14 +226,12 @@ void zebra_pw_install_failure(struct zebra_pw *pw, int pwstatus) zebra_pw_update_status(pw, pwstatus); } -static int zebra_pw_install_retry(struct thread *thread) +static void zebra_pw_install_retry(struct thread *thread) { struct zebra_pw *pw = THREAD_ARG(thread); pw->install_retry_timer = NULL; zebra_pw_install(pw); - - return 0; } static void zebra_pw_update_status(struct zebra_pw *pw, int status) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index fbd3c6eb7..e376d4b2a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -116,6 +116,7 @@ static const struct { [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 5}, [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 7}, [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 7}, + [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, 255, 7}, /* Any new route type added to zebra, should be mirrored here */ /* no entry/default: 150 */ @@ -3123,6 +3124,17 @@ static void rib_addnode(struct route_node *rn, rib_link(rn, re, process); } +static void rib_re_nhg_free(struct route_entry *re) +{ + if (re->nhe && re->nhe_id) { + assert(re->nhe->id == re->nhe_id); + route_entry_update_nhe(re, NULL); + } else if (re->nhe && re->nhe->nhg.nexthop) + nexthops_free(re->nhe->nhg.nexthop); + + nexthops_free(re->fib_ng.nexthop); +} + /* * rib_unlink * @@ -3149,14 +3161,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; - if (re->nhe && re->nhe_id) { - assert(re->nhe->id == re->nhe_id); - - route_entry_update_nhe(re, NULL); - } else if (re->nhe && re->nhe->nhg.nexthop) - nexthops_free(re->nhe->nhg.nexthop); - - nexthops_free(re->fib_ng.nexthop); + rib_re_nhg_free(re); zapi_re_opaque_free(re->opaque); @@ -3346,7 +3351,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, */ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re, - struct nhg_hash_entry *re_nhe) + struct nhg_hash_entry *re_nhe, bool startup) { struct nhg_hash_entry *nhe = NULL; struct route_table *table; @@ -3438,6 +3443,26 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, same = first_same; + if (!startup && + (re->flags & ZEBRA_FLAG_SELFROUTE) && zrouter.asic_offloaded) { + if (!same) { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("prefix: %pRN is a self route where we do not have an entry for it. Dropping this update, it's useless", rn); + /* + * We are not on startup, this is a self route + * and we have asic offload. Which means + * we are getting a callback for a entry + * that was already deleted to the kernel + * but an earlier response was just handed + * back. Drop it on the floor + */ + rib_re_nhg_free(re); + + XFREE(MTYPE_RE, re); + return ret; + } + } + /* If this route is kernel/connected route, notify the dataplane. */ if (RIB_SYSTEM_ROUTE(re)) { /* Notify dataplane */ @@ -3491,7 +3516,7 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, */ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re, - struct nexthop_group *ng) + struct nexthop_group *ng, bool startup) { int ret; struct nhg_hash_entry nhe; @@ -3512,7 +3537,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, else if (re->nhe_id > 0) nhe.id = re->nhe_id; - ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, &nhe); + ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, &nhe, startup); /* In this path, the callers expect memory to be freed. */ nexthop_group_delete(&ng); @@ -3743,7 +3768,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, uint32_t flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint32_t mtu, - uint8_t distance, route_tag_t tag) + uint8_t distance, route_tag_t tag, bool startup) { struct route_entry *re = NULL; struct nexthop *nexthop = NULL; @@ -3775,7 +3800,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, nexthop_group_add_sorted(ng, nexthop); } - return rib_add_multipath(afi, safi, p, src_p, re, ng); + return rib_add_multipath(afi, safi, p, src_p, re, ng, startup); } static const char *rib_update_event2str(enum rib_update_event event) @@ -3924,7 +3949,7 @@ static void rib_update_ctx_fini(struct rib_update_ctx **ctx) XFREE(MTYPE_RIB_UPDATE_CTX, *ctx); } -static int rib_update_handler(struct thread *thread) +static void rib_update_handler(struct thread *thread) { struct rib_update_ctx *ctx; @@ -3936,8 +3961,6 @@ static int rib_update_handler(struct thread *thread) rib_update_handle_vrf(ctx->vrf_id, ctx->event, ZEBRA_ROUTE_ALL); rib_update_ctx_fini(&ctx); - - return 0; } /* @@ -4031,7 +4054,7 @@ void rib_sweep_table(struct route_table *table) } /* Sweep all RIB tables. */ -int rib_sweep_route(struct thread *t) +void rib_sweep_route(struct thread *t) { struct vrf *vrf; struct zebra_vrf *zvrf; @@ -4046,8 +4069,6 @@ int rib_sweep_route(struct thread *t) zebra_router_sweep_route(); zebra_router_sweep_nhgs(); - - return 0; } /* Remove specific by protocol routes from 'table'. */ @@ -4157,7 +4178,7 @@ done: * Handle results from the dataplane system. Dequeue update context * structs, dispatch to appropriate internal handlers. */ -static int rib_process_dplane_results(struct thread *thread) +static void rib_process_dplane_results(struct thread *thread) { struct zebra_dplane_ctx *ctx; struct dplane_ctx_q ctxlist; @@ -4300,6 +4321,10 @@ static int rib_process_dplane_results(struct thread *thread) zebra_if_addr_update_ctx(ctx); break; + case DPLANE_OP_INTF_NETCONFIG: + zebra_if_netconf_update_ctx(ctx); + break; + /* Some op codes not handled here */ case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_UNINSTALL: @@ -4325,8 +4350,6 @@ static int rib_process_dplane_results(struct thread *thread) } } while (1); - - return 0; } /* @@ -4364,9 +4387,8 @@ static void check_route_info(void) * ZEBRA_ROUTE_ALL is also ignored. */ for (int i = 0; i < len; i++) { - if (i == ZEBRA_ROUTE_SYSTEM || i == ZEBRA_ROUTE_ALL) - continue; - assert(route_info[i].key); + assert(route_info[i].key >= ZEBRA_ROUTE_SYSTEM && + route_info[i].key < ZEBRA_ROUTE_MAX); assert(route_info[i].meta_q_map < MQ_SIZE); } } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index f5faaab71..4d5336120 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -637,15 +637,11 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, if (re) { *prn = rn; return re; - } - - if (!CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + } else { + /* Resolve the nexthop recursively by finding matching + * route with lower prefix length + */ rn = rn->parent; - else { - if (IS_ZEBRA_DEBUG_NHT_DETAILED) - zlog_debug( - " Nexthop must be connected, cannot recurse up"); - return NULL; } } @@ -1173,15 +1169,17 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, SET_FLAG(message, ZAPI_MESSAGE_SRTE); stream_putl(s, message); + /* + * Put what we were told to match against + */ stream_putw(s, rnh->safi); stream_putw(s, rn->p.family); + stream_putc(s, rn->p.prefixlen); switch (rn->p.family) { case AF_INET: - stream_putc(s, rn->p.prefixlen); stream_put_in_addr(s, &rn->p.u.prefix4); break; case AF_INET6: - stream_putc(s, rn->p.prefixlen); stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN); break; default: @@ -1190,6 +1188,26 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, __func__, rn->p.family); goto failure; } + + /* + * What we matched against + */ + stream_putw(s, rnh->resolved_route.family); + stream_putc(s, rnh->resolved_route.prefixlen); + switch (rnh->resolved_route.family) { + case AF_INET: + stream_put_in_addr(s, &rnh->resolved_route.u.prefix4); + break; + case AF_INET6: + stream_put(s, &rnh->resolved_route.u.prefix6, IPV6_MAX_BYTELEN); + break; + default: + flog_err(EC_ZEBRA_RNH_UNKNOWN_FAMILY, + "%s: Unknown family (%d) notification attempted", + __func__, rn->p.family); + goto failure; + } + if (srte_color) stream_putl(s, srte_color); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 908c13f3d..e99cb7611 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -1638,7 +1638,7 @@ static void zebra_route_map_process_update_cb(char *rmap_name) zebra_nht_rm_update(rmap_name); } -static int zebra_route_map_update_timer(struct thread *thread) +static void zebra_route_map_update_timer(struct thread *thread) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("Event driven route-map update triggered"); @@ -1655,7 +1655,6 @@ static int zebra_route_map_update_timer(struct thread *thread) * 1) VRF Aware * 2) Route-map aware */ - return 0; } static void zebra_route_map_set_delay_timer(uint32_t value) diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 92a3b9424..6b4a7543c 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -262,6 +262,9 @@ void zebra_router_terminate(void) #ifdef HAVE_SCRIPTING zebra_script_destroy(); #endif + + /* OS-specific deinit */ + kernel_router_terminate(); } bool zebra_router_notify_on_ack(void) @@ -307,4 +310,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) #ifdef HAVE_SCRIPTING zebra_script_init(); #endif + + /* OS-specific init */ + kernel_router_init(); } diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index dd788216c..63a61d529 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -209,11 +209,14 @@ struct zebra_router { */ bool asic_offloaded; bool notify_on_ack; + + bool supports_nhgs; }; #define GRACEFUL_RESTART_TIME 60 extern struct zebra_router zrouter; +extern uint32_t rcvbufsize; extern void zebra_router_init(bool asic_offload, bool notify_on_ack); extern void zebra_router_cleanup(void); @@ -256,6 +259,11 @@ extern enum multicast_mode multicast_mode_ipv4_get(void); extern bool zebra_router_notify_on_ack(void); +static inline void zebra_router_set_supports_nhgs(bool support) +{ + zrouter.supports_nhgs = support; +} + /* zebra_northbound.c */ extern const struct frr_yang_module_info frr_zebra_info; diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c index 0e19376ab..4087749fd 100644 --- a/zebra/zebra_script.c +++ b/zebra/zebra_script.c @@ -412,6 +412,8 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) lua_setfield(L, -2, "mtu"); } lua_setfield(L, -2, "gre"); + + case DPLANE_OP_INTF_NETCONFIG: /*NYI*/ case DPLANE_OP_NONE: break; } /* Dispatch by op code */ diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c index 7933ef66b..c0f18dd09 100644 --- a/zebra/zebra_srte.c +++ b/zebra/zebra_srte.c @@ -117,13 +117,25 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy, stream_putl(s, message); stream_putw(s, SAFI_UNICAST); + /* + * The prefix is copied twice because the ZEBRA_NEXTHOP_UPDATE + * code was modified to send back both the matched against + * as well as the actual matched. There does not appear to + * be an equivalent here so just send the same thing twice. + */ switch (policy->endpoint.ipa_type) { case IPADDR_V4: + stream_putw(s, AF_INET); + stream_putc(s, IPV4_MAX_BITLEN); + stream_put_in_addr(s, &policy->endpoint.ipaddr_v4); stream_putw(s, AF_INET); stream_putc(s, IPV4_MAX_BITLEN); stream_put_in_addr(s, &policy->endpoint.ipaddr_v4); break; case IPADDR_V6: + stream_putw(s, AF_INET6); + stream_putc(s, IPV6_MAX_BITLEN); + stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN); stream_putw(s, AF_INET6); stream_putc(s, IPV6_MAX_BITLEN); stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index fab1e7b89..bb1623211 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -33,6 +33,7 @@ #include "routemap.h" #include "srcdest_table.h" #include "vxlan.h" +#include "termtable.h" #include "zebra/zebra_router.h" #include "zebra/zserv.h" @@ -61,6 +62,7 @@ #include "zebra/kernel_netlink.h" #include "zebra/table_manager.h" #include "zebra/zebra_script.h" +#include "zebra/rtadv.h" extern int allow_delete; @@ -3423,7 +3425,7 @@ DEFUN (show_evpn_mac_vni_mac, vni = strtoul(argv[4]->arg, NULL, 10); if (!prefix_str2mac(argv[6]->arg, &mac)) { - vty_out(vty, "%% Malformed MAC address"); + vty_out(vty, "%% Malformed MAC address\n"); return CMD_WARNING; } zvrf = zebra_vrf_get_evpn(); @@ -3969,9 +3971,43 @@ DEFUN (show_zebra, ZEBRA_STR) { struct vrf *vrf; + struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + char *out; + + ttable_rowseps(table, 0, BOTTOM, true, '-'); + ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get()); + ttable_add_row(table, "v4 Forwarding|%s", ipforward() ? "On" : "Off"); + ttable_add_row(table, "v6 Forwarding|%s", + ipforward_ipv6() ? "On" : "Off"); + ttable_add_row(table, "MPLS|%s", mpls_enabled ? "On" : "Off"); + ttable_add_row(table, "EVPN|%s", is_evpn_enabled() ? "On" : "Off"); + + +#ifdef GNU_LINUX + if (!vrf_is_backend_netns()) + ttable_add_row(table, "VRF|l3mdev Available"); + else + ttable_add_row(table, "VRF|Namespaces"); +#else + ttable_add_row(table, "VRF|Not Available"); +#endif + + ttable_add_row(table, "ASIC offload|%s", + zrouter.asic_offloaded ? "Used" : "Unavailable"); + + ttable_add_row(table, "RA|%s", + rtadv_compiled_in() ? "Compiled in" : "Not Compiled in"); + ttable_add_row(table, "RFC 5549|%s", + rtadv_get_interfaces_configured_from_bgp() + ? "BGP is using" + : "BGP is not using"); + + ttable_add_row(table, "Kernel NHG|%s", + zrouter.supports_nhgs ? "Available" : "Unavailable"); - if (zrouter.asic_offloaded) - vty_out(vty, "Asic Offload is being used\n"); + out = ttable_dump(table, "\n"); + vty_out(vty, "%s\n", out); + XFREE(MTYPE_TMP, out); vty_out(vty, " Route Route Neighbor LSP LSP\n"); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index b6da445e3..d01d8158d 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2124,13 +2124,6 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni, return 0; zevpn = zebra_evpn_add(vni); - if (!zevpn) { - flog_err(EC_ZEBRA_VNI_ADD_FAILED, - "Adding L2-VNI - Failed to add VNI hash, VNI %u", - vni); - - return -1; - } /* Find bridge interface for the VNI */ vlan_if = zvni_map_to_svi(vxl->access_vlan, @@ -5171,16 +5164,8 @@ int zebra_vxlan_if_add(struct interface *ifp) /* Create or update EVPN hash. */ zevpn = zebra_evpn_lookup(vni); - if (!zevpn) { + if (!zevpn) zevpn = zebra_evpn_add(vni); - if (!zevpn) { - flog_err( - EC_ZEBRA_VNI_ADD_FAILED, - "Failed to add EVPN hash, IF %s(%u) VNI %u", - ifp->name, ifp->ifindex, vni); - return -1; - } - } if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr || zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) { diff --git a/zebra/zserv.c b/zebra/zserv.c index f3f69661c..630c76c98 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -216,7 +216,7 @@ static void zserv_client_fail(struct zserv *client) * allows us to expose information about input and output queues to the user in * terms of number of packets rather than size of data. */ -static int zserv_write(struct thread *thread) +static void zserv_write(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); struct stream *msg; @@ -232,7 +232,7 @@ static int zserv_write(struct thread *thread) (uint32_t)monotime(NULL), memory_order_relaxed); zserv_client_event(client, ZSERV_CLIENT_WRITE); - return 0; + return; case BUFFER_EMPTY: break; } @@ -268,7 +268,7 @@ static int zserv_write(struct thread *thread) (uint32_t)monotime(NULL), memory_order_relaxed); zserv_client_event(client, ZSERV_CLIENT_WRITE); - return 0; + return; case BUFFER_EMPTY: break; } @@ -279,14 +279,13 @@ static int zserv_write(struct thread *thread) atomic_store_explicit(&client->last_write_time, (uint32_t)monotime(NULL), memory_order_relaxed); - return 0; + return; zwrite_fail: flog_warn(EC_ZEBRA_CLIENT_WRITE_FAILED, "%s: could not write to %s [fd = %d], closing.", __func__, zebra_route_string(client->proto), client->sock); zserv_client_fail(client); - return 0; } /* @@ -311,7 +310,7 @@ zwrite_fail: * * Any failure in any of these actions is handled by terminating the client. */ -static int zserv_read(struct thread *thread) +static void zserv_read(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); int sock; @@ -453,12 +452,11 @@ static int zserv_read(struct thread *thread) stream_fifo_free(cache); - return 0; + return; zread_fail: stream_fifo_free(cache); zserv_client_fail(client); - return -1; } static void zserv_client_event(struct zserv *client, @@ -495,7 +493,7 @@ static void zserv_client_event(struct zserv *client, * rely on the read thread to handle queuing this task enough times to process * everything on the input queue. */ -static int zserv_process_messages(struct thread *thread) +static void zserv_process_messages(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); struct stream *msg; @@ -529,8 +527,6 @@ static int zserv_process_messages(struct thread *thread) /* Reschedule ourselves if necessary */ if (need_resched) zserv_event(client, ZSERV_PROCESS_MESSAGES); - - return 0; } int zserv_send_message(struct zserv *client, struct stream *msg) @@ -714,12 +710,11 @@ void zserv_close_client(struct zserv *client) * already have been closed and the thread will most likely have died, but its * resources still need to be cleaned up. */ -static int zserv_handle_client_fail(struct thread *thread) +static void zserv_handle_client_fail(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); zserv_close_client(client); - return 0; } /* @@ -853,7 +848,7 @@ void zserv_release_client(struct zserv *client) /* * Accept socket connection. */ -static int zserv_accept(struct thread *thread) +static void zserv_accept(struct thread *thread) { int accept_sock; int client_sock; @@ -871,7 +866,7 @@ static int zserv_accept(struct thread *thread) if (client_sock < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't accept zebra socket: %s", safe_strerror(errno)); - return -1; + return; } /* Make client socket non-blocking. */ @@ -879,8 +874,6 @@ static int zserv_accept(struct thread *thread) /* Create new zebra client. */ zserv_client_create(client_sock); - - return 0; } void zserv_close(void) diff --git a/zebra/zserv.h b/zebra/zserv.h index 203670ac1..7a5be001b 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -379,7 +379,7 @@ void zserv_log_message(const char *errmsg, struct stream *msg, struct zmsghdr *hdr); /* TODO */ -__attribute__((__noreturn__)) int zebra_finalize(struct thread *event); +__attribute__((__noreturn__)) void zebra_finalize(struct thread *event); /* * Graceful restart functions.