diff options
82 files changed, 1524 insertions, 319 deletions
diff --git a/.github/workflows/docker-daily-master.yml b/.github/workflows/docker-daily-master.yml new file mode 100644 index 0000000000..c82d05323d --- /dev/null +++ b/.github/workflows/docker-daily-master.yml @@ -0,0 +1,51 @@ +name: Build daily 'master' images for Docker + +on: + schedule: + - cron: '59 23 * * *' + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + docker_daily_master: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Custom variables + id: vars + run: | + # To package a specific git commit, the date of the commit gets + # appended to the latest release, e.g. 1.0.0_git20180204. + # This is the requirement by APKBUILD (abuild). + # More details: https://wiki.alpinelinux.org/wiki/APKBUILD_Reference. + echo ::set-output name=date::$(date +'%Y%m%d') + + - name: Checkout + uses: actions/checkout@v3 + with: + ref: master + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + file: ./docker/alpine/Dockerfile + push: true + tags: ${{ secrets.DOCKERHUB_USERNAME }}/frr:master + build-args: PKGVER=${{ steps.vars.outputs.date }} + platforms: linux/amd64,linux/arm64,linux/arm/v7 diff --git a/.github/workflows/docker-stable.yml b/.github/workflows/docker-stable.yml new file mode 100644 index 0000000000..c720d35ca3 --- /dev/null +++ b/.github/workflows/docker-stable.yml @@ -0,0 +1,52 @@ +name: Build stable branch images for Docker + +on: + push: + branches: + - 'stable/**' + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + docker_daily_master: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Custom variables + id: vars + run: | + # To package a specific git commit, the date of the commit gets + # appended to the latest release, e.g. 1.0.0_git20180204. + # This is the requirement by APKBUILD (abuild). + # More details: https://wiki.alpinelinux.org/wiki/APKBUILD_Reference. + echo ::set-output name=date::$(date +'%Y%m%d') + # Get the real version specified in configure.ac file. + echo ::set-output name=frr_version::$(grep AC_INIT configure.ac | cut -d '[' -f3 | cut -d ']' -f 1) + + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + file: ./docker/alpine/Dockerfile + push: true + tags: ${{ secrets.DOCKERHUB_USERNAME }}/frr:v${{ steps.vars.outputs.frr_version }} + build-args: PKGVER=${{ steps.vars.outputs.date }} + platforms: linux/amd64,linux/arm64,linux/arm/v7 diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 06f6073781..85f09ccf0b 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1187,6 +1187,33 @@ int aspath_loop_check(struct aspath *aspath, as_t asno) return count; } +/* AS path loop check. If aspath contains asno + * that is a confed id then return >= 1. + */ +int aspath_loop_check_confed(struct aspath *aspath, as_t asno) +{ + struct assegment *seg; + int count = 0; + + if (aspath == NULL || aspath->segments == NULL) + return 0; + + seg = aspath->segments; + + while (seg) { + unsigned int i; + + for (i = 0; i < seg->length; i++) + if (seg->type != AS_CONFED_SEQUENCE && + seg->type != AS_CONFED_SET && seg->as[i] == asno) + count++; + + seg = seg->next; + } + return count; +} + + /* When all of AS path is private AS return 1. */ bool aspath_private_as_check(struct aspath *aspath) { diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 0b58e1adc4..97bc7c0aca 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -111,6 +111,7 @@ extern unsigned int aspath_key_make(const void *p); extern unsigned int aspath_get_first_as(struct aspath *aspath); extern unsigned int aspath_get_last_as(struct aspath *aspath); extern int aspath_loop_check(struct aspath *aspath, as_t asno); +extern int aspath_loop_check_confed(struct aspath *aspath, as_t asno); extern bool aspath_private_as_check(struct aspath *aspath); extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath, as_t target_asn, diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 1f8c7dc098..ace7e79753 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2702,6 +2702,18 @@ bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args) } if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) { + if (STREAM_READABLE(peer->curr) < + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH) { + flog_err( + EC_BGP_ATTR_LEN, + "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)", + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH, + STREAM_READABLE(peer->curr)); + return bgp_attr_malformed( + args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + loc_block_len = stream_getc(peer->curr); loc_node_len = stream_getc(peer->curr); func_len = stream_getc(peer->curr); @@ -2774,6 +2786,17 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args) } if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) { + if (STREAM_READABLE(peer->curr) < + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) { + flog_err( + EC_BGP_ATTR_LEN, + "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)", + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH, + STREAM_READABLE(peer->curr)); + return bgp_attr_malformed( + args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } stream_getc(peer->curr); stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid)); sid_flags = stream_getc(peer->curr); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index fcb7275c34..65de35cbdb 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -61,6 +61,13 @@ DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer)); DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer)); +enum bgp_fsm_state_progress { + BGP_FSM_FAILURE_AND_DELETE = -2, + BGP_FSM_FAILURE = -1, + BGP_FSM_SUCCESS = 0, + BGP_FSM_SUCCESS_STATE_TRANSFER = 1, +}; + /* Definition of display strings corresponding to FSM events. This should be * kept consistent with the events defined in bgpd.h */ @@ -99,7 +106,7 @@ static void bgp_holdtime_timer(struct thread *); static void bgp_delayopen_timer(struct thread *); /* BGP FSM functions. */ -static int bgp_start(struct peer *); +static enum bgp_fsm_state_progress bgp_start(struct peer *); /* Register peer with NHT */ int bgp_peer_reg_with_nht(struct peer *peer) @@ -1293,7 +1300,8 @@ void bgp_fsm_change_status(struct peer *peer, int status) * Clearing * (or Deleted). */ - if (!work_queue_is_scheduled(peer->clear_node_queue)) + if (!work_queue_is_scheduled(peer->clear_node_queue) && + status != Deleted) BGP_EVENT_ADD(peer, Clearing_Completed); } @@ -1341,11 +1349,11 @@ void bgp_fsm_change_status(struct peer *peer, int status) } /* Flush the event queue and ensure the peer is shut down */ -static int bgp_clearing_completed(struct peer *peer) +static enum bgp_fsm_state_progress bgp_clearing_completed(struct peer *peer) { - int rc = bgp_stop(peer); + enum bgp_fsm_state_progress rc = bgp_stop(peer); - if (rc >= 0) + if (rc >= BGP_FSM_SUCCESS) BGP_EVENT_FLUSH(peer); return rc; @@ -1353,12 +1361,12 @@ static int bgp_clearing_completed(struct peer *peer) /* Administrative BGP peer stop event. */ /* May be called multiple times for the same peer */ -int bgp_stop(struct peer *peer) +enum bgp_fsm_state_progress bgp_stop(struct peer *peer) { afi_t afi; safi_t safi; char orf_name[BUFSIZ]; - int ret = 0; + enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS; struct bgp *bgp = peer->bgp; struct graceful_restart_info *gr_info = NULL; @@ -1375,7 +1383,7 @@ int bgp_stop(struct peer *peer) zlog_debug("%s (dynamic neighbor) deleted (%s)", peer->host, __func__); peer_delete(peer); - return -1; + return BGP_FSM_FAILURE_AND_DELETE; } /* Can't do this in Clearing; events are used for state transitions */ @@ -1584,7 +1592,7 @@ int bgp_stop(struct peer *peer) if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { peer_delete(peer); - ret = -1; + ret = BGP_FSM_FAILURE_AND_DELETE; } else { bgp_peer_conf_if_to_su_update(peer); } @@ -1592,7 +1600,7 @@ int bgp_stop(struct peer *peer) } /* BGP peer is stoped by the error. */ -static int bgp_stop_with_error(struct peer *peer) +static enum bgp_fsm_state_progress bgp_stop_with_error(struct peer *peer) { /* Double start timer. */ peer->v_start *= 2; @@ -1606,16 +1614,16 @@ static int bgp_stop_with_error(struct peer *peer) zlog_debug("%s (dynamic neighbor) deleted (%s)", peer->host, __func__); peer_delete(peer); - return -1; + return BGP_FSM_FAILURE; } - return (bgp_stop(peer)); + return bgp_stop(peer); } /* something went wrong, send notify and tear down */ -static int bgp_stop_with_notify(struct peer *peer, uint8_t code, - uint8_t sub_code) +static enum bgp_fsm_state_progress +bgp_stop_with_notify(struct peer *peer, uint8_t code, uint8_t sub_code) { /* Send notify to remote peer */ bgp_notify_send(peer, code, sub_code); @@ -1625,13 +1633,13 @@ static int bgp_stop_with_notify(struct peer *peer, uint8_t code, zlog_debug("%s (dynamic neighbor) deleted (%s)", peer->host, __func__); peer_delete(peer); - return -1; + return BGP_FSM_FAILURE; } /* Clear start timer value to default. */ peer->v_start = BGP_INIT_START_TIMER; - return (bgp_stop(peer)); + return bgp_stop(peer); } /** @@ -1696,13 +1704,12 @@ static void bgp_connect_check(struct thread *thread) /* TCP connection open. Next we send open message to remote peer. And add read thread for reading open message. */ -static int bgp_connect_success(struct peer *peer) +static enum bgp_fsm_state_progress bgp_connect_success(struct peer *peer) { if (peer->fd < 0) { flog_err(EC_BGP_CONNECT, "%s peer's fd is negative value %d", __func__, peer->fd); - bgp_stop(peer); - return -1; + return bgp_stop(peer); } if (bgp_getsockname(peer) < 0) { @@ -1712,7 +1719,7 @@ static int bgp_connect_success(struct peer *peer) bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, bgp_fsm_error_subcode(peer->status)); bgp_writes_on(peer); - return -1; + return BGP_FSM_FAILURE; } /* @@ -1734,19 +1741,19 @@ static int bgp_connect_success(struct peer *peer) /* Send an open message */ bgp_open_send(peer); - return 0; + return BGP_FSM_SUCCESS; } /* TCP connection open with RFC 4271 optional session attribute DelayOpen flag * set. */ -static int bgp_connect_success_w_delayopen(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_connect_success_w_delayopen(struct peer *peer) { if (peer->fd < 0) { flog_err(EC_BGP_CONNECT, "%s: peer's fd is negative value %d", __func__, peer->fd); - bgp_stop(peer); - return -1; + return bgp_stop(peer); } if (bgp_getsockname(peer) < 0) { @@ -1756,7 +1763,7 @@ static int bgp_connect_success_w_delayopen(struct peer *peer) bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, bgp_fsm_error_subcode(peer->status)); bgp_writes_on(peer); - return -1; + return BGP_FSM_FAILURE; } /* @@ -1787,18 +1794,18 @@ static int bgp_connect_success_w_delayopen(struct peer *peer) zlog_debug("%s [FSM] BGP OPEN message delayed for %d seconds", peer->host, peer->delayopen); - return 0; + return BGP_FSM_SUCCESS; } /* TCP connect fail */ -static int bgp_connect_fail(struct peer *peer) +static enum bgp_fsm_state_progress bgp_connect_fail(struct peer *peer) { if (peer_dynamic_neighbor_no_nsf(peer)) { if (bgp_debug_neighbor_events(peer)) zlog_debug("%s (dynamic neighbor) deleted (%s)", peer->host, __func__); peer_delete(peer); - return -1; + return BGP_FSM_FAILURE_AND_DELETE; } /* @@ -1807,13 +1814,13 @@ static int bgp_connect_fail(struct peer *peer) */ bgp_nht_interface_events(peer); - return (bgp_stop(peer)); + return bgp_stop(peer); } /* This function is the first starting point of all BGP connection. It * try to connect to remote peer with non-blocking IO. */ -int bgp_start(struct peer *peer) +enum bgp_fsm_state_progress bgp_start(struct peer *peer) { int status; @@ -1825,7 +1832,7 @@ int bgp_start(struct peer *peer) "%s [FSM] Unable to get neighbor's IP address, waiting...", peer->host); peer->last_reset = PEER_DOWN_NBR_ADDR; - return -1; + return BGP_FSM_FAILURE; } if (BGP_PEER_START_SUPPRESSED(peer)) { @@ -1841,7 +1848,7 @@ int bgp_start(struct peer *peer) peer->last_reset = PEER_DOWN_USER_SHUTDOWN; else if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) peer->last_reset = PEER_DOWN_PFX_COUNT; - return -1; + return BGP_FSM_FAILURE; } /* Scrub some information that might be left over from a previous, @@ -1867,7 +1874,7 @@ int bgp_start(struct peer *peer) /* If the peer is passive mode, force to move to Active mode. */ if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) { BGP_EVENT_ADD(peer, TCP_connection_open_failed); - return 0; + return BGP_FSM_SUCCESS; } if (peer->bgp->vrf_id == VRF_UNKNOWN) { @@ -1877,7 +1884,7 @@ int bgp_start(struct peer *peer) "%s [FSM] In a VRF that is not initialised yet", peer->host); peer->last_reset = PEER_DOWN_VRF_UNINIT; - return -1; + return BGP_FSM_FAILURE; } /* Register peer for NHT. If next hop is already resolved, proceed @@ -1891,7 +1898,7 @@ int bgp_start(struct peer *peer) peer->host); peer->last_reset = PEER_DOWN_WAITING_NHT; BGP_EVENT_ADD(peer, TCP_connection_open_failed); - return 0; + return BGP_FSM_SUCCESS; } } @@ -1926,7 +1933,7 @@ int bgp_start(struct peer *peer) flog_err(EC_BGP_FSM, "%s peer's fd is negative value %d", __func__, peer->fd); - return -1; + return BGP_FSM_FAILURE; } /* * - when the socket becomes ready, poll() will signify POLLOUT @@ -1943,24 +1950,26 @@ int bgp_start(struct peer *peer) &peer->t_connect_check_w); break; } - return 0; + return BGP_FSM_SUCCESS; } /* Connect retry timer is expired when the peer status is Connect. */ -static int bgp_reconnect(struct peer *peer) +static enum bgp_fsm_state_progress bgp_reconnect(struct peer *peer) { - if (bgp_stop(peer) < 0) - return -1; + enum bgp_fsm_state_progress ret; + + ret = bgp_stop(peer); + if (ret < BGP_FSM_SUCCESS) + return ret; /* Send graceful restart capabilty */ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp, peer->bgp->peer); - bgp_start(peer); - return 0; + return bgp_start(peer); } -static int bgp_fsm_open(struct peer *peer) +static enum bgp_fsm_state_progress bgp_fsm_open(struct peer *peer) { /* If DelayOpen is active, we may still need to send an open message */ if ((peer->status == Connect) || (peer->status == Active)) @@ -1969,12 +1978,12 @@ static int bgp_fsm_open(struct peer *peer) /* Send keepalive and make keepalive timer */ bgp_keepalive_send(peer); - return 0; + return BGP_FSM_SUCCESS; } /* FSM error, unexpected event. This is error of BGP connection. So cut the peer and change to Idle status. */ -static int bgp_fsm_event_error(struct peer *peer) +static enum bgp_fsm_state_progress bgp_fsm_event_error(struct peer *peer) { flog_err(EC_BGP_FSM, "%s [FSM] unexpected packet received in state %s", peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); @@ -1985,7 +1994,7 @@ static int bgp_fsm_event_error(struct peer *peer) /* Hold timer expire. This is error of BGP connection. So cut the peer and change to Idle status. */ -static int bgp_fsm_holdtime_expire(struct peer *peer) +static enum bgp_fsm_state_progress bgp_fsm_holdtime_expire(struct peer *peer) { if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [FSM] Hold timer expire", peer->host); @@ -2003,7 +2012,8 @@ static int bgp_fsm_holdtime_expire(struct peer *peer) } /* RFC 4271 DelayOpenTimer_Expires event */ -static int bgp_fsm_delayopen_timer_expire(struct peer *peer) +static enum bgp_fsm_state_progress +bgp_fsm_delayopen_timer_expire(struct peer *peer) { /* Stop the DelayOpenTimer */ THREAD_OFF(peer->t_delayopen); @@ -2014,7 +2024,7 @@ static int bgp_fsm_delayopen_timer_expire(struct peer *peer) /* Set the HoldTimer to a large value (4 minutes) */ peer->v_holdtime = 245; - return 0; + return BGP_FSM_SUCCESS; } /* Start the selection deferral timer thread for the specified AFI, SAFI */ @@ -2095,25 +2105,28 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi) * Convert peer from stub to full fledged peer, set some timers, and generate * initial updates. */ -static int bgp_establish(struct peer *peer) +static enum bgp_fsm_state_progress bgp_establish(struct peer *peer) { afi_t afi; safi_t safi; int nsf_af_count = 0; - int ret = 0; + enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS; struct peer *other; int status; other = peer->doppelganger; + hash_release(peer->bgp->peerhash, peer); + if (other) + hash_release(peer->bgp->peerhash, other); + peer = peer_xfer_conn(peer); if (!peer) { flog_err(EC_BGP_CONNECT, "%%Neighbor failed in xfer_conn"); - return -1; + return BGP_FSM_FAILURE; } if (other == peer) - ret = 1; /* bgp_establish specific code when xfer_conn - happens. */ + ret = BGP_FSM_SUCCESS_STATE_TRANSFER; /* Reset capability open status flag. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN)) @@ -2309,7 +2322,6 @@ static int bgp_establish(struct peer *peer) * the doppelgangers su and this peer's su are the same * so the hash_release is the same for either. */ - hash_release(peer->bgp->peerhash, peer); (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); /* Start BFD peer if not already running. */ @@ -2320,21 +2332,21 @@ static int bgp_establish(struct peer *peer) } /* Keepalive packet is received. */ -static int bgp_fsm_keepalive(struct peer *peer) +static enum bgp_fsm_state_progress bgp_fsm_keepalive(struct peer *peer) { THREAD_OFF(peer->t_holdtime); - return 0; + return BGP_FSM_SUCCESS; } /* Update packet is received. */ -static int bgp_fsm_update(struct peer *peer) +static enum bgp_fsm_state_progress bgp_fsm_update(struct peer *peer) { THREAD_OFF(peer->t_holdtime); - return 0; + return BGP_FSM_SUCCESS; } /* This is empty event. */ -static int bgp_ignore(struct peer *peer) +static enum bgp_fsm_state_progress bgp_ignore(struct peer *peer) { flog_err( EC_BGP_FSM, @@ -2343,11 +2355,11 @@ static int bgp_ignore(struct peer *peer) lookup_msg(bgp_status_msg, peer->status, NULL), bgp_event_str[peer->last_event], bgp_event_str[peer->last_major_event], peer->fd); - return 0; + return BGP_FSM_SUCCESS; } /* This is to handle unexpected events.. */ -static int bgp_fsm_exeption(struct peer *peer) +static enum bgp_fsm_state_progress bgp_fsm_exception(struct peer *peer) { flog_err( EC_BGP_FSM, @@ -2356,7 +2368,7 @@ static int bgp_fsm_exeption(struct peer *peer) lookup_msg(bgp_status_msg, peer->status, NULL), bgp_event_str[peer->last_event], bgp_event_str[peer->last_major_event], peer->fd); - return (bgp_stop(peer)); + return bgp_stop(peer); } void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops) @@ -2397,7 +2409,7 @@ void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops) /* Finite State Machine structure */ static const struct { - int (*func)(struct peer *); + enum bgp_fsm_state_progress (*func)(struct peer *); enum bgp_fsm_status next_state; } FSM[BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] = { { @@ -2428,19 +2440,19 @@ static const struct { {bgp_connect_success, OpenSent}, /* TCP_connection_open */ {bgp_connect_success_w_delayopen, Connect}, /* TCP_connection_open_w_delay */ - {bgp_stop, Idle}, /* TCP_connection_closed */ + {bgp_stop, Idle}, /* TCP_connection_closed */ {bgp_connect_fail, Active}, /* TCP_connection_open_failed */ {bgp_connect_fail, Idle}, /* TCP_fatal_error */ {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */ - {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */ - {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */ + {bgp_fsm_exception, Idle}, /* Hold_Timer_expired */ + {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */ {bgp_fsm_delayopen_timer_expire, OpenSent}, /* DelayOpen_timer_expired */ {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ - {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */ - {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */ - {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ - {bgp_fsm_exeption, Idle}, /* Clearing_Completed */ + {bgp_fsm_exception, Idle}, /* Receive_KEEPALIVE_message */ + {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */ + {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ + {bgp_fsm_exception, Idle}, /* Clearing_Completed */ }, { /* Active, */ @@ -2448,97 +2460,97 @@ static const struct { {bgp_stop, Idle}, /* BGP_Stop */ {bgp_connect_success, OpenSent}, /* TCP_connection_open */ {bgp_connect_success_w_delayopen, - Active}, /* TCP_connection_open_w_delay */ - {bgp_stop, Idle}, /* TCP_connection_closed */ - {bgp_ignore, Active}, /* TCP_connection_open_failed */ - {bgp_fsm_exeption, Idle}, /* TCP_fatal_error */ - {bgp_start, Connect}, /* ConnectRetry_timer_expired */ - {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */ - {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */ + Active}, /* TCP_connection_open_w_delay */ + {bgp_stop, Idle}, /* TCP_connection_closed */ + {bgp_ignore, Active}, /* TCP_connection_open_failed */ + {bgp_fsm_exception, Idle}, /* TCP_fatal_error */ + {bgp_start, Connect}, /* ConnectRetry_timer_expired */ + {bgp_fsm_exception, Idle}, /* Hold_Timer_expired */ + {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */ {bgp_fsm_delayopen_timer_expire, OpenSent}, /* DelayOpen_timer_expired */ {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ - {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */ - {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */ - {bgp_fsm_exeption, Idle}, /* Receive_NOTIFICATION_message */ - {bgp_fsm_exeption, Idle}, /* Clearing_Completed */ + {bgp_fsm_exception, Idle}, /* Receive_KEEPALIVE_message */ + {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */ + {bgp_fsm_exception, Idle}, /* Receive_NOTIFICATION_message */ + {bgp_fsm_exception, Idle}, /* Clearing_Completed */ }, { /* OpenSent, */ - {bgp_ignore, OpenSent}, /* BGP_Start */ - {bgp_stop, Idle}, /* BGP_Stop */ - {bgp_stop, Active}, /* TCP_connection_open */ - {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */ - {bgp_stop, Active}, /* TCP_connection_closed */ - {bgp_stop, Active}, /* TCP_connection_open_failed */ - {bgp_stop, Active}, /* TCP_fatal_error */ - {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */ + {bgp_ignore, OpenSent}, /* BGP_Start */ + {bgp_stop, Idle}, /* BGP_Stop */ + {bgp_stop, Active}, /* TCP_connection_open */ + {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */ + {bgp_stop, Active}, /* TCP_connection_closed */ + {bgp_stop, Active}, /* TCP_connection_open_failed */ + {bgp_stop, Active}, /* TCP_fatal_error */ + {bgp_fsm_exception, Idle}, /* ConnectRetry_timer_expired */ {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ - {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */ - {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */ + {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */ + {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */ {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ {bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */ {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_fsm_event_error, Idle}, /* Receive_NOTIFICATION_message */ - {bgp_fsm_exeption, Idle}, /* Clearing_Completed */ + {bgp_fsm_exception, Idle}, /* Clearing_Completed */ }, { /* OpenConfirm, */ {bgp_ignore, OpenConfirm}, /* BGP_Start */ - {bgp_stop, Idle}, /* BGP_Stop */ - {bgp_stop, Idle}, /* TCP_connection_open */ - {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */ - {bgp_stop, Idle}, /* TCP_connection_closed */ - {bgp_stop, Idle}, /* TCP_connection_open_failed */ - {bgp_stop, Idle}, /* TCP_fatal_error */ - {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */ + {bgp_stop, Idle}, /* BGP_Stop */ + {bgp_stop, Idle}, /* TCP_connection_open */ + {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */ + {bgp_stop, Idle}, /* TCP_connection_closed */ + {bgp_stop, Idle}, /* TCP_connection_open_failed */ + {bgp_stop, Idle}, /* TCP_fatal_error */ + {bgp_fsm_exception, Idle}, /* ConnectRetry_timer_expired */ {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */ - {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */ - {bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */ + {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */ + {bgp_fsm_exception, Idle}, /* Receive_OPEN_message */ {bgp_establish, Established}, /* Receive_KEEPALIVE_message */ - {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */ + {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ - {bgp_fsm_exeption, Idle}, /* Clearing_Completed */ + {bgp_fsm_exception, Idle}, /* Clearing_Completed */ }, { /* Established, */ {bgp_ignore, Established}, /* BGP_Start */ - {bgp_stop, Clearing}, /* BGP_Stop */ - {bgp_stop, Clearing}, /* TCP_connection_open */ - {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */ - {bgp_stop, Clearing}, /* TCP_connection_closed */ - {bgp_stop, Clearing}, /* TCP_connection_open_failed */ - {bgp_stop, Clearing}, /* TCP_fatal_error */ - {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ + {bgp_stop, Clearing}, /* BGP_Stop */ + {bgp_stop, Clearing}, /* TCP_connection_open */ + {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */ + {bgp_stop, Clearing}, /* TCP_connection_closed */ + {bgp_stop, Clearing}, /* TCP_connection_open_failed */ + {bgp_stop, Clearing}, /* TCP_fatal_error */ + {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ {bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */ {bgp_ignore, Established}, /* KeepAlive_timer_expired */ - {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */ - {bgp_stop, Clearing}, /* Receive_OPEN_message */ + {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */ + {bgp_stop, Clearing}, /* Receive_OPEN_message */ {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */ {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ {bgp_stop_with_error, - Clearing}, /* Receive_NOTIFICATION_message */ - {bgp_fsm_exeption, Idle}, /* Clearing_Completed */ + Clearing}, /* Receive_NOTIFICATION_message */ + {bgp_fsm_exception, Idle}, /* Clearing_Completed */ }, { /* Clearing, */ {bgp_ignore, Clearing}, /* BGP_Start */ - {bgp_stop, Clearing}, /* BGP_Stop */ - {bgp_stop, Clearing}, /* TCP_connection_open */ - {bgp_stop, Clearing}, /* TCP_connection_open_w_delay */ - {bgp_stop, Clearing}, /* TCP_connection_closed */ - {bgp_stop, Clearing}, /* TCP_connection_open_failed */ - {bgp_stop, Clearing}, /* TCP_fatal_error */ - {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ - {bgp_stop, Clearing}, /* Hold_Timer_expired */ - {bgp_stop, Clearing}, /* KeepAlive_timer_expired */ - {bgp_stop, Clearing}, /* DelayOpen_timer_expired */ - {bgp_stop, Clearing}, /* Receive_OPEN_message */ - {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */ - {bgp_stop, Clearing}, /* Receive_UPDATE_message */ - {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */ + {bgp_stop, Clearing}, /* BGP_Stop */ + {bgp_stop, Clearing}, /* TCP_connection_open */ + {bgp_stop, Clearing}, /* TCP_connection_open_w_delay */ + {bgp_stop, Clearing}, /* TCP_connection_closed */ + {bgp_stop, Clearing}, /* TCP_connection_open_failed */ + {bgp_stop, Clearing}, /* TCP_fatal_error */ + {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ + {bgp_stop, Clearing}, /* Hold_Timer_expired */ + {bgp_stop, Clearing}, /* KeepAlive_timer_expired */ + {bgp_stop, Clearing}, /* DelayOpen_timer_expired */ + {bgp_stop, Clearing}, /* Receive_OPEN_message */ + {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */ + {bgp_stop, Clearing}, /* Receive_UPDATE_message */ + {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_clearing_completed, Idle}, /* Clearing_Completed */ }, { @@ -2571,13 +2583,15 @@ void bgp_event(struct thread *thread) peer = THREAD_ARG(thread); event = THREAD_VAL(thread); + peer_lock(peer); bgp_event_update(peer, event); + peer_unlock(peer); } int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) { enum bgp_fsm_status next; - int ret = 0; + enum bgp_fsm_state_progress ret = 0; struct peer *other; int passive_conn = 0; int dyn_nbr; @@ -2606,8 +2620,9 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) if (FSM[peer->status - 1][event - 1].func) ret = (*(FSM[peer->status - 1][event - 1].func))(peer); - if (ret >= 0) { - if (ret == 1 && next == Established) { + if (ret >= BGP_FSM_SUCCESS) { + if (ret == BGP_FSM_SUCCESS_STATE_TRANSFER && + next == Established) { /* The case when doppelganger swap accurred in bgp_establish. Update the peer pointer accordingly */ @@ -2641,7 +2656,8 @@ int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) * we need to indicate that the peer was stopped in the return * code. */ - if (!dyn_nbr && !passive_conn && peer->bgp) { + if (!dyn_nbr && !passive_conn && peer->bgp && + ret != BGP_FSM_FAILURE_AND_DELETE) { flog_err( EC_BGP_FSM, "%s [FSM] Failure handling event %s in state %s, prior events %s, %s, fd %d", diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index b39a7daa1d..0e83157ecd 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -36,6 +36,10 @@ #include "bgpd/bgp_keepalives.h" /* clang-format on */ +DEFINE_MTYPE_STATIC(BGPD, BGP_PKAT, "Peer KeepAlive Timer"); +DEFINE_MTYPE_STATIC(BGPD, BGP_COND, "BGP Peer pthread Conditional"); +DEFINE_MTYPE_STATIC(BGPD, BGP_MUTEX, "BGP Peer pthread Mutex"); + /* * Peer KeepAlive Timer. * Associates a peer with the time of its last keepalive. @@ -54,7 +58,7 @@ static struct hash *peerhash; static struct pkat *pkat_new(struct peer *peer) { - struct pkat *pkat = XMALLOC(MTYPE_TMP, sizeof(struct pkat)); + struct pkat *pkat = XMALLOC(MTYPE_BGP_PKAT, sizeof(struct pkat)); pkat->peer = peer; monotime(&pkat->last); return pkat; @@ -62,7 +66,7 @@ static struct pkat *pkat_new(struct peer *peer) static void pkat_del(void *pkat) { - XFREE(MTYPE_TMP, pkat); + XFREE(MTYPE_BGP_PKAT, pkat); } @@ -158,8 +162,8 @@ static void bgp_keepalives_finish(void *arg) pthread_mutex_destroy(peerhash_mtx); pthread_cond_destroy(peerhash_cond); - XFREE(MTYPE_TMP, peerhash_mtx); - XFREE(MTYPE_TMP, peerhash_cond); + XFREE(MTYPE_BGP_MUTEX, peerhash_mtx); + XFREE(MTYPE_BGP_COND, peerhash_cond); } /* @@ -184,8 +188,8 @@ void *bgp_keepalives_start(void *arg) */ rcu_read_unlock(); - peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t)); - peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t)); + peerhash_mtx = XCALLOC(MTYPE_BGP_MUTEX, sizeof(pthread_mutex_t)); + peerhash_cond = XCALLOC(MTYPE_BGP_COND, sizeof(pthread_cond_t)); /* initialize mutex */ pthread_mutex_init(peerhash_mtx, NULL); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 52f6b64c2c..32a5e14b11 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -567,7 +567,7 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (debug) zlog_debug( - "%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw u%" PRIu64, + "%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64, bgp_dest_to_rnode(dest), bgp->name_pretty, new_best ? new_best->peer->host : "NONE", mp_list ? listcount(mp_list) : 0, old_mpath_count, @@ -750,7 +750,7 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (debug) zlog_debug( - "%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw u%" PRIu64, + "%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64, bgp_dest_to_rnode(dest), bgp->name_pretty, mpath_count, mpath_changed ? "YES" : "NO", all_paths_lb, cum_bw); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 18cb90763c..12b68f2607 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -888,7 +888,7 @@ void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf, srv6_locator_chunk_free(&bgp_vrf->vpn_policy[afi].tovpn_sid_locator); if (bgp_vrf->vpn_policy[afi].tovpn_sid) { - sid_unregister(bgp_vrf, bgp_vrf->vpn_policy[afi].tovpn_sid); + sid_unregister(bgp_vpn, bgp_vrf->vpn_policy[afi].tovpn_sid); XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid); } bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label = 0; @@ -915,7 +915,7 @@ void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf) srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator); if (bgp_vrf->tovpn_sid) { - sid_unregister(bgp_vrf, bgp_vrf->tovpn_sid); + sid_unregister(bgp_vpn, bgp_vrf->tovpn_sid); XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid); } bgp_vrf->tovpn_sid_transpose_label = 0; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index b43f8c8664..7186a50711 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -553,9 +553,7 @@ static void bgp_accept(struct thread *thread) peer1->host); peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as, - peer1->as, peer1->as_type, NULL); - hash_release(peer->bgp->peerhash, peer); - (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); + peer1->as, peer1->as_type, NULL, false); peer_xfer_config(peer, peer1); bgp_peer_gr_flags_update(peer); @@ -572,8 +570,6 @@ static void bgp_accept(struct thread *thread) } } - UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - peer->doppelganger = peer1; peer1->doppelganger = peer; peer->fd = bgp_sock; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 027cb20e41..9fb8d7cfee 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2197,7 +2197,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* If we're a CONFED we need to loop check the CONFED ID too */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { - if (aspath_loop_check(piattr->aspath, bgp->confed_id)) { + if (aspath_loop_check_confed(piattr->aspath, bgp->confed_id)) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( "%pBP [Update:SEND] suppress announcement to peer AS %u is AS path.", @@ -4114,16 +4114,23 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* AS path loop check. */ if (do_loop_check) { - if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in || - (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) && - (aspath_loop_check(attr->aspath, bgp->confed_id) > - allowas_in))) { + if (aspath_loop_check(attr->aspath, bgp->as) > + peer->allowas_in[afi][safi]) { peer->stat_pfx_aspath_loop++; reason = "as-path contains our own AS;"; goto filtered; } } + /* If we're a CONFED we need to loop check the CONFED ID too */ + if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) && do_loop_check) + if (aspath_loop_check_confed(attr->aspath, bgp->confed_id) > + peer->allowas_in[afi][safi]) { + peer->stat_pfx_aspath_loop++; + reason = "as-path contains our own confed AS;"; + goto filtered; + } + /* Route reflector originator ID check. If ACCEPT_OWN mechanism is * enabled, then take care of that too. */ @@ -9613,7 +9620,7 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, json_status = json_object_new_object(); json_net = json_object_new_object(); } else { - vty_out(vty, "*"); + vty_out(vty, " *"); vty_out(vty, ">"); vty_out(vty, " "); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1f532d4990..7b9400118b 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1960,13 +1960,6 @@ DEFUN (bgp_confederation_peers, for (i = idx_asn; i < argc; i++) { as = strtoul(argv[i]->arg, NULL, 10); - - if (bgp->as == as) { - vty_out(vty, - "%% Local member-AS not allowed in confed peer list\n"); - continue; - } - bgp_confederation_peers_add(bgp, as); } return CMD_SUCCESS; @@ -4685,7 +4678,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type); } else { peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type, - NULL); + NULL, true); if (!peer) { vty_out(vty, "%% BGP failed to create peer\n"); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 12ee96ff45..734e44f252 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -671,7 +671,7 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as) struct peer *peer; struct listnode *node, *nnode; - if (bgp->as == as) + if (!bgp) return; if (bgp_confederation_peers_check(bgp, as)) @@ -687,8 +687,8 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as) if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (peer->as == as) { - (void)peer_sort(peer); peer->local_as = bgp->as; + (void)peer_sort(peer); if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->status)) { peer->last_reset = @@ -738,8 +738,8 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as) if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (peer->as == as) { - (void)peer_sort(peer); peer->local_as = bgp->confed_id; + (void)peer_sort(peer); if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->status)) { peer->last_reset = @@ -950,6 +950,7 @@ static bool peer_hash_same(const void *p1, const void *p2) { const struct peer *peer1 = p1; const struct peer *peer2 = p2; + return (sockunion_same(&peer1->su, &peer2->su) && CHECK_FLAG(peer1->flags, PEER_FLAG_CONFIG_NODE) == CHECK_FLAG(peer2->flags, PEER_FLAG_CONFIG_NODE)); @@ -1127,6 +1128,7 @@ static void peer_free(struct peer *peer) bgp_timer_set(peer); bgp_reads_off(peer); bgp_writes_off(peer); + thread_cancel_event_ready(bm->master, peer); FOREACH_AFI_SAFI (afi, safi) THREAD_OFF(peer->t_revalidate_all[afi][safi]); assert(!peer->t_write); @@ -1457,7 +1459,10 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) /* peer flags apply */ peer_dst->flags = peer_src->flags; - + /* + * The doppelganger *must* not have a config node stored + */ + UNSET_FLAG(peer_dst->flags, PEER_FLAG_CONFIG_NODE); peer_dst->peer_gr_present_state = peer_src->peer_gr_present_state; peer_dst->peer_gr_new_status_flag = peer_src->peer_gr_new_status_flag; @@ -1613,15 +1618,18 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) struct interface *ifp; int prev_family; int peer_addr_updated = 0; + struct listnode *node; + union sockunion old_su; + /* + * This function is only ever needed when FRR an interface + * based peering, so this simple test will tell us if + * we are in an interface based configuration or not + */ if (!peer->conf_if) return; - /* - * Our peer structure is stored in the bgp->peerhash - * release it before we modify anything. - */ - hash_release(peer->bgp->peerhash, peer); + old_su = peer->su; prev_family = peer->su.sa.sa_family; if ((ifp = if_lookup_by_name(peer->conf_if, peer->bgp->vrf_id))) { @@ -1664,9 +1672,48 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) } /* - * Since our su changed we need to del/add peer to the peerhash + * If they are the same, nothing to do here, move along */ - (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); + if (!sockunion_same(&old_su, &peer->su)) { + union sockunion new_su = peer->su; + struct bgp *bgp = peer->bgp; + + /* + * Our peer structure is stored in the bgp->peerhash + * release it before we modify anything in both the + * hash and the list. But *only* if the peer + * is in the bgp->peerhash as that on deletion + * we call bgp_stop which calls this function :( + * so on deletion let's remove from the list first + * and then do the deletion preventing this from + * being added back on the list below when we + * fail to remove it up here. + */ + + /* + * listnode_lookup just scans the list + * for the peer structure so it's safe + * to use without modifying the su + */ + node = listnode_lookup(bgp->peer, peer); + if (node) { + /* + * Let's reset the peer->su release and + * reset it and put it back. We have to + * do this because hash_release will + * scan through looking for a matching + * su if needed. + */ + peer->su = old_su; + hash_release(peer->bgp->peerhash, peer); + listnode_delete(peer->bgp->peer, peer); + + peer->su = new_su; + (void)hash_get(peer->bgp->peerhash, peer, + hash_alloc_intern); + listnode_add_sort(peer->bgp->peer, peer); + } + } } void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, safi_t safi) @@ -1715,7 +1762,8 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp) */ struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group) + int as_type, struct peer_group *group, + bool config_node) { int active; struct peer *peer; @@ -1753,6 +1801,10 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, peer = peer_lock(peer); /* bgp peer list reference */ peer->group = group; listnode_add_sort(bgp->peer, peer); + + if (config_node) + SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); + (void)hash_get(bgp->peerhash, peer, hash_alloc_intern); /* Adjust update-group coalesce timer heuristics for # peers. */ @@ -1780,8 +1832,6 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, /* Default configured keepalives count for shutdown rtt command */ peer->rtt_keepalive_conf = 1; - SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - /* If 'bgp default <afi>-<safi>' is configured, then activate the * neighbor for the corresponding address family. IPv4 Unicast is * the only address family enabled by default without expliict @@ -1816,6 +1866,7 @@ struct peer *peer_create_accept(struct bgp *bgp) peer = peer_lock(peer); /* bgp peer list reference */ listnode_add_sort(bgp->peer, peer); + (void)hash_get(bgp->peerhash, peer, hash_alloc_intern); return peer; } @@ -1987,7 +2038,8 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, else local_as = bgp->as; - peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL); + peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL, + true); } return 0; @@ -2446,6 +2498,7 @@ int peer_delete(struct peer *peer) bgp_keepalives_off(peer); bgp_reads_off(peer); bgp_writes_off(peer); + thread_cancel_event_ready(bm->master, peer); FOREACH_AFI_SAFI (afi, safi) THREAD_OFF(peer->t_revalidate_all[afi][safi]); assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON)); @@ -2509,9 +2562,16 @@ int peer_delete(struct peer *peer) /* Delete from all peer list. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) && (pn = listnode_lookup(bgp->peer, peer))) { - peer_unlock(peer); /* bgp peer list reference */ + /* + * Removing from the list node first because + * peer_unlock *can* call peer_delete( I know, + * I know ). So let's remove it and in + * the su recalculate function we'll ensure + * it's in there or not. + */ list_delete_node(bgp->peer, pn); hash_release(bgp->peerhash, peer); + peer_unlock(peer); /* bgp peer list reference */ } /* Buffers. */ @@ -2649,6 +2709,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, { uint32_t flags_tmp; struct peer *conf; + bool config_node = !!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); conf = group->conf; @@ -2676,6 +2737,9 @@ static void peer_group2peer_config_copy(struct peer_group *group, SET_FLAG(peer->flags, flags_tmp); SET_FLAG(peer->flags_invert, conf->flags_invert); + if (config_node) + SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); + /* peer timers apply */ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER)) { PEER_ATTR_INHERIT(peer, group, holdtime); @@ -3077,7 +3141,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, } peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as, - group->conf->as_type, group); + group->conf->as_type, group, true); peer = peer_lock(peer); /* group->peer list reference */ listnode_add(group->peer, peer); @@ -3099,8 +3163,6 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, peer_deactivate(peer, afi, safi); } - SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - /* Set up peer's events and timers. */ if (peer_active(peer)) bgp_timer_set(peer); @@ -3723,8 +3785,10 @@ int bgp_delete(struct bgp *bgp) for (ALL_LIST_ELEMENTS(bgp->group, node, next, group)) peer_group_delete(group); - for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) + while (listcount(bgp->peer)) { + peer = listnode_head(bgp->peer); peer_delete(peer); + } if (bgp->peer_self) { peer_delete(bgp->peer_self); @@ -3971,7 +4035,7 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp, /* Create peer first; we've already checked group config is valid. */ peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as, - group->conf->as_type, group); + group->conf->as_type, group, true); if (!peer) return NULL; @@ -4000,7 +4064,6 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp, /* Mark as dynamic, but also as a "config node" for other things to * work. */ SET_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR); - SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); return peer; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index b7a329fdcd..a75bfdf746 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -2177,8 +2177,10 @@ extern bool peer_active_nego(struct peer *); extern bool peer_afc_received(struct peer *peer); extern bool peer_afc_advertised(struct peer *peer); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); -extern struct peer *peer_create(union sockunion *, const char *, struct bgp *, - as_t, as_t, int, struct peer_group *); +extern struct peer *peer_create(union sockunion *su, const char *conf_if, + struct bgp *bgp, as_t local_as, as_t remote_as, + int as_type, struct peer_group *group, + bool config_node); extern struct peer *peer_create_accept(struct bgp *); extern void peer_xfer_config(struct peer *dst, struct peer *src); extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, diff --git a/configure.ac b/configure.ac index 97c8ca451b..8040a1644a 100644 --- a/configure.ac +++ b/configure.ac @@ -636,7 +636,7 @@ AC_ARG_ENABLE([isisd], AC_ARG_ENABLE([pimd], AS_HELP_STRING([--disable-pimd], [do not build pimd])) AC_ARG_ENABLE([pim6d], - AS_HELP_STRING([--enable-pim6d], [build pim6d])) + AS_HELP_STRING([--disable-pim6d], [do not build pim6d])) AC_ARG_ENABLE([pbrd], AS_HELP_STRING([--disable-pbrd], [do not build pbrd])) AC_ARG_ENABLE([sharpd], @@ -1765,7 +1765,7 @@ AS_IF([test "$enable_pimd" != "no"], [ AC_DEFINE([HAVE_PIMD], [1], [pimd]) ]) -AS_IF([test "$enable_pim6d" = "yes"], [ +AS_IF([test "$enable_pim6d" != "no"], [ AC_DEFINE([HAVE_PIM6D], [1], [pim6d]) ]) @@ -2078,7 +2078,7 @@ if test "$enable_rpki" = "yes"; then fi dnl ------------------------------------ -dnl pimd is not supported on OpenBSD and MacOS +dnl pimd and pim6d not supported on OpenBSD and MacOS dnl ------------------------------------ if test "$enable_pimd" != "no"; then AC_MSG_CHECKING([for pimd OS support]) @@ -2097,6 +2097,23 @@ case "$host_os" in esac fi +if test "$enable_pim6d" != "no"; then +AC_MSG_CHECKING([for pim6d OS support]) +case "$host_os" in + darwin*) + AC_MSG_RESULT([no]) + enable_pim6d="no" + ;; + openbsd*) + AC_MSG_RESULT([no]) + enable_pim6d="no" + ;; + *) + AC_MSG_RESULT([yes]) + ;; +esac +fi + dnl ------------------------------------- dnl VRRP is only supported on linux dnl ------------------------------------- @@ -2730,7 +2747,7 @@ AM_CONDITIONAL([BABELD], [test "$enable_babeld" != "no"]) AM_CONDITIONAL([OSPF6D], [test "$enable_ospf6d" != "no"]) AM_CONDITIONAL([ISISD], [test "$enable_isisd" != "no"]) AM_CONDITIONAL([PIMD], [test "$enable_pimd" != "no"]) -AM_CONDITIONAL([PIM6D], [test "$enable_pim6d" = "yes"]) +AM_CONDITIONAL([PIM6D], [test "$enable_pim6d" != "no"]) AM_CONDITIONAL([PBRD], [test "$enable_pbrd" != "no"]) AM_CONDITIONAL([SHARPD], [test "$enable_sharpd" = "yes"]) AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"]) diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 7679a377eb..4a64d8f949 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -617,6 +617,10 @@ Terminal Mode Commands usage is printed sequentially. You can specify the daemon's name to print only its memory usage. +.. clicmd:: show motd + + Show current motd banner. + .. clicmd:: show history Dump the vtysh cli history. diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 98338ebf32..830d3c5762 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2418,9 +2418,9 @@ in AS 7675, the announced routes' local preference value will be set to 80. The following configuration is an example of BGP route filtering using communities attribute. This configuration only permit BGP routes which has BGP -communities value ``0:80`` or ``0:90``. The network operator can set special -internal communities value at BGP border router, then limit the BGP route -announcements into the internal network. +communities value (``0:80`` and ``0:90``) or ``0:100``. The network operator can +set special internal communities value at BGP border router, then limit the +BGP route announcements into the internal network. .. code-block:: frr @@ -2431,6 +2431,7 @@ announcements into the internal network. exit-address-family ! bgp community-list 1 permit 0:80 0:90 + bgp community-list 1 permit 0:100 ! route-map RMAP permit in match community 1 diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst index 44a56f2fca..ef3aebeafa 100644 --- a/doc/user/vrrp.rst +++ b/doc/user/vrrp.rst @@ -393,6 +393,11 @@ All interface configuration commands are documented below. higher priority to take over Master status from the existing Master. Enabled by default. +.. clicmd:: vrrp (1-255) checksum-with-ipv4-pseudoheader + + Specify whether VRRPv3 checksum should involve IPv4 pseudoheader. This + command should not affect VRRPv2 and IPv6. Enabled by default. + .. clicmd:: vrrp (1-255) priority (1-254) Set the router priority. The router with the highest priority is elected as @@ -448,7 +453,7 @@ Show commands, global defaults and debugging configuration commands. zebra Logs communications with Zebra. -.. clicmd:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown> +.. clicmd:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|checksum-with-ipv4-pseudoheader|shutdown> Configure defaults for new VRRP routers. These values will not affect already configured VRRP routers, but will be applied to newly configured @@ -550,3 +555,19 @@ feature instead, explained `here <https://www.virtuallyghetto.com/2018/04/native-mac-learning-in-vsphere-6-7-removes-the-need-for-promiscuous-mode-for-nested-esxi.html>`_. Issue reference: https://github.com/FRRouting/frr/issues/5386 + + +My router cannot interoperate with branded routers / L3 switches +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +FRR includes a pseudoheader when calculating VRRPv3 checksums by default, +regardless of whether it's IPv4 or IPv6. + +Some vendors have different interpretations of `VRRPv3 RFC 5798 #5.2.8 +<https://www.rfc-editor.org/rfc/rfc5798.html#section-5.2.8>`_. In such cases, +their checksums are calculated with a pseudoheader only when it comes to IPv6. + +You need to disable ``checksum-with-ipv4-pseudoheader`` so that FRR computes and +accepts such checksums. + +Issue reference: https://github.com/FRRouting/frr/issues/9951 diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 238a7fc409..afc6be2312 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # Create a basic stage set up to build APKs -FROM alpine:3.16 as alpine-builder +FROM alpine:3.17 as alpine-builder RUN apk add \ --update-cache \ abuild \ @@ -13,7 +13,7 @@ RUN apk add \ RUN adduser -D -G abuild builder && su builder -c 'abuild-keygen -a -n' # This stage builds a dist tarball from the source -FROM alpine:3.16 as source-builder +FROM alpine:3.17 as source-builder RUN mkdir -p /src/alpine COPY alpine/APKBUILD.in /src/alpine @@ -48,7 +48,7 @@ RUN cd /dist \ && abuild -r -P /pkgs/apk # This stage installs frr from the apk -FROM alpine:3.16 +FROM alpine:3.17 RUN mkdir -p /pkgs/apk COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/ RUN apk add \ diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 1b5c0e90fb..35d2bf21c9 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -208,7 +208,6 @@ ldpe_shutdown(void) iev_main_sync->ibuf.fd = -1; control_cleanup(ctl_sock_path); - config_clear(leconf); #ifdef __OpenBSD__ if (sysdep.no_pfkey == 0) { @@ -231,6 +230,7 @@ ldpe_shutdown(void) adj_del(adj, S_SHUTDOWN); } + config_clear(leconf); /* clean up */ if (iev_lde) free(iev_lde); @@ -38,6 +38,7 @@ #include "lib/if_clippy.c" DEFINE_MTYPE_STATIC(LIB, IF, "Interface"); +DEFINE_MTYPE_STATIC(LIB, IFDESC, "Intf Desc"); DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected"); DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected"); DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label"); @@ -288,7 +289,7 @@ void if_delete(struct interface **ifp) if_link_params_free(ptr); - XFREE(MTYPE_TMP, ptr->desc); + XFREE(MTYPE_IFDESC, ptr->desc); XFREE(MTYPE_IF, ptr); *ifp = NULL; @@ -1612,9 +1613,9 @@ static int lib_interface_description_modify(struct nb_cb_modify_args *args) return NB_OK; ifp = nb_running_get_entry(args->dnode, NULL, true); - XFREE(MTYPE_TMP, ifp->desc); + XFREE(MTYPE_IFDESC, ifp->desc); description = yang_dnode_get_string(args->dnode, NULL); - ifp->desc = XSTRDUP(MTYPE_TMP, description); + ifp->desc = XSTRDUP(MTYPE_IFDESC, description); return NB_OK; } @@ -1627,7 +1628,7 @@ static int lib_interface_description_destroy(struct nb_cb_destroy_args *args) return NB_OK; ifp = nb_running_get_entry(args->dnode, NULL, true); - XFREE(MTYPE_TMP, ifp->desc); + XFREE(MTYPE_IFDESC, ifp->desc); return NB_OK; } diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 2792820a54..55ac7c88a5 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -573,7 +573,7 @@ void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa, json = json_object_new_object(); size_t header_str_sz = (2 * (end - start)) + 1; - header_str = XMALLOC(MTYPE_TMP, header_str_sz); + header_str = XMALLOC(MTYPE_OSPF6_LSA_HEADER, header_str_sz); inet_ntop(AF_INET, &lsa->header->id, id, sizeof(id)); inet_ntop(AF_INET, &lsa->header->adv_router, adv_router, @@ -586,7 +586,7 @@ void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa, json_object_string_add(json, "header", header_str); json_object_array_add(json_array, json); - XFREE(MTYPE_TMP, header_str); + XFREE(MTYPE_OSPF6_LSA_HEADER, header_str); } else { vty_out(vty, "\n%s:\n", lsa->name); diff --git a/ospfclient/ospf_apiclient.c b/ospfclient/ospf_apiclient.c index 05c5e7789d..4982cd885e 100644 --- a/ospfclient/ospf_apiclient.c +++ b/ospfclient/ospf_apiclient.c @@ -54,10 +54,6 @@ #include "ospf_apiclient.h" -/* *sigh* ... can't find a better way to hammer this into automake */ -#include "ospfd/ospf_dump_api.c" -#include "ospfd/ospf_api.c" - XREF_SETUP(); DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient"); diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am index b8c82c0bcf..289ddd009d 100644 --- a/ospfclient/subdir.am +++ b/ospfclient/subdir.am @@ -27,6 +27,7 @@ endif ospfclient_ospfclient_LDADD = \ ospfclient/libfrrospfapiclient.la \ + ospfd/libfrrospfclient.a \ $(LIBCAP) \ # end diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 0c2ee0c4f8..6fd1c82c24 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -56,10 +56,14 @@ #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_errors.h" +#include "ospfd/ospf_memory.h" #include "ospfd/ospf_api.h" #include "ospfd/ospf_apiserver.h" +DEFINE_MTYPE_STATIC(OSPFD, APISERVER, "API Server"); +DEFINE_MTYPE_STATIC(OSPFD, APISERVER_MSGFILTER, "API Server Message Filter"); + /* This is an implementation of an API to the OSPF daemon that allows * external applications to access the OSPF daemon through socket * connections. The application can use this API to inject its own @@ -245,9 +249,9 @@ static int ospf_apiserver_del_lsa_hook(struct ospf_lsa *lsa) struct ospf_apiserver *ospf_apiserver_new(int fd_sync, int fd_async) { struct ospf_apiserver *new = - XMALLOC(MTYPE_OSPF_APISERVER, sizeof(struct ospf_apiserver)); + XMALLOC(MTYPE_APISERVER, sizeof(struct ospf_apiserver)); - new->filter = XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, + new->filter = XMALLOC(MTYPE_APISERVER_MSGFILTER, sizeof(struct lsa_filter_type)); new->fd_sync = fd_sync; @@ -360,7 +364,7 @@ void ospf_apiserver_free(struct ospf_apiserver *apiserv) (void *)apiserv, apiserver_list->count); /* And free instance. */ - XFREE(MTYPE_OSPF_APISERVER, apiserv); + XFREE(MTYPE_APISERVER, apiserv); } void ospf_apiserver_read(struct thread *thread) @@ -862,8 +866,8 @@ int ospf_apiserver_register_opaque_type(struct ospf_apiserver *apiserv, connection shuts down, we can flush all LSAs of this opaque type. */ - regtype = XCALLOC(MTYPE_OSPF_APISERVER, - sizeof(struct registered_opaque_type)); + regtype = + XCALLOC(MTYPE_APISERVER, sizeof(struct registered_opaque_type)); regtype->lsa_type = lsa_type; regtype->opaque_type = opaque_type; @@ -1155,12 +1159,12 @@ int ospf_apiserver_handle_register_event(struct ospf_apiserver *apiserv, seqnum = msg_get_seq(msg); /* Free existing filter in apiserv. */ - XFREE(MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter); + XFREE(MTYPE_APISERVER_MSGFILTER, apiserv->filter); /* Alloc new space for filter. */ size = ntohs(msg->hdr.msglen); if (size < OSPF_MAX_LSA_SIZE) { - apiserv->filter = XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, size); + apiserv->filter = XMALLOC(MTYPE_APISERVER_MSGFILTER, size); /* copy it over. */ memcpy(apiserv->filter, &rmsg->filter, size); @@ -1365,8 +1369,7 @@ int ospf_apiserver_handle_sync_reachable(struct ospf_apiserver *apiserv, goto out; /* send all adds based on current reachable routers */ - a = abuf = XCALLOC(MTYPE_OSPF_APISERVER, - sizeof(struct in_addr) * rt->count); + a = abuf = XCALLOC(MTYPE_APISERVER, sizeof(struct in_addr) * rt->count); for (struct route_node *rn = route_top(rt); rn; rn = route_next(rn)) if (listhead((struct list *)rn->info)) *a++ = rn->p.u.prefix4; @@ -1385,7 +1388,7 @@ int ospf_apiserver_handle_sync_reachable(struct ospf_apiserver *apiserv, rc = ospf_apiserver_send_msg(apiserv, amsg); msg_free(amsg); } - XFREE(MTYPE_OSPF_APISERVER, abuf); + XFREE(MTYPE_APISERVER, abuf); out: /* Send a reply back to client with return code */ @@ -2616,9 +2619,9 @@ void ospf_apiserver_notify_reachable(struct route_table *ort, return; } if (nrt && nrt->count) - a = abuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * nrt->count); + a = abuf = XCALLOC(MTYPE_APISERVER, insz * nrt->count); if (ort && ort->count) - d = dbuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * ort->count); + d = dbuf = XCALLOC(MTYPE_APISERVER, insz * ort->count); /* walk both tables */ orn = ort ? route_top(ort) : NULL; @@ -2683,9 +2686,9 @@ void ospf_apiserver_notify_reachable(struct route_table *ort, msg_free(msg); } if (abuf) - XFREE(MTYPE_OSPF_APISERVER, abuf); + XFREE(MTYPE_APISERVER, abuf); if (dbuf) - XFREE(MTYPE_OSPF_APISERVER, dbuf); + XFREE(MTYPE_APISERVER, dbuf); } diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h index e28202e46f..0a6b7319a0 100644 --- a/ospfd/ospf_apiserver.h +++ b/ospfd/ospf_apiserver.h @@ -26,10 +26,6 @@ #include "ospf_api.h" #include "ospf_lsdb.h" -/* MTYPE definition is not reflected to "memory.h". */ -#define MTYPE_OSPF_APISERVER MTYPE_TMP -#define MTYPE_OSPF_APISERVER_MSGFILTER MTYPE_TMP - /* List of opaque types that application registered */ struct registered_opaque_type { uint8_t lsa_type; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 9727c7039c..f1b876cfbe 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -50,6 +50,8 @@ #include "ospfd/ospf_route.h" #include "ospfd/ospf_zebra.h" +DEFINE_MTYPE_STATIC(OSPFD, SNMP, "OSPF SNMP"); + /* OSPF2-MIB. */ #define OSPF2MIB 1,3,6,1,2,1,14 @@ -1321,12 +1323,12 @@ struct ospf_snmp_if { static struct ospf_snmp_if *ospf_snmp_if_new(void) { - return XCALLOC(MTYPE_TMP, sizeof(struct ospf_snmp_if)); + return XCALLOC(MTYPE_SNMP, sizeof(struct ospf_snmp_if)); } static void ospf_snmp_if_free(struct ospf_snmp_if *osif) { - XFREE(MTYPE_TMP, osif); + XFREE(MTYPE_SNMP, osif); } static int ospf_snmp_if_delete(struct interface *ifp) diff --git a/ospfd/subdir.am b/ospfd/subdir.am index b67f942883..e45f617dfa 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -4,6 +4,7 @@ if OSPFD noinst_LIBRARIES += ospfd/libfrrospf.a +noinst_LIBRARIES += ospfd/libfrrospfclient.a sbin_PROGRAMS += ospfd/ospfd vtysh_daemons += ospfd if SNMP @@ -12,6 +13,11 @@ endif man8 += $(MANBUILD)/frr-ospfd.8 endif +ospfd_libfrrospfclient_a_SOURCES = \ + ospfd/ospf_api.c \ + ospfd/ospf_dump_api.c \ + #end + ospfd_libfrrospf_a_SOURCES = \ ospfd/ospf_abr.c \ ospfd/ospf_api.c \ @@ -104,7 +110,7 @@ noinst_HEADERS += \ ospfd/ospf_zebra.h \ # end -ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM) +ospfd_ospfd_LDADD = ospfd/libfrrospf.a ospfd/libfrrospfclient.a lib/libfrr.la $(LIBCAP) $(LIBM) ospfd_ospfd_SOURCES = ospfd/ospf_main.c ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c diff --git a/tests/topotests/bgp_comm_list_match/__init__.py b/tests/topotests/bgp_comm_list_match/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/__init__.py diff --git a/tests/topotests/bgp_comm_list_match/r1/bgpd.conf b/tests/topotests/bgp_comm_list_match/r1/bgpd.conf new file mode 100644 index 0000000000..89c9f7728e --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/r1/bgpd.conf @@ -0,0 +1,23 @@ +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.0.2 remote-as external + neighbor 192.168.0.2 timers 1 3 + neighbor 192.168.0.2 timers connect 1 + address-family ipv4 + redistribute connected + neighbor 192.168.0.2 route-map r2 out + exit-address-family +! +ip prefix-list p1 seq 5 permit 172.16.255.1/32 +ip prefix-list p3 seq 5 permit 172.16.255.3/32 +! +route-map r2 permit 10 + match ip address prefix-list p1 + set community 65001:1 65001:2 +route-map r2 permit 20 + match ip address prefix-list p3 + set community 65001:3 +route-map r2 permit 30 +exit +! diff --git a/tests/topotests/bgp_comm_list_match/r1/zebra.conf b/tests/topotests/bgp_comm_list_match/r1/zebra.conf new file mode 100644 index 0000000000..17d0ecceaf --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/r1/zebra.conf @@ -0,0 +1,11 @@ +! +interface lo + ip address 172.16.255.1/32 + ip address 172.16.255.2/32 + ip address 172.16.255.3/32 +! +interface r1-eth0 + ip address 192.168.0.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_comm_list_match/r2/bgpd.conf b/tests/topotests/bgp_comm_list_match/r2/bgpd.conf new file mode 100644 index 0000000000..35ad2d32e6 --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/r2/bgpd.conf @@ -0,0 +1,21 @@ +! +debug bgp updates +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.0.1 remote-as external + neighbor 192.168.0.1 timers 1 3 + neighbor 192.168.0.1 timers connect 1 + address-family ipv4 + neighbor 192.168.0.1 route-map r1 in + neighbor 192.168.0.1 soft-reconfiguration inbound + exit-address-family +! +bgp community-list 1 seq 5 permit 65001:1 65001:2 +bgp community-list 1 seq 10 permit 65001:3 +! +route-map r1 deny 10 + match community 1 +route-map r1 permit 20 +exit +! diff --git a/tests/topotests/bgp_comm_list_match/r2/zebra.conf b/tests/topotests/bgp_comm_list_match/r2/zebra.conf new file mode 100644 index 0000000000..a69c622352 --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.0.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py new file mode 100644 index 0000000000..1b8f73d233 --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2022 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# +# 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. +# + +""" +Check if BGP community-list works as OR if multiple community entries specified, +like: + +bgp community-list 1 seq 5 permit 65001:1 65002:2 +bgp community-list 1 seq 10 permit 65001:3 +! +route-map test deny 10 + match community 1 +route-map test permit 20 + +Here, we should deny routes in/out if the path has: +(65001:1 AND 65001:2) OR 65001:3. +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + 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.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_comm_list_match(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads( + router.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.0.1 filtered-routes json" + ) + ) + expected = { + "receivedRoutes": { + "172.16.255.1/32": { + "path": "65001", + }, + "172.16.255.3/32": { + "path": "65001", + }, + } + } + return topotest.json_cmp(output, expected) + + step("Initial BGP converge") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to filter BGP UPDATES with community-list on R2" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_confed1/__init__.py b/tests/topotests/bgp_confed1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_confed1/__init__.py diff --git a/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json new file mode 100644 index 0000000000..d3988eb0e7 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json @@ -0,0 +1,63 @@ +{ + "vrfId":0, + "vrfName":"default", + "routerId":"203.0.113.1", + "defaultLocPrf":100, + "localAS":100, + "routes":{"203.0.113.0/28":[ + { + "network":"203.0.113.0\/28", + "peerId":"(unspec)", + "path":"", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.16/28":[ + { + "network":"203.0.113.16\/28", + "peerId":"192.0.2.2", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.2", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.32/28":[ + { + "network":"203.0.113.32\/28", + "peerId":"192.0.2.2", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.2", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.48/28":[ + { + "network":"203.0.113.48\/28", + "peerId":"192.0.2.2", + "path":"300 400", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.2", + "afi":"ipv4", + "used":true + } + ] + } +] } } diff --git a/tests/topotests/bgp_confed1/r1/bgp_summary.json b/tests/topotests/bgp_confed1/r1/bgp_summary.json new file mode 100644 index 0000000000..f999021a20 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/bgp_summary.json @@ -0,0 +1,13 @@ +{ + "ipv4Unicast":{ + "routerId":"203.0.113.1", + "as":100, + "peers":{ + "192.0.2.2":{ + "remoteAs": 300, + "state": "Established", + "peerState":"OK" + } + } + } +} diff --git a/tests/topotests/bgp_confed1/r1/bgpd.conf b/tests/topotests/bgp_confed1/r1/bgpd.conf new file mode 100644 index 0000000000..8413ef7fc3 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/bgpd.conf @@ -0,0 +1,13 @@ +debug bgp neighbor-events +debug bgp nht +debug bgp updates in +debug bgp updates out +! +router bgp 100 + no bgp ebgp-requires-policy +! + neighbor 192.0.2.2 remote-as 300 + address-family ipv4 unicast + network 203.0.113.0/28 + exit-address-family +! diff --git a/tests/topotests/bgp_confed1/r1/isisd.conf b/tests/topotests/bgp_confed1/r1/isisd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/isisd.conf diff --git a/tests/topotests/bgp_confed1/r1/zebra.conf b/tests/topotests/bgp_confed1/r1/zebra.conf new file mode 100644 index 0000000000..5f76e74493 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/zebra.conf @@ -0,0 +1,6 @@ +interface r1-eth0 + ip address 192.0.2.1/28 +! +interface lo + ip address 203.0.113.1/28 +! diff --git a/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json new file mode 100644 index 0000000000..b4a0946072 --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json @@ -0,0 +1,63 @@ +{ + "vrfId":0, + "vrfName":"default", + "routerId":"203.0.113.17", + "defaultLocPrf":100, + "localAS":200, + "routes":{"203.0.113.0/28": [ + { + "network":"203.0.113.0\/28", + "peerId":"192.0.2.1", + "path":"100", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.1", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.16/28":[ + { + "network":"203.0.113.16\/28", + "peerId":"(unspec)", + "path":"", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.32/28":[ + { + "network":"203.0.113.32\/28", + "peerId":"192.0.2.18", + "path":"(300)", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.18", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.48/28":[ + { + "network":"203.0.113.48\/28", + "peerId":"192.0.2.18", + "path":"(300) 400", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.50", + "afi":"ipv4", + "used":true + } + ] + } +] } } diff --git a/tests/topotests/bgp_confed1/r2/bgp_summary.json b/tests/topotests/bgp_confed1/r2/bgp_summary.json new file mode 100644 index 0000000000..c2690a145a --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/bgp_summary.json @@ -0,0 +1,18 @@ +{ + "ipv4Unicast":{ + "routerId":"203.0.113.17", + "as":200, + "peers":{ + "192.0.2.1":{ + "remoteAs":100, + "state":"Established", + "peerState":"OK" + }, + "192.0.2.18":{ + "remoteAs":300, + "state":"Established", + "peerState":"OK" + } + } + } +} diff --git a/tests/topotests/bgp_confed1/r2/bgpd.conf b/tests/topotests/bgp_confed1/r2/bgpd.conf new file mode 100644 index 0000000000..9f6a9852de --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/bgpd.conf @@ -0,0 +1,18 @@ +debug bgp neighbor-events +debug bgp nht +debug bgp updates in +debug bgp updates out +! +router bgp 200 + no bgp ebgp-requires-policy + bgp confederation identifier 300 + bgp confederation peers 300 + neighbor 192.0.2.1 remote-as 100 + neighbor 192.0.2.18 remote-as 300 + ! + address-family ipv4 unicast + network 203.0.113.16/28 + neighbor 192.0.2.18 default-originate + exit-address-family +! + diff --git a/tests/topotests/bgp_confed1/r2/isisd.conf b/tests/topotests/bgp_confed1/r2/isisd.conf new file mode 100644 index 0000000000..135bb00a83 --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/isisd.conf @@ -0,0 +1,8 @@ +interface r2-eth1 + ip router isis 1 + isis circuit-type level-2-only + +router isis 1 + is-type level-2-only + net 49.0001.0002.0002.0002.00 + redistribute ipv4 connected level-2 diff --git a/tests/topotests/bgp_confed1/r2/zebra.conf b/tests/topotests/bgp_confed1/r2/zebra.conf new file mode 100644 index 0000000000..85ebe9ee02 --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/zebra.conf @@ -0,0 +1,9 @@ +interface r2-eth0 + ip address 192.0.2.2/28 +! +interface r2-eth1 + ip address 192.0.2.17/28 +! +interface lo + ip address 203.0.113.17/28 +! diff --git a/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json new file mode 100644 index 0000000000..a263a9f4a7 --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json @@ -0,0 +1,77 @@ +{ + "vrfId":0, + "vrfName":"default", + "routerId":"203.0.113.33", + "defaultLocPrf":100, + "localAS":300, + "routes":{"0.0.0.0/0":[ + { + "network":"0.0.0.0\/0", + "peerId":"192.0.2.17", + "path":"(200)", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.17", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.0/28":[ + { + "network":"203.0.113.0\/28", + "peerId":"192.0.2.17", + "path":"(200) 100", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.1", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.16/28":[ + { + "network":"203.0.113.16\/28", + "peerId":"192.0.2.17", + "path":"(200)", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.17", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.32/28":[ + { + "network":"203.0.113.32\/28", + "peerId":"(unspec)", + "path":"", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.48/28":[ + { + "network":"203.0.113.48\/28", + "peerId":"192.0.2.50", + "path":"400", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.50", + "afi":"ipv4", + "used":true + } + ] + } +] } } diff --git a/tests/topotests/bgp_confed1/r3/bgp_summary.json b/tests/topotests/bgp_confed1/r3/bgp_summary.json new file mode 100644 index 0000000000..0cc0d53895 --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/bgp_summary.json @@ -0,0 +1,18 @@ +{ + "ipv4Unicast":{ + "routerId":"203.0.113.33", + "as":300, + "peers":{ + "192.0.2.17":{ + "remoteAs":200, + "state":"Established", + "peerState":"OK" + }, + "192.0.2.50":{ + "remoteAs":400, + "state":"Established", + "peerState":"OK" + } + } + } +} diff --git a/tests/topotests/bgp_confed1/r3/bgpd.conf b/tests/topotests/bgp_confed1/r3/bgpd.conf new file mode 100644 index 0000000000..3a018a42b3 --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/bgpd.conf @@ -0,0 +1,17 @@ +debug bgp neighbor-events +debug bgp nht +debug bgp updates in +debug bgp updates out +! +router bgp 300 + no bgp ebgp-requires-policy + bgp confederation identifier 300 + bgp confederation peers 200 + neighbor 192.0.2.17 remote-as 200 + neighbor 192.0.2.50 remote-as 400 +! + address-family ipv4 unicast + network 203.0.113.32/28 + exit-address-family +! + diff --git a/tests/topotests/bgp_confed1/r3/isisd.conf b/tests/topotests/bgp_confed1/r3/isisd.conf new file mode 100644 index 0000000000..a0b120019b --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/isisd.conf @@ -0,0 +1,8 @@ +interface r3-eth1 + ip router isis 1 + isis circuit-type level-2-only + +router isis 1 + is-type level-2-only + net 49.0001.0003.0003.0003.00 + redistribute ipv4 connected level-2 diff --git a/tests/topotests/bgp_confed1/r3/zebra.conf b/tests/topotests/bgp_confed1/r3/zebra.conf new file mode 100644 index 0000000000..555c8ed3cf --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/zebra.conf @@ -0,0 +1,10 @@ +! +interface r3-eth0 + ip address 192.0.2.49/28 +! +interface r3-eth1 + ip address 192.0.2.18/28 +! +interface lo + ip address 203.0.113.33/28 +! diff --git a/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json new file mode 100644 index 0000000000..8a1f0b6762 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json @@ -0,0 +1,77 @@ +{ + "vrfId":0, + "vrfName":"default", + "routerId":"203.0.113.49", + "defaultLocPrf":100, + "localAS":400, + "routes":{"0.0.0.0/0":[ + { + "network":"0.0.0.0\/0", + "peerId":"192.0.2.49", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.49", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.0/28":[ + { + "network":"203.0.113.0\/28", + "peerId":"192.0.2.49", + "path":"300 100", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.49", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.16/28":[ + { + "network":"203.0.113.16\/28", + "peerId":"192.0.2.49", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.49", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.32/28":[ + { + "network":"203.0.113.32\/28", + "peerId":"192.0.2.49", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.49", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.48/28":[ + { + "network":"203.0.113.48\/28", + "peerId":"(unspec)", + "path":"", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "afi":"ipv4", + "used":true + } + ] + } +] } } diff --git a/tests/topotests/bgp_confed1/r4/bgp_summary.json b/tests/topotests/bgp_confed1/r4/bgp_summary.json new file mode 100644 index 0000000000..11a0c45cc7 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/bgp_summary.json @@ -0,0 +1,13 @@ +{ + "ipv4Unicast":{ + "routerId":"203.0.113.49", + "as":400, + "peers":{ + "192.0.2.49":{ + "remoteAs":300, + "state":"Established", + "peerState":"OK" + } + } + } +} diff --git a/tests/topotests/bgp_confed1/r4/bgpd.conf b/tests/topotests/bgp_confed1/r4/bgpd.conf new file mode 100644 index 0000000000..134f221543 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/bgpd.conf @@ -0,0 +1,14 @@ +debug bgp neighbor-events +debug bgp nht +debug bgp updates in +debug bgp updates out +! +router bgp 400 + no bgp ebgp-requires-policy + bgp disable-ebgp-connected-route-check +! + neighbor 192.0.2.49 remote-as 300 + address-family ipv4 unicast + network 203.0.113.48/28 + exit-address-family +! diff --git a/tests/topotests/bgp_confed1/r4/isisd.conf b/tests/topotests/bgp_confed1/r4/isisd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/isisd.conf diff --git a/tests/topotests/bgp_confed1/r4/zebra.conf b/tests/topotests/bgp_confed1/r4/zebra.conf new file mode 100644 index 0000000000..28c448eef8 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/zebra.conf @@ -0,0 +1,6 @@ +interface r4-eth0 + ip address 192.0.2.50/28 +! +interface lo + ip address 203.0.113.49/28 +! diff --git a/tests/topotests/bgp_confed1/test_bgp_confed1.py b/tests/topotests/bgp_confed1/test_bgp_confed1.py new file mode 100644 index 0000000000..7a35a10852 --- /dev/null +++ b/tests/topotests/bgp_confed1/test_bgp_confed1.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +# +# test_bgp_confed1.py +# +# Copyright 2022 6WIND S.A. +# +# 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 6WIND DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 6WIND 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_bgp_confed1.py: Test the FRR BGP confederations with AS member +same as confederation Id, verify BGP prefixes and path distribution +""" + +import os +import sys +import json +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 + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + +def setup_module(mod): + + 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)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_convergence(): + "Assert that BGP is converging." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for bgp peers to go up") + + for router in tgen.routers().values(): + ref_file = "{}/{}/bgp_summary.json".format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=125, wait=2.0) + assertmsg = "{}: bgp did not converge".format(router.name) + assert res is None, assertmsg + + +def test_bgp_confed_ipv4_unicast(): + "Assert that BGP is exchanging BGP route." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for bgp peers exchanging UPDATES") + + for router in tgen.routers().values(): + ref_file = "{}/{}/bgp_ipv4_unicast.json".format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show bgp ipv4 unicast json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=40, wait=2.5) + assertmsg = "{}: BGP UPDATE exchange failure".format(router.name) + assert res is None, assertmsg + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py index 10d890effb..7c23d4c576 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py @@ -155,7 +155,7 @@ def check_ping(name, dest_addr, expect_connected): if match not in output: return "ping fail" - match = "{} packet loss".format("0%" if expect_connected else "100%") + 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) 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 index af66a5a791..1209e9d6e3 100755 --- 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 @@ -69,10 +69,12 @@ def setup_module(mod): 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))) + 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") @@ -114,7 +116,7 @@ def check_ping(name, dest_addr, expect_connected): logger.info(output) assert match in output, "ping fail" - match = "{} packet loss".format("0%" if expect_connected else "100%") + 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) @@ -131,7 +133,7 @@ def check_rib(name, cmd, expected_file): expected = open_json_file("{}/{}".format(CWD, expected_file)) return topotest.json_cmp(output, expected) - logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file)) + 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) @@ -154,16 +156,16 @@ def test_rib(): 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") + check_ping("ce1", "192.168.2.2", True) + check_ping("ce1", "192.168.3.2", True) + check_ping("ce1", "192.168.4.2", False) + check_ping("ce1", "192.168.5.2", False) + check_ping("ce1", "192.168.6.2", False) + check_ping("ce4", "192.168.1.2", False) + check_ping("ce4", "192.168.2.2", False) + check_ping("ce4", "192.168.3.2", False) + check_ping("ce4", "192.168.5.2", True) + check_ping("ce4", "192.168.6.2", True) if __name__ == "__main__": diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py index e410bbbdeb..61ac7418a4 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py @@ -66,10 +66,12 @@ def setup_module(mod): 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))) + 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") @@ -111,7 +113,7 @@ def check_ping4(name, dest_addr, expect_connected): logger.info(output) assert match in output, "ping fail" - match = "{} packet loss".format("0%" if expect_connected else "100%") + 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) @@ -144,7 +146,7 @@ def check_rib(name, cmd, expected_file): expected = open_json_file("{}/{}".format(CWD, expected_file)) return topotest.json_cmp(output, expected) - logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file)) + 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) @@ -214,10 +216,18 @@ def test_bgp_sid_vpn_export_disable(): no sid vpn per-vrf export """ ) - check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_disabled.json") - check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_disabled.json") - check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_disabled.json") - check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_disabled.json") + check_rib( + "r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_disabled.json" + ) + check_rib( + "r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_disabled.json" + ) + check_rib( + "r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_disabled.json" + ) + check_rib( + "r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_disabled.json" + ) check_ping4("ce1", "192.168.2.2", False) check_ping6("ce1", "2001:2::2", False) @@ -233,10 +243,18 @@ def test_bgp_sid_vpn_export_reenable(): sid vpn per-vrf export auto """ ) - check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_reenabled.json") - check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_reenabled.json") - check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_reenabled.json") - check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_reenabled.json") + check_rib( + "r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_reenabled.json" + ) + check_rib( + "r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_reenabled.json" + ) + check_rib( + "r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_reenabled.json" + ) + check_rib( + "r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_reenabled.json" + ) check_ping4("ce1", "192.168.2.2", True) check_ping6("ce1", "2001:2::2", True) diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 4a0356411f..e1bb40c28d 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -647,6 +647,8 @@ struct vrrp_vrouter *vrrp_vrouter_create(struct interface *ifp, uint8_t vrid, vr->priority = vd.priority; vr->preempt_mode = vd.preempt_mode; vr->accept_mode = vd.accept_mode; + vr->checksum_with_ipv4_pseudoheader = + vd.checksum_with_ipv4_pseudoheader; vr->shutdown = vd.shutdown; vr->v4 = vrrp_router_create(vr, AF_INET); @@ -789,7 +791,8 @@ static void vrrp_send_advertisement(struct vrrp_router *r) pktsz = vrrp_pkt_adver_build(&pkt, &r->src, r->vr->version, r->vr->vrid, r->priority, r->vr->advertisement_interval, - r->addrs->count, (struct ipaddr **)&addrs); + r->addrs->count, (struct ipaddr **)&addrs, + r->vr->checksum_with_ipv4_pseudoheader); if (DEBUG_MODE_CHECK(&vrrp_dbg_pkt, DEBUG_MODE_ALL)) zlog_hexdump(pkt, (size_t)pktsz); @@ -1027,8 +1030,10 @@ static void vrrp_read(struct thread *thread) zlog_hexdump(r->ibuf, nbytes); } - pktsize = vrrp_pkt_parse_datagram(r->family, r->vr->version, &m, nbytes, - &src, &pkt, errbuf, sizeof(errbuf)); + pktsize = vrrp_pkt_parse_datagram( + r->family, r->vr->version, + r->vr->checksum_with_ipv4_pseudoheader, &m, nbytes, &src, &pkt, + errbuf, sizeof(errbuf)); if (pktsize < 0) DEBUGD(&vrrp_dbg_pkt, @@ -2347,6 +2352,12 @@ int vrrp_config_write_global(struct vty *vty) vty_out(vty, "%svrrp default accept\n", !vd.accept_mode ? "no " : ""); + if (vd.checksum_with_ipv4_pseudoheader != + VRRP_DEFAULT_CHECKSUM_WITH_IPV4_PSEUDOHEADER && + ++writes) + vty_out(vty, "%svrrp default checksum-with-ipv4-pseudoheader\n", + !vd.checksum_with_ipv4_pseudoheader ? "no " : ""); + if (vd.shutdown != VRRP_DEFAULT_SHUTDOWN && ++writes) vty_out(vty, "%svrrp default shutdown\n", !vd.shutdown ? "no " : ""); @@ -2387,6 +2398,8 @@ void vrrp_init(void) vd.preempt_mode = yang_get_default_bool("%s/preempt", VRRP_XPATH_FULL); vd.accept_mode = yang_get_default_bool("%s/accept-mode", VRRP_XPATH_FULL); + vd.checksum_with_ipv4_pseudoheader = yang_get_default_bool( + "%s/checksum-with-ipv4-pseudoheader", VRRP_XPATH_FULL); vd.shutdown = VRRP_DEFAULT_SHUTDOWN; vrrp_autoconfig_version = 3; diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h index c181c2159b..b3141ef318 100644 --- a/vrrpd/vrrp.h +++ b/vrrpd/vrrp.h @@ -53,6 +53,7 @@ #define VRRP_DEFAULT_ADVINT 100 #define VRRP_DEFAULT_PREEMPT true #define VRRP_DEFAULT_ACCEPT true +#define VRRP_DEFAULT_CHECKSUM_WITH_IPV4_PSEUDOHEADER true #define VRRP_DEFAULT_SHUTDOWN false /* User compatibility constant */ @@ -70,6 +71,7 @@ struct vrrp_defaults { uint16_t advertisement_interval; bool preempt_mode; bool accept_mode; + bool checksum_with_ipv4_pseudoheader; bool shutdown; }; @@ -266,6 +268,14 @@ struct vrrp_vrouter { */ bool accept_mode; + /* + * Indicates whether this router computes and accepts VRRPv3 checksums + * without pseudoheader, for device interoperability. + * + * This option should only affect IPv4 virtual routers. + */ + bool checksum_with_ipv4_pseudoheader; + struct vrrp_router *v4; struct vrrp_router *v6; }; diff --git a/vrrpd/vrrp_northbound.c b/vrrpd/vrrp_northbound.c index d25dc0a197..76d0ad3b1b 100644 --- a/vrrpd/vrrp_northbound.c +++ b/vrrpd/vrrp_northbound.c @@ -602,6 +602,26 @@ lib_interface_vrrp_vrrp_group_shutdown_modify(struct nb_cb_modify_args *args) return NB_OK; } +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with- + * ipv4-pseudoheader + */ +static int lib_interface_vrrp_vrrp_group_checksum_with_ipv4_pseudoheader_modify( + struct nb_cb_modify_args *args) +{ + if (args->event != NB_EV_APPLY) + return NB_OK; + + struct vrrp_vrouter *vr; + bool checksum_with_ipv4_ph; + + vr = nb_running_get_entry(args->dnode, NULL, true); + checksum_with_ipv4_ph = yang_dnode_get_bool(args->dnode, NULL); + vr->checksum_with_ipv4_pseudoheader = checksum_with_ipv4_ph; + + return NB_OK; +} + /* clang-format off */ const struct frr_yang_module_info frr_vrrpd_info = { .name = "frr-vrrpd", @@ -644,6 +664,13 @@ const struct frr_yang_module_info frr_vrrpd_info = { } }, { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with-ipv4-pseudoheader", + .cbs = { + .modify = lib_interface_vrrp_vrrp_group_checksum_with_ipv4_pseudoheader_modify, + .cli_show = cli_show_checksum_with_ipv4_pseudoheader, + } + }, + { .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval", .cbs = { .modify = lib_interface_vrrp_vrrp_group_advertisement_interval_modify, diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index 991c030196..96a19da88c 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -71,7 +71,7 @@ static const char *const vrrp_packet_names[16] = { * VRRP checksum in network byte order. */ static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize, - struct ipaddr *src) + struct ipaddr *src, bool ipv4_ph) { uint16_t chksum; bool v6 = (src->ipa_type == IPADDR_V6); @@ -89,13 +89,16 @@ static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize, ph.next_hdr = IPPROTO_VRRP; chksum = in_cksum_with_ph6(&ph, pkt, pktsize); } else if (!v6 && ((pkt->hdr.vertype >> 4) == 3)) { - struct ipv4_ph ph = {}; - - ph.src = src->ipaddr_v4; - inet_pton(AF_INET, VRRP_MCASTV4_GROUP_STR, &ph.dst); - ph.proto = IPPROTO_VRRP; - ph.len = htons(pktsize); - chksum = in_cksum_with_ph4(&ph, pkt, pktsize); + if (ipv4_ph) { + struct ipv4_ph ph = {}; + + ph.src = src->ipaddr_v4; + inet_pton(AF_INET, VRRP_MCASTV4_GROUP_STR, &ph.dst); + ph.proto = IPPROTO_VRRP; + ph.len = htons(pktsize); + chksum = in_cksum_with_ph4(&ph, pkt, pktsize); + } else + chksum = in_cksum(pkt, pktsize); } else if (!v6 && ((pkt->hdr.vertype >> 4) == 2)) { chksum = in_cksum(pkt, pktsize); } else { @@ -110,7 +113,7 @@ static uint16_t vrrp_pkt_checksum(struct vrrp_pkt *pkt, size_t pktsize, ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src, uint8_t version, uint8_t vrid, uint8_t prio, uint16_t max_adver_int, uint8_t numip, - struct ipaddr **ips) + struct ipaddr **ips, bool ipv4_ph) { bool v6 = false; size_t addrsz = 0; @@ -147,7 +150,7 @@ ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src, aptr += addrsz; } - (*pkt)->hdr.chksum = vrrp_pkt_checksum(*pkt, pktsize, src); + (*pkt)->hdr.chksum = vrrp_pkt_checksum(*pkt, pktsize, src, ipv4_ph); return pktsize; } @@ -188,10 +191,10 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt) return rs; } -ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m, - size_t read, struct ipaddr *src, - struct vrrp_pkt **pkt, char *errmsg, - size_t errmsg_len) +ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph, + struct msghdr *m, size_t read, + struct ipaddr *src, struct vrrp_pkt **pkt, + char *errmsg, size_t errmsg_len) { /* Source (MAC & IP), Dest (MAC & IP) TTL validation done by kernel */ size_t addrsz = (family == AF_INET) ? sizeof(struct in_addr) @@ -289,7 +292,7 @@ ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m, VRRP_PKT_VCHECK(pktver == version, "Bad version %u", pktver); /* Checksum check */ - uint16_t chksum = vrrp_pkt_checksum(*pkt, pktsize, src); + uint16_t chksum = vrrp_pkt_checksum(*pkt, pktsize, src, ipv4_ph); VRRP_PKT_VCHECK((*pkt)->hdr.chksum == chksum, "Bad VRRP checksum %hx; should be %hx", diff --git a/vrrpd/vrrp_packet.h b/vrrpd/vrrp_packet.h index 082935f080..eec709593e 100644 --- a/vrrpd/vrrp_packet.h +++ b/vrrpd/vrrp_packet.h @@ -131,7 +131,7 @@ struct vrrp_pkt { ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src, uint8_t version, uint8_t vrid, uint8_t prio, uint16_t max_adver_int, uint8_t numip, - struct ipaddr **ips); + struct ipaddr **ips, bool ipv4_ph); /* free memory allocated by vrrp_pkt_adver_build's pkt arg */ void vrrp_pkt_free(struct vrrp_pkt *pkt); @@ -195,9 +195,9 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt); * Returns: * Size of VRRP packet, or -1 upon error */ -ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m, - size_t read, struct ipaddr *src, - struct vrrp_pkt **pkt, char *errmsg, - size_t errmsg_len); +ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph, + struct msghdr *m, size_t read, + struct ipaddr *src, struct vrrp_pkt **pkt, + char *errmsg, size_t errmsg_len); #endif /* __VRRP_PACKET_H__ */ diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index f822b89854..1e1edb8212 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -281,6 +281,35 @@ void cli_show_preempt(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, " %svrrp %s preempt\n", pre ? "" : "no ", vrid); } +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with- + * ipv4-pseudoheader + */ +DEFPY_YANG(vrrp_checksum_with_ipv4_pseudoheader, + vrrp_checksum_with_ipv4_pseudoheader_cmd, + "[no] vrrp (1-255)$vrid checksum-with-ipv4-pseudoheader", + NO_STR + VRRP_STR + VRRP_VRID_STR + "Checksum mode in VRRPv3\n") +{ + nb_cli_enqueue_change(vty, "./checksum-with-ipv4-pseudoheader", + NB_OP_MODIFY, no ? "false" : "true"); + + return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); +} + +void cli_show_checksum_with_ipv4_pseudoheader(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); + const bool pre = yang_dnode_get_bool(dnode, NULL); + + vty_out(vty, " %svrrp %s checksum-with-ipv4-pseudoheader\n", + pre ? "" : "no ", vrid); +} + /* XXX: yang conversion */ DEFPY_YANG(vrrp_autoconfigure, vrrp_autoconfigure_cmd, @@ -304,7 +333,7 @@ DEFPY_YANG(vrrp_autoconfigure, /* XXX: yang conversion */ DEFPY_YANG(vrrp_default, vrrp_default_cmd, - "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|shutdown$s>", + "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|checksum-with-ipv4-pseudoheader$ipv4ph|shutdown$s>", NO_STR VRRP_STR "Configure defaults for new VRRP instances\n" @@ -313,6 +342,7 @@ DEFPY_YANG(vrrp_default, "Preempt mode\n" VRRP_PRIORITY_STR "Priority value\n" + "Checksum mode in VRRPv3\n" "Force VRRP router into administrative shutdown\n") { if (adv) { @@ -329,6 +359,8 @@ DEFPY_YANG(vrrp_default, vd.preempt_mode = !no; if (prio) vd.priority = no ? VRRP_DEFAULT_PRIORITY : prioval; + if (ipv4ph) + vd.checksum_with_ipv4_pseudoheader = !no; if (s) vd.shutdown = !no; @@ -374,6 +406,8 @@ static struct json_object *vrrp_build_json(struct vrrp_vrouter *vr) json_object_boolean_add(j, "shutdown", vr->shutdown); json_object_boolean_add(j, "preemptMode", vr->preempt_mode); json_object_boolean_add(j, "acceptMode", vr->accept_mode); + json_object_boolean_add(j, "checksumWithIpv4Pseudoheader", + vr->checksum_with_ipv4_pseudoheader); json_object_string_add(j, "interface", vr->ifp->name); json_object_int_add(j, "advertisementInterval", vr->advertisement_interval * CS2MS); @@ -499,6 +533,8 @@ static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr) vr->preempt_mode ? "Yes" : "No"); ttable_add_row(tt, "%s|%s", "Accept Mode", vr->accept_mode ? "Yes" : "No"); + ttable_add_row(tt, "%s|%s", "Checksum with IPv4 Pseudoheader", + vr->checksum_with_ipv4_pseudoheader ? "Yes" : "No"); ttable_add_row(tt, "%s|%d ms", "Advertisement Interval", vr->advertisement_interval * CS2MS); ttable_add_row(tt, "%s|%d ms (stale)", @@ -752,4 +788,6 @@ void vrrp_vty_init(void) install_element(INTERFACE_NODE, &vrrp_ip_cmd); install_element(INTERFACE_NODE, &vrrp_ip6_cmd); install_element(INTERFACE_NODE, &vrrp_preempt_cmd); + install_element(INTERFACE_NODE, + &vrrp_checksum_with_ipv4_pseudoheader_cmd); } diff --git a/vrrpd/vrrp_vty.h b/vrrpd/vrrp_vty.h index 587537a6f3..be88349e78 100644 --- a/vrrpd/vrrp_vty.h +++ b/vrrpd/vrrp_vty.h @@ -40,5 +40,8 @@ void cli_show_ipv6(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_preempt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void cli_show_checksum_with_ipv4_pseudoheader(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); #endif /* __VRRP_VTY_H__ */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 30f117505a..dea09fa151 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -3939,6 +3939,12 @@ DEFUN (vtysh_ping, return CMD_SUCCESS; } +DEFUN(vtysh_motd, vtysh_motd_cmd, "show motd", SHOW_STR "Show motd\n") +{ + vty_hello(vty); + return CMD_SUCCESS; +} + ALIAS(vtysh_ping, vtysh_ping_ip_cmd, "ping ip WORD", "Send echo messages\n" "IP echo\n" @@ -4907,6 +4913,7 @@ void vtysh_init_vty(void) install_element(VIEW_NODE, &no_vtysh_terminal_monitor_cmd); install_element(VIEW_NODE, &vtysh_ping_cmd); + install_element(VIEW_NODE, &vtysh_motd_cmd); install_element(VIEW_NODE, &vtysh_ping_ip_cmd); install_element(VIEW_NODE, &vtysh_traceroute_cmd); install_element(VIEW_NODE, &vtysh_traceroute_ip_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index ac0cdc6ffd..ac32f0a774 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -348,9 +348,13 @@ void vtysh_config_parse_line(void *arg, const char *line) break; default: if (strncmp(line, "exit", strlen("exit")) == 0) { - if (config) + if (config) { + if (config->exit) + XFREE(MTYPE_VTYSH_CONFIG_LINE, + config->exit); config->exit = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line); + } } else if (strncmp(line, "interface", strlen("interface")) == 0) config = config_get(INTERFACE_NODE, line); else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0) diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index ca119eb900..a72cb6e809 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -111,6 +111,8 @@ static void vtysh_rl_callback(char *line_read) if (!vtysh_loop_exited) rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback); + + free(line_read); } /* SIGTSTP handler. This function care user's ^Z input. */ diff --git a/yang/frr-vrrpd.yang b/yang/frr-vrrpd.yang index 200eaeb0b5..cd04df2670 100644 --- a/yang/frr-vrrpd.yang +++ b/yang/frr-vrrpd.yang @@ -110,6 +110,13 @@ module frr-vrrpd { address is not owned by the router interface"; } + leaf checksum-with-ipv4-pseudoheader { + type boolean; + default "true"; + description + "Enabled if VRRPv3 checksum for IPv4 involves pseudoheader"; + } + leaf advertisement-interval { type uint16 { range "1..4095"; diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index b28c468a96..d628e47492 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1081,8 +1081,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) zif->link_ifindex = link_ifindex; if (desc) { - XFREE(MTYPE_TMP, zif->desc); - zif->desc = XSTRDUP(MTYPE_TMP, desc); + XFREE(MTYPE_ZIF_DESC, zif->desc); + zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc); } /* Hardware type and address. */ @@ -2136,9 +2136,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) zif = ifp->info; if (zif) { - XFREE(MTYPE_TMP, zif->desc); + XFREE(MTYPE_ZIF_DESC, zif->desc); if (desc) - zif->desc = XSTRDUP(MTYPE_TMP, desc); + zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc); } } else { /* Delete interface notification from kernel */ diff --git a/zebra/interface.c b/zebra/interface.c index 81ee995dd7..87bb49042a 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -61,6 +61,7 @@ DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), (vty, ifp)); +DEFINE_MTYPE(ZEBRA, ZIF_DESC, "Intf desc"); static void if_down_del_nbr_connected(struct interface *ifp); @@ -233,7 +234,7 @@ static int if_zebra_delete_hook(struct interface *ifp) if_nhg_dependents_release(ifp); zebra_if_nhg_dependents_free(zebra_if); - XFREE(MTYPE_TMP, zebra_if->desc); + XFREE(MTYPE_ZIF_DESC, zebra_if->desc); THREAD_OFF(zebra_if->speed_update); diff --git a/zebra/interface.h b/zebra/interface.h index 801078e83d..0242438dc2 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -109,6 +109,9 @@ enum zebra_if_flags { #define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \ ((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL) +/* Mem type for zif desc */ +DECLARE_MTYPE(ZIF_DESC); + /* `zebra' daemon local interface structure. */ struct zebra_if { /* back pointer to the interface */ diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 28db2ad87d..36852b65b6 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -200,12 +200,12 @@ static void if_set_defaults(struct irdp_interface *irdp) static struct Adv *Adv_new(void) { - return XCALLOC(MTYPE_TMP, sizeof(struct Adv)); + return XCALLOC(MTYPE_IRDP_IF, sizeof(struct Adv)); } static void Adv_free(struct Adv *adv) { - XFREE(MTYPE_TMP, adv); + XFREE(MTYPE_IRDP_IF, adv); } static void irdp_if_start(struct interface *ifp, int multicast, diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index d594512b36..a2233a6667 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3698,7 +3698,7 @@ static inline void zebra_neigh_ip_del(ZAPI_HANDLER_ARGS) static inline void zread_iptable(ZAPI_HANDLER_ARGS) { struct zebra_pbr_iptable *zpi = - XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable)); + XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable)); struct stream *s; s = msg; diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index 56d0df569c..d3c104cc80 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -46,6 +46,7 @@ #include "zebra/debug.h" #include "zebra/zapi_msg.h" +DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_GR, "GR"); /* * Forward declaration. @@ -111,7 +112,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client) { struct client_gr_info *info; - info = XCALLOC(MTYPE_TMP, sizeof(struct client_gr_info)); + info = XCALLOC(MTYPE_ZEBRA_GR, sizeof(struct client_gr_info)); TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info); return info; @@ -127,7 +128,7 @@ static void zebra_gr_client_info_delte(struct zserv *client, THREAD_OFF(info->t_stale_removal); - XFREE(MTYPE_TMP, info->current_prefix); + XFREE(MTYPE_ZEBRA_GR, info->current_prefix); LOG_GR("%s: Instance info is being deleted for client %s", __func__, zebra_route_string(client->proto)); @@ -136,7 +137,7 @@ static void zebra_gr_client_info_delte(struct zserv *client, info->do_delete = true; zebra_gr_delete_stale_routes(info); - XFREE(MTYPE_TMP, info); + XFREE(MTYPE_ZEBRA_GR, info); } /* @@ -222,8 +223,8 @@ static void zebra_gr_delete_stale_client(struct client_gr_info *info) TAILQ_INIT(&(s_client->gr_info_queue)); listnode_delete(zrouter.stale_client_list, s_client); if (info->stale_client) - XFREE(MTYPE_TMP, s_client); - XFREE(MTYPE_TMP, info); + zserv_client_delete(s_client); + XFREE(MTYPE_ZEBRA_GR, info); } /* @@ -288,7 +289,7 @@ void zebra_gr_client_reconnect(struct zserv *client) /* Delete the stale client */ listnode_delete(zrouter.stale_client_list, old_client); /* Delete old client */ - XFREE(MTYPE_TMP, old_client); + zserv_client_delete(old_client); } /* @@ -474,7 +475,7 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct thread *thread) LOG_GR("%s: Client %s all stale routes processed", __func__, zebra_route_string(client->proto)); - XFREE(MTYPE_TMP, info->current_prefix); + XFREE(MTYPE_ZEBRA_GR, info->current_prefix); info->current_afi = 0; zebra_gr_delete_stale_client(info); } @@ -579,7 +580,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, && (info->do_delete == false)) { info->current_afi = afi; info->current_prefix = XCALLOC( - MTYPE_TMP, + MTYPE_ZEBRA_GR, sizeof(struct prefix)); prefix_copy( info->current_prefix, @@ -593,7 +594,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, * Reset the current prefix to indicate processing completion * of the current AFI */ - XFREE(MTYPE_TMP, info->current_prefix); + XFREE(MTYPE_ZEBRA_GR, info->current_prefix); } return 0; } diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index f52c5e0058..7b076b8a4a 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -138,7 +138,9 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) */ static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete) { - route_table_finish(zns->if_table); + if (zns->if_table) + route_table_finish(zns->if_table); + zns->if_table = NULL; zebra_dplane_ns_enable(zns, false /*Disable*/); diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 43e21a6d34..405241fc22 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -36,6 +36,7 @@ /* definitions */ DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list"); +DEFINE_MTYPE(ZEBRA, PBR_OBJ, "PBR"); /* definitions */ static const struct message ipset_type_msg[] = { @@ -163,7 +164,7 @@ void zebra_pbr_rules_free(void *arg) rule = (struct zebra_pbr_rule *)arg; (void)dplane_pbr_rule_delete(rule); - XFREE(MTYPE_TMP, rule); + XFREE(MTYPE_PBR_OBJ, rule); } uint32_t zebra_pbr_rules_hash_key(const void *arg) @@ -275,7 +276,7 @@ void zebra_pbr_ipset_free(void *arg) ipset = (struct zebra_pbr_ipset *)arg; hook_call(zebra_pbr_ipset_update, 0, ipset); - XFREE(MTYPE_TMP, ipset); + XFREE(MTYPE_PBR_OBJ, ipset); } uint32_t zebra_pbr_ipset_hash_key(const void *arg) @@ -319,7 +320,7 @@ void zebra_pbr_ipset_entry_free(void *arg) hook_call(zebra_pbr_ipset_entry_update, 0, ipset); - XFREE(MTYPE_TMP, ipset); + XFREE(MTYPE_PBR_OBJ, ipset); } uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg) @@ -396,7 +397,7 @@ static void _zebra_pbr_iptable_free_all(void *arg, bool all) } list_delete(&iptable->interface_name_list); } - XFREE(MTYPE_TMP, iptable); + XFREE(MTYPE_PBR_OBJ, iptable); } void zebra_pbr_iptable_free(void *arg) @@ -478,7 +479,7 @@ static void *pbr_rule_alloc_intern(void *arg) zpr = (struct zebra_pbr_rule *)arg; - new = XCALLOC(MTYPE_TMP, sizeof(*new)); + new = XCALLOC(MTYPE_PBR_OBJ, sizeof(*new)); memcpy(new, zpr, sizeof(*zpr)); @@ -492,7 +493,7 @@ static struct zebra_pbr_rule *pbr_rule_free(struct zebra_pbr_rule *hash_data, zebra_neigh_deref(hash_data); hash_release(zrouter.rules_hash, hash_data); if (free_data) { - XFREE(MTYPE_TMP, hash_data); + XFREE(MTYPE_PBR_OBJ, hash_data); return NULL; } @@ -688,7 +689,7 @@ void zebra_pbr_add_rule(struct zebra_pbr_rule *rule) (void)dplane_pbr_rule_update(found, new); /* release the old hash data */ if (old) - XFREE(MTYPE_TMP, old); + XFREE(MTYPE_PBR_OBJ, old); } else { if (IS_ZEBRA_DEBUG_PBR) zlog_debug( @@ -856,7 +857,7 @@ static void *pbr_ipset_alloc_intern(void *arg) zpi = (struct zebra_pbr_ipset *)arg; - new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset)); + new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset)); memcpy(new, zpi, sizeof(*zpi)); @@ -877,7 +878,7 @@ void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset) (void)dplane_pbr_ipset_delete(ipset); if (lookup) { hash_release(zrouter.ipset_hash, lookup); - XFREE(MTYPE_TMP, lookup); + XFREE(MTYPE_PBR_OBJ, lookup); } else zlog_debug( "%s: IPSet Entry being deleted we know nothing about", @@ -930,7 +931,7 @@ static void *pbr_ipset_entry_alloc_intern(void *arg) zpi = (struct zebra_pbr_ipset_entry *)arg; - new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry)); + new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset_entry)); memcpy(new, zpi, sizeof(*zpi)); @@ -952,7 +953,7 @@ void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset) (void)dplane_pbr_ipset_entry_delete(ipset); if (lookup) { hash_release(zrouter.ipset_entry_hash, lookup); - XFREE(MTYPE_TMP, lookup); + XFREE(MTYPE_PBR_OBJ, lookup); } else zlog_debug("%s: IPSet being deleted we know nothing about", __func__); @@ -967,7 +968,7 @@ static void *pbr_iptable_alloc_intern(void *arg) zpi = (struct zebra_pbr_iptable *)arg; - new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable)); + new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable)); /* Deep structure copy */ memcpy(new, zpi, sizeof(*zpi)); @@ -1009,7 +1010,7 @@ void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable) node); } list_delete(&iptable->interface_name_list); - XFREE(MTYPE_TMP, lookup); + XFREE(MTYPE_PBR_OBJ, lookup); } else zlog_debug("%s: IPTable being deleted we know nothing about", __func__); diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index baa8755fa5..60457914cc 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -36,6 +36,9 @@ extern "C" { #endif +/* Memory type for PBR objects. */ +DECLARE_MTYPE(PBR_OBJ); + struct zebra_pbr_action { afi_t afi; diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 13ad9d71bb..b4fd5f0181 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -434,9 +434,9 @@ static int zebra_sr_config(struct vty *vty) if (locator->argument_bits_length) vty_out(vty, " arg-len %u", locator->argument_bits_length); - if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) - vty_out(vty, " behavior usid"); vty_out(vty, "\n"); + if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + vty_out(vty, " behavior usid\n"); vty_out(vty, " exit\n"); vty_out(vty, " !\n"); } diff --git a/zebra/zserv.c b/zebra/zserv.c index ebe246ffbc..d788811d3d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -78,6 +78,8 @@ static struct zserv *find_client_internal(uint8_t proto, unsigned short instance, uint32_t session_id); +/* Mem type for zclients. */ +DEFINE_MTYPE_STATIC(ZEBRA, ZSERV_CLIENT, "ZClients"); /* * Client thread events. @@ -146,6 +148,14 @@ static void zserv_event(struct zserv *client, enum zserv_event event); /* Client thread lifecycle -------------------------------------------------- */ /* + * Free a zserv client object. + */ +void zserv_client_delete(struct zserv *client) +{ + XFREE(MTYPE_ZSERV_CLIENT, client); +} + +/* * Log zapi message to zlog. * * errmsg (optional) @@ -644,7 +654,7 @@ static void zserv_client_free(struct zserv *client) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("%s: Deleting client %s", __func__, zebra_route_string(client->proto)); - XFREE(MTYPE_TMP, client); + zserv_client_delete(client); } else { /* Handle cases where client has GR instance. */ if (IS_ZEBRA_DEBUG_EVENT) @@ -733,7 +743,7 @@ static struct zserv *zserv_client_create(int sock) int i; afi_t afi; - client = XCALLOC(MTYPE_TMP, sizeof(struct zserv)); + client = XCALLOC(MTYPE_ZSERV_CLIENT, sizeof(struct zserv)); /* Make client input/output buffer. */ client->sock = sock; diff --git a/zebra/zserv.h b/zebra/zserv.h index db7b70d7c4..de784e382a 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -364,6 +364,13 @@ extern void zserv_release_client(struct zserv *client); extern void zserv_close_client(struct zserv *client); /* + * Free memory for a zserv client object - note that this does not + * clean up the internal allocations associated with the zserv client, + * this just free the struct's memory. + */ +void zserv_client_delete(struct zserv *client); + +/* * Log a ZAPI message hexdump. * * errmsg |
