From 102b94e2ed1ef190b9224291faf380b5467b9ce8 Mon Sep 17 00:00:00 2001 From: "James R. Leu" Date: Wed, 1 Oct 2003 22:07:58 -0600 Subject: [PATCH] FECs are now inserted in the tree upon creation [git-p4: depot-paths = "//depot/ldp-portable/": change = 424] --- ldp/ldp_attr.c | 2 +- ldp/ldp_cfg.c | 14 +-- ldp/ldp_fec.c | 245 ++++++++++++++++++++++-------------------------- ldp/ldp_fec.h | 18 ++-- ldp/ldp_global.c | 9 +- ldp/ldp_label_mapping.c | 4 +- ldp/ldp_label_request.c | 4 +- ldp/ldp_nexthop.c | 1 - ldp/ldp_session.c | 6 +- ldp/ldp_struct.h | 5 - 10 files changed, 133 insertions(+), 175 deletions(-) diff --git a/ldp/ldp_attr.c b/ldp/ldp_attr.c index 5669e9a..2b07d43 100644 --- a/ldp/ldp_attr.c +++ b/ldp/ldp_attr.c @@ -855,7 +855,7 @@ ldp_fec *_ldp_attr_get_fec2(ldp_global * g, mpls_fec * f, mpls_bool flag) } /* this FEC doesn't exist in the tree yet, create one ... */ - if (!(fnode = ldp_fec_insert(g, f))) { + if (!(fnode = ldp_fec_create(g, f))) { /* insert failed */ return NULL; } diff --git a/ldp/ldp_cfg.c b/ldp/ldp_cfg.c index 9cc607f..af7d6a7 100644 --- a/ldp/ldp_cfg.c +++ b/ldp/ldp_cfg.c @@ -861,8 +861,8 @@ mpls_return_enum ldp_cfg_if_set(mpls_cfg_handle handle, ldp_if * i, uint32_t fla np = MPLS_LIST_HEAD(&global->nexthop); while (np) { - if ((np->type & MPLS_NH_IF) && (np->info.if_handle == iff->handle) && - (!MPLS_LIST_IN_LIST(np, _if))) { + if ((np->info.type & MPLS_NH_IF) && + (np->info.if_handle == iff->handle) && (!MPLS_LIST_IN_LIST(np, _if))) { ldp_if_add_nexthop(iff, np); } np = MPLS_LIST_NEXT(&global->nexthop, np, _global); @@ -1292,16 +1292,10 @@ mpls_return_enum ldp_cfg_fec_set(mpls_cfg_handle handle, mpls_fec * f, mpls_lock_get(global->global_lock); /* LOCK */ if (flag & LDP_CFG_ADD) { - if (ldp_fec_find(global, f) || (fec = ldp_fec_create(global)) == NULL) { + if (ldp_fec_find(global, f) || (fec = ldp_fec_create(global, f)) == NULL) { goto ldp_cfg_fec_set_end; } f->index = fec->index; - mpls_fec2ldp_fec(f, fec); - if (ldp_fec_insert2(global, fec) != MPLS_SUCCESS) { - LDP_PRINT(global->user_data, "ldp_cfg_fec_set: insert failed\n"); - MPLS_REFCNT_RELEASE2(global, fec, ldp_fec_delete); - goto ldp_cfg_fec_set_end; - } } else { if (flag & LDP_FEC_CFG_BY_INDEX) { ldp_global_find_fec_index(global, f->index, &fec); @@ -1316,7 +1310,7 @@ mpls_return_enum ldp_cfg_fec_set(mpls_cfg_handle handle, mpls_fec * f, } if (flag & LDP_CFG_DEL) { - ldp_fec_remove(global,&fec->info); + MPLS_ASSERT(0); } retval = MPLS_SUCCESS; diff --git a/ldp/ldp_fec.c b/ldp/ldp_fec.c index 50fe895..c76a5b9 100644 --- a/ldp/ldp_fec.c +++ b/ldp/ldp_fec.c @@ -35,130 +35,130 @@ #endif static uint32_t _ldp_fec_next_index = 1; -static uint32_t _ldp_fec_get_next_index(); -ldp_nexthop *ldp_fec_nexthop_find(ldp_fec *f, mpls_nexthop *n) +static mpls_return_enum ldp_fec_insert(ldp_global *g, ldp_fec * fec) { - ldp_nexthop *nh = NULL; - - MPLS_ASSERT(f && n); - - nh = MPLS_LIST_HEAD(&f->nh_root); - while (nh) { - if (!mpls_nexthop_compare(&nh->info, n)) { - return nh; - } - nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec); - } - - return NULL; -} - -ldp_fec *ldp_fec_find(ldp_global *g, mpls_fec *fec) -{ - ldp_fec *f = NULL; + mpls_return_enum retval = MPLS_SUCCESS; uint32_t key; uint8_t len; - switch(fec->type) { + MPLS_ASSERT(g && fec); + LDP_ENTER(g->user_data, "ldp_fec_insert"); + + switch(fec->info.type) { case MPLS_FEC_PREFIX: - key = fec->u.prefix.network.u.ipv4; - len = fec->u.prefix.length; + key = fec->info.u.prefix.network.u.ipv4; + len = fec->info.u.prefix.length; break; case MPLS_FEC_HOST: - key = fec->u.host.u.ipv4; + key = fec->info.u.host.u.ipv4; len = 32; break; case MPLS_FEC_L2CC: - if (ldp_global_find_fec(g, fec, &f) == MPLS_SUCCESS) { - return f; - } - return NULL; + /* they had better insert it into the global list */ + LDP_EXIT(g->user_data, "ldp_fec_insert: l2cc"); + return MPLS_SUCCESS; default: MPLS_ASSERT(0); } - if (mpls_tree_get(g->fec_tree, key, len, (void **)&f) != MPLS_SUCCESS) { - return NULL; + if (mpls_tree_insert(g->fec_tree, key, len, (void *)fec) != MPLS_SUCCESS) { + LDP_PRINT(g->user_data, "ldp_fec_insert: error adding fec\n"); + retval = MPLS_FATAL; } - return f; + + LDP_EXIT(g->user_data, "ldp_fec_insert"); + return retval; } -mpls_return_enum ldp_fec_insert2(ldp_global *g, ldp_fec * fec) +static void ldp_fec_remove(ldp_global *g, mpls_fec *fec) { + ldp_fec *f = NULL; uint32_t key; uint8_t len; - MPLS_ASSERT(MPLS_LIST_EMPTY(&fec->nh_root)); + MPLS_ASSERT(g && fec); + LDP_ENTER(g->user_data, "ldp_fec_remove"); - switch(fec->info.type) { + switch(fec->type) { case MPLS_FEC_PREFIX: - key = fec->info.u.prefix.network.u.ipv4; - len = fec->info.u.prefix.length; + key = fec->u.prefix.network.u.ipv4; + len = fec->u.prefix.length; break; case MPLS_FEC_HOST: - key = fec->info.u.host.u.ipv4; + key = fec->u.host.u.ipv4; len = 32; + break; case MPLS_FEC_L2CC: - /* they had better insert it into the global list */ - return MPLS_SUCCESS; + /* they had better remove it from the global list */ + LDP_EXIT(g->user_data, "ldp_fec_remove"); + return; default: MPLS_ASSERT(0); } - /* hold it since it is going in the tree */ - MPLS_REFCNT_HOLD(fec); - - if (mpls_tree_insert(g->fec_tree, key, len, (void *)fec) != MPLS_SUCCESS) { - LDP_PRINT(g->user_data, "ldp_fec_insert: error adding addr\n"); + mpls_tree_remove(g->fec_tree, key, len, (void **)&f); - /* delete the refcnt we just took */ - MPLS_REFCNT_RELEASE2(g, fec, ldp_fec_delete); - goto ldp_fec_insert2_error; - } - return MPLS_SUCCESS; + MPLS_ASSERT(f); -ldp_fec_insert2_error: - return MPLS_FATAL; + LDP_EXIT(g->user_data, "ldp_fec_remove"); } -ldp_fec *ldp_fec_insert(ldp_global *g, mpls_fec * fec) +static uint32_t _ldp_fec_get_next_index() { - ldp_fec *f = NULL; + uint32_t retval = _ldp_fec_next_index; - if ((f = ldp_fec_create(g)) == NULL) { - LDP_PRINT(g->user_data, "ldp_fec_insert: error creating address\n"); - return NULL; + _ldp_fec_next_index++; + if (retval > _ldp_fec_next_index) { + _ldp_fec_next_index = 1; } + return retval; +} - mpls_fec2ldp_fec(fec,f); +ldp_fec *ldp_fec_create(ldp_global *g, mpls_fec *f) +{ + ldp_fec *fec = (ldp_fec *) mpls_malloc(sizeof(ldp_fec)); - if (ldp_fec_insert2(g,f) != MPLS_SUCCESS) { - /* this should delete it */ - MPLS_REFCNT_RELEASE2(g, f, ldp_fec_delete); - return NULL; + if (fec != NULL) { + memset(fec, 0, sizeof(ldp_fec)); + /* + * note: this is init to 1 for a reason! + * We're placing it in the global list, so this is our refcnt + * when this refcnt gets to zero, it will be removed from the + * global list and deleted + */ + MPLS_REFCNT_INIT(fec, 1); + MPLS_LIST_ELEM_INIT(fec, _global); + MPLS_LIST_ELEM_INIT(fec, _inlabel); + MPLS_LIST_ELEM_INIT(fec, _outlabel); + MPLS_LIST_ELEM_INIT(fec, _fec); + MPLS_LIST_INIT(&fec->nh_root, ldp_nexthop); + MPLS_LIST_INIT(&fec->fs_root_us, ldp_fs); + MPLS_LIST_INIT(&fec->fs_root_ds, ldp_fs); + fec->index = _ldp_fec_get_next_index(); + mpls_fec2ldp_fec(f,fec); + + _ldp_global_add_fec(g, fec); + ldp_fec_insert(g, fec); } - return f; + return fec; } -ldp_fec *ldp_fec_find2(ldp_global *g, mpls_fec *fec) +void ldp_fec_delete(ldp_global *g, ldp_fec * fec) { - ldp_fec *f = NULL; - f = ldp_fec_find(g, fec); - if (!f) { - f = ldp_fec_insert(g, fec); - } - return f; + fprintf(stderr, "fec delete: %08x/%d\n", fec->info.u.prefix.network.u.ipv4, + fec->info.u.prefix.length); + ldp_fec_remove(g, &fec->info); + _ldp_global_del_fec(g, fec); + mpls_free(fec); } -void ldp_fec_remove(ldp_global *g, mpls_fec *fec) +ldp_fec *ldp_fec_find(ldp_global *g, mpls_fec *fec) { ldp_fec *f = NULL; uint32_t key; uint8_t len; - LDP_ENTER(g->user_data, "ldp_fec_remove"); - switch(fec->type) { case MPLS_FEC_PREFIX: key = fec->u.prefix.network.u.ipv4; @@ -169,33 +169,45 @@ void ldp_fec_remove(ldp_global *g, mpls_fec *fec) len = 32; break; case MPLS_FEC_L2CC: - /* they had better remove it from the global list */ - LDP_EXIT(g->user_data, "ldp_fec_remove"); - return; + if (ldp_global_find_fec(g, fec, &f) == MPLS_SUCCESS) { + return f; + } + return NULL; default: MPLS_ASSERT(0); } - mpls_tree_remove(g->fec_tree, key, len, (void **)&f); - if (!f) { - LDP_EXIT(g->user_data, "ldp_fec_remove"); - return; + if (mpls_tree_get(g->fec_tree, key, len, (void **)&f) != MPLS_SUCCESS) { + return NULL; } + return f; +} - MPLS_ASSERT(MPLS_LIST_EMPTY(&f->nh_root)); - - MPLS_REFCNT_RELEASE2(g, f, ldp_fec_delete); - - LDP_EXIT(g->user_data, "ldp_fec_remove"); +ldp_fec *ldp_fec_find2(ldp_global *g, mpls_fec *fec) +{ + ldp_fec *f = NULL; + f = ldp_fec_find(g, fec); + if (!f) { + f = ldp_fec_create(g, fec); + } + return f; } -mpls_bool ldp_fec_empty(ldp_fec *fec) +ldp_nexthop *ldp_fec_nexthop_find(ldp_fec *f, mpls_nexthop *n) { - if (MPLS_LIST_EMPTY(&fec->fs_root_us) && - MPLS_LIST_EMPTY(&fec->fs_root_ds)) { - return MPLS_BOOL_TRUE; + ldp_nexthop *nh = NULL; + + MPLS_ASSERT(f && n); + + nh = MPLS_LIST_HEAD(&f->nh_root); + while (nh) { + if (!mpls_nexthop_compare(&nh->info, n)) { + return nh; + } + nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec); } - return MPLS_BOOL_FALSE; + + return NULL; } mpls_return_enum ldp_fec_find_nexthop_index(ldp_fec *f, int index, @@ -238,7 +250,7 @@ mpls_return_enum ldp_fec_add_nexthop(ldp_global *g, ldp_fec * f, ldp_nexthop_add_fec(nh, f); - if (nh->type & MPLS_NH_IP) { + if (nh->info.type & MPLS_NH_IP) { ldp_addr *addr = NULL; if (!(addr = ldp_addr_find(g, &nh->info.ip))) { if (!(addr = ldp_addr_insert(g, &nh->info.ip))) { @@ -249,14 +261,14 @@ mpls_return_enum ldp_fec_add_nexthop(ldp_global *g, ldp_fec * f, ldp_addr_add_nexthop(addr, nh); } - if (nh->type & MPLS_NH_IF) { + if (nh->info.type & MPLS_NH_IF) { ldp_if *iff = NULL; if ((iff = ldp_global_find_if_handle(g, nh->info.if_handle))) { ldp_if_add_nexthop(iff, nh); } } - if (nh->type & MPLS_NH_OUTSEGMENT) { + if (nh->info.type & MPLS_NH_OUTSEGMENT) { ldp_outlabel *out = NULL; MPLS_ASSERT((out = ldp_global_find_outlabel_handle(g, nh->info.outsegment_handle))); @@ -536,46 +548,11 @@ Detect_Change_Fec_Next_Hop_20: return MPLS_SUCCESS; } -ldp_fec *ldp_fec_create(ldp_global *g) -{ - ldp_fec *fec = (ldp_fec *) mpls_malloc(sizeof(ldp_fec)); - - if (fec != NULL) { - memset(fec, 0, sizeof(ldp_fec)); - /* - * note: this is init to 1 for a reason! - * We're placing it in the global list, so this is our refcnt - * when this refcnt gets to zero, it will be removed from the - * global list and deleted - */ - MPLS_REFCNT_INIT(fec, 1); - MPLS_LIST_ELEM_INIT(fec, _global); - MPLS_LIST_ELEM_INIT(fec, _inlabel); - MPLS_LIST_ELEM_INIT(fec, _outlabel); - MPLS_LIST_ELEM_INIT(fec, _fec); - MPLS_LIST_INIT(&fec->nh_root, ldp_nexthop); - MPLS_LIST_INIT(&fec->fs_root_us, ldp_fs); - MPLS_LIST_INIT(&fec->fs_root_ds, ldp_fs); - fec->info.type = MPLS_FEC_NONE; - fec->index = _ldp_fec_get_next_index(); - _ldp_global_add_fec(g, fec); - } - return fec; -} - void mpls_fec2ldp_fec(mpls_fec * a, ldp_fec * b) { memcpy(&b->info, a, sizeof(mpls_fec)); } -void ldp_fec_delete(ldp_global *g, ldp_fec * fec) -{ - fprintf(stderr, "fec delete: %08x/%d\n", fec->info.u.prefix.network.u.ipv4, - fec->info.u.prefix.length); - _ldp_global_del_fec(g, fec); - mpls_free(fec); -} - void mpls_fec2fec_tlv(mpls_fec * lf, mplsLdpFecTlv_t * tlv, int i) { tlv->fecElArray[i].addressEl.addressFam = 1; @@ -616,15 +593,13 @@ void fec_tlv2mpls_fec(mplsLdpFecTlv_t * tlv, int i, mpls_fec * lf) { } } -static uint32_t _ldp_fec_get_next_index() +mpls_bool ldp_fec_empty(ldp_fec *fec) { - uint32_t retval = _ldp_fec_next_index; - - _ldp_fec_next_index++; - if (retval > _ldp_fec_next_index) { - _ldp_fec_next_index = 1; + if (MPLS_LIST_EMPTY(&fec->fs_root_us) && + MPLS_LIST_EMPTY(&fec->nh_root) && + MPLS_LIST_EMPTY(&fec->fs_root_ds)) { + return MPLS_BOOL_TRUE; } - return retval; + return MPLS_BOOL_FALSE; } - diff --git a/ldp/ldp_fec.h b/ldp/ldp_fec.h index c0977fe..39dae80 100644 --- a/ldp/ldp_fec.h +++ b/ldp/ldp_fec.h @@ -10,29 +10,25 @@ #ifndef _LDP_FEC_H_ #define _LDP_FEC_H_ +extern ldp_fec *ldp_fec_create(ldp_global *g, mpls_fec *fec); +extern void ldp_fec_delete(ldp_global *g, ldp_fec * fec); extern ldp_fec *ldp_fec_find(ldp_global *g, mpls_fec *fec); extern ldp_fec *ldp_fec_find2(ldp_global *g, mpls_fec *fec); extern ldp_nexthop *ldp_fec_nexthop_find(ldp_fec *f, mpls_nexthop *n); extern mpls_return_enum ldp_fec_find_nexthop_index(ldp_fec *f, int index, ldp_nexthop **n); -extern ldp_fec *ldp_fec_insert(ldp_global *g, mpls_fec * fec); -extern mpls_return_enum ldp_fec_insert2(ldp_global *g, ldp_fec * fec); -extern void ldp_fec_remove(ldp_global *g, mpls_fec *fec); -extern mpls_bool ldp_fec_empty(ldp_fec *fec); extern mpls_return_enum ldp_fec_add_nexthop(ldp_global *g, ldp_fec *f, ldp_nexthop *n); extern void ldp_fec_del_nexthop(ldp_global *g, ldp_fec *f, ldp_nexthop *n); -extern ldp_fec *ldp_fec_create(ldp_global *g); -extern void ldp_fec_delete(ldp_global *g, ldp_fec * fec); - -extern void mpls_fec2ldp_fec(mpls_fec * a, ldp_fec * b); - -extern void fec_tlv2mpls_fec(mplsLdpFecTlv_t * tlv, int num, mpls_fec * lf); -extern void mpls_fec2fec_tlv(mpls_fec * lf, mplsLdpFecTlv_t * tlv, int num); extern mpls_return_enum ldp_fec_process_add(ldp_global * g, ldp_fec * f, ldp_nexthop *nh); extern mpls_return_enum ldp_fec_process_change(ldp_global * g, ldp_fec * f, ldp_nexthop *nh, ldp_session * nh_session_old); +extern mpls_bool ldp_fec_empty(ldp_fec *fec); +extern void mpls_fec2ldp_fec(mpls_fec * a, ldp_fec * b); +extern void fec_tlv2mpls_fec(mplsLdpFecTlv_t * tlv, int num, mpls_fec * lf); +extern void mpls_fec2fec_tlv(mpls_fec * lf, mplsLdpFecTlv_t * tlv, int num); + #endif diff --git a/ldp/ldp_global.c b/ldp/ldp_global.c index a959ef7..9cc875b 100644 --- a/ldp/ldp_global.c +++ b/ldp/ldp_global.c @@ -294,10 +294,10 @@ mpls_return_enum ldp_global_startup(ldp_global * g) ldp_fec *f; if (!(f = ldp_fec_find(g, &fec))) { - f = ldp_fec_insert(g, &fec); - } - if (!f) { - goto ldp_global_startup_cleanup; + f = ldp_fec_create(g, &fec); + if (!f) { + goto ldp_global_startup_cleanup; + } } n = ldp_nexthop_create(); @@ -306,7 +306,6 @@ mpls_return_enum ldp_global_startup(ldp_global * g) } memcpy(&n->info, &nexthop, sizeof(mpls_nexthop)); - n->type = nexthop.type; if (ldp_fec_add_nexthop(g, f, n) != MPLS_SUCCESS) { goto ldp_global_startup_cleanup; } diff --git a/ldp/ldp_label_mapping.c b/ldp/ldp_label_mapping.c index ab3516e..ba597ce 100644 --- a/ldp/ldp_label_mapping.c +++ b/ldp/ldp_label_mapping.c @@ -419,11 +419,11 @@ void ldp_label_mapping_initial_callback(mpls_timer_handle timer, void *extra, MPLS_ASSERT(0); } - if (nh->type & MPLS_NH_IP) { + if (nh->info.type & MPLS_NH_IP) { LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ROUTE, "via %08x\n", nh->addr->address.u.ipv4); } - if (nh->type & MPLS_NH_IF && nh->iff) { + if (nh->info.type & MPLS_NH_IF && nh->iff) { LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ROUTE, "via %p\n", nh->iff->handle); } diff --git a/ldp/ldp_label_request.c b/ldp/ldp_label_request.c index f120852..e0ce7d5 100644 --- a/ldp/ldp_label_request.c +++ b/ldp/ldp_label_request.c @@ -225,11 +225,11 @@ void ldp_label_request_initial_callback(mpls_timer_handle timer, void *extra, MPLS_ASSERT(0); } - if (nh->type & MPLS_NH_IP) { + if (nh->info.type & MPLS_NH_IP) { LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ROUTE, "via %08x\n", nh->addr->address.u.ipv4); } - if (nh->type & MPLS_NH_IF) { + if (nh->info.type & MPLS_NH_IF) { LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ROUTE, "via %p\n", nh->iff->handle); } diff --git a/ldp/ldp_nexthop.c b/ldp/ldp_nexthop.c index 412de19..acf7798 100644 --- a/ldp/ldp_nexthop.c +++ b/ldp/ldp_nexthop.c @@ -140,7 +140,6 @@ void ldp_nexthop_del_fec(ldp_global *g, ldp_nexthop * nh) void mpls_nexthop2ldp_nexthop(mpls_nexthop *mnh, ldp_nexthop *lnh) { - lnh->type = mnh->type; memcpy(&lnh->info, mnh, sizeof(mpls_nexthop)); } diff --git a/ldp/ldp_session.c b/ldp/ldp_session.c index e35ca84..6cebafd 100644 --- a/ldp/ldp_session.c +++ b/ldp/ldp_session.c @@ -734,20 +734,20 @@ ldp_session *ldp_session_for_nexthop(ldp_nexthop *nh) { MPLS_ASSERT(nh); - if (nh->type & MPLS_NH_IP) { + if (nh->info.type & MPLS_NH_IP) { MPLS_ASSERT(mpls_link_list_count(&nh->addr->session_root) < 2); ldp_session *s = mpls_link_list_head_data(&nh->addr->session_root); if (s) { return s; } } - if (nh->type & MPLS_NH_IF) { + if (nh->info.type & MPLS_NH_IF) { ldp_session *s = NULL; if (nh->iff && (s = mpls_link_list_head_data(&nh->iff->session_root))) { return s; } } - if (nh->type & MPLS_NH_OUTSEGMENT) { + if (nh->info.type & MPLS_NH_OUTSEGMENT) { MPLS_ASSERT(0); } return NULL; diff --git a/ldp/ldp_struct.h b/ldp/ldp_struct.h index 3be6765..383a7aa 100644 --- a/ldp/ldp_struct.h +++ b/ldp/ldp_struct.h @@ -515,7 +515,6 @@ typedef struct ldp_nexthop { MPLS_LIST_ELEM(ldp_nexthop) _if; MPLS_LIST_ELEM(ldp_nexthop) _outlabel; struct ldp_outlabel_list outlabel_root; - enum mpls_nexthop_enum type; struct ldp_fec *fec; struct ldp_addr *addr; struct ldp_if *iff; @@ -700,10 +699,6 @@ typedef struct ldp_tunnel { uint32_t owner; } ldp_tunnel; -typedef void (*ldp_fib_callback) (mpls_cfg_handle cfg, mpls_update_enum type, - mpls_fec * dest); -typedef void (*ldp_ifmgr_callback) (mpls_cfg_handle cfg, mpls_update_enum type, - mpls_inet_addr *addr); typedef void (*ldp_tree_callback) (void *); #endif -- 2.11.4.GIT