diff options
| -rw-r--r-- | isisd/isis_adjacency.c | 47 | ||||
| -rw-r--r-- | isisd/isis_adjacency.h | 9 | ||||
| -rw-r--r-- | isisd/isis_circuit.c | 56 | ||||
| -rw-r--r-- | isisd/isis_circuit.h | 10 | ||||
| -rw-r--r-- | isisd/isis_csm.c | 9 | ||||
| -rw-r--r-- | isisd/isis_lsp.c | 10 | ||||
| -rw-r--r-- | isisd/isis_pdu.c | 133 | ||||
| -rw-r--r-- | isisd/isis_route.c | 40 | ||||
| -rw-r--r-- | isisd/isis_spf.c | 42 | ||||
| -rw-r--r-- | isisd/isis_te.c | 60 | ||||
| -rw-r--r-- | isisd/isis_tlvs.c | 337 | ||||
| -rw-r--r-- | isisd/isis_tlvs.h | 24 | ||||
| -rw-r--r-- | isisd/isis_vty.c | 17 | ||||
| -rw-r--r-- | isisd/isisd.h | 5 | ||||
| -rw-r--r-- | lib/strlcat.c | 14 | ||||
| -rw-r--r-- | lib/strlcpy.c | 29 | ||||
| -rw-r--r-- | lib/zebra.h | 6 | ||||
| -rw-r--r-- | ospf6d/ospf6_message.c | 3 | ||||
| -rw-r--r-- | tests/isisd/test_fuzz_isis_tlv_tests.h.gz | bin | 232370 -> 262877 bytes | |||
| -rwxr-xr-x | tools/frr-reload.py | 30 | ||||
| -rw-r--r-- | zebra/rib.h | 2 | ||||
| -rw-r--r-- | zebra/zebra_vrf.c | 7 | ||||
| -rw-r--r-- | zebra/zebra_vty.c | 352 |
23 files changed, 862 insertions, 380 deletions
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 72e6d4bdb9..a6e1a55a9f 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -47,6 +47,7 @@ #include "isisd/isis_spf.h" #include "isisd/isis_events.h" #include "isisd/isis_mt.h" +#include "isisd/isis_tlvs.h" extern struct isis *isis; @@ -78,6 +79,7 @@ struct isis_adjacency *isis_new_adj(const u_char *id, const u_char *snpa, adj->level = level; adj->flaps = 0; adj->last_flap = time(NULL); + adj->threeway_state = ISIS_THREEWAY_DOWN; if (circuit->circ_type == CIRCUIT_T_BROADCAST) { listnode_add(circuit->u.bc.adjdb[level - 1], adj); adj->dischanges[level - 1] = 0; @@ -161,6 +163,51 @@ static const char *adj_state2string(int state) return NULL; /* not reached */ } +void isis_adj_process_threeway(struct isis_adjacency *adj, + struct isis_threeway_adj *tw_adj, + enum isis_adj_usage adj_usage) +{ + enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN; + + if (tw_adj && !adj->circuit->disable_threeway_adj) { + if (tw_adj->state == ISIS_THREEWAY_DOWN) { + next_tw_state = ISIS_THREEWAY_INITIALIZING; + } else if (tw_adj->state == ISIS_THREEWAY_INITIALIZING) { + next_tw_state = ISIS_THREEWAY_UP; + } else if (tw_adj->state == ISIS_THREEWAY_UP) { + if (adj->threeway_state == ISIS_THREEWAY_DOWN) + next_tw_state = ISIS_THREEWAY_DOWN; + else + next_tw_state = ISIS_THREEWAY_UP; + } + } else { + next_tw_state = ISIS_THREEWAY_UP; + } + + if (next_tw_state != adj->threeway_state) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_info("ISIS-Adj (%s): Threeway state change %s to %s", + adj->circuit->area->area_tag, + isis_threeway_state_name(adj->threeway_state), + isis_threeway_state_name(next_tw_state)); + } + } + + if (next_tw_state == ISIS_THREEWAY_DOWN) { + isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Neighbor restarted"); + return; + } + + if (next_tw_state == ISIS_THREEWAY_UP) { + if (adj->adj_state != ISIS_ADJ_UP) { + isis_adj_state_change(adj, ISIS_ADJ_UP, NULL); + adj->adj_usage = adj_usage; + } + } + + adj->threeway_state = next_tw_state; +} + void isis_adj_state_change(struct isis_adjacency *adj, enum isis_adj_state new_state, const char *reason) { diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 98bb9838fa..2c3bd19af8 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -25,6 +25,8 @@ #ifndef _ZEBRA_ISIS_ADJACENCY_H #define _ZEBRA_ISIS_ADJACENCY_H +#include "isisd/isis_tlvs.h" + enum isis_adj_usage { ISIS_ADJ_NONE, ISIS_ADJ_LEVEL1, @@ -91,6 +93,8 @@ struct isis_adjacency { u_int16_t hold_time; /* entryRemainingTime */ u_int32_t last_upd; u_int32_t last_flap; /* last time the adj flapped */ + enum isis_threeway_state threeway_state; + uint32_t ext_circuit_id; int flaps; /* number of adjacency flaps */ struct thread *t_expire; /* expire after hold_time */ struct isis_circuit *circuit; /* back pointer */ @@ -98,12 +102,17 @@ struct isis_adjacency { unsigned int mt_count; /* Number of entries in mt_set */ }; +struct isis_threeway_adj; + struct isis_adjacency *isis_adj_lookup(const u_char *sysid, struct list *adjdb); struct isis_adjacency *isis_adj_lookup_snpa(const u_char *ssnpa, struct list *adjdb); struct isis_adjacency *isis_new_adj(const u_char *id, const u_char *snpa, int level, struct isis_circuit *circuit); void isis_delete_adj(void *adj); +void isis_adj_process_threeway(struct isis_adjacency *adj, + struct isis_threeway_adj *tw_adj, + enum isis_adj_usage adj_usage); void isis_adj_state_change(struct isis_adjacency *adj, enum isis_adj_state state, const char *reason); void isis_adj_print(struct isis_adjacency *adj); diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 75d4397637..2c443c71f7 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -234,8 +234,8 @@ void isis_circuit_add_addr(struct isis_circuit *circuit, #ifdef EXTREME_DEBUG prefix2str(connected->address, buf, sizeof(buf)); - zlog_debug("Added IP address %s to circuit %d", buf, - circuit->circuit_id); + zlog_debug("Added IP address %s to circuit %s", buf, + circuit->interface->name); #endif /* EXTREME_DEBUG */ } if (connected->address->family == AF_INET6) { @@ -265,8 +265,8 @@ void isis_circuit_add_addr(struct isis_circuit *circuit, #ifdef EXTREME_DEBUG prefix2str(connected->address, buf, sizeof(buf)); - zlog_debug("Added IPv6 address %s to circuit %d", buf, - circuit->circuit_id); + zlog_debug("Added IPv6 address %s to circuit %s", buf, + circuit->interface->name); #endif /* EXTREME_DEBUG */ } return; @@ -300,9 +300,9 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, } else { prefix2str(connected->address, buf, sizeof(buf)); zlog_warn( - "Nonexistant ip address %s removal attempt from \ - circuit %d", - buf, circuit->circuit_id); + "Nonexistent ip address %s removal attempt from \ + circuit %s", + buf, circuit->interface->name); zlog_warn("Current ip addresses on %s:", circuit->interface->name); for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, @@ -349,9 +349,9 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, if (!found) { prefix2str(connected->address, buf, sizeof(buf)); zlog_warn( - "Nonexitant ip address %s removal attempt from \ - circuit %d", - buf, circuit->circuit_id); + "Nonexistent ip address %s removal attempt from \ + circuit %s", + buf, circuit->interface->name); zlog_warn("Current ip addresses on %s:", circuit->interface->name); for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, @@ -377,17 +377,15 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, return; } -static uint8_t isis_circuit_id_gen(struct interface *ifp) +static uint8_t isis_circuit_id_gen(struct isis *isis, struct interface *ifp) { /* Circuit ids MUST be unique for any broadcast circuits. Otherwise, * Pseudo-Node LSPs cannot be generated correctly. * - * Currently, allocate one circuit ID for any circuit, limiting the - * total + * Currently, allocate one circuit ID for any circuit, limiting the total * numer of circuits IS-IS can run on to 255. * - * We should revisit this when implementing 3-way adjacencies for p2p, - * since + * We should revisit this when implementing 3-way adjacencies for p2p, since * we then have extended interface IDs available. */ uint8_t id = ifp->ifindex; @@ -405,6 +403,7 @@ static uint8_t isis_circuit_id_gen(struct interface *ifp) return 0; } + _ISIS_SET_FLAG(isis->circuit_ids_used, id); return id; } @@ -413,11 +412,7 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) struct listnode *node, *nnode; struct connected *conn; - circuit->circuit_id = isis_circuit_id_gen(ifp); - _ISIS_SET_FLAG(isis->circuit_ids_used, circuit->circuit_id); - isis_circuit_if_bind(circuit, ifp); - /* isis_circuit_update_addrs (circuit, ifp); */ if (if_is_broadcast(ifp)) { if (circuit->circ_type_config == CIRCUIT_T_P2P) @@ -442,8 +437,6 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) isis_circuit_add_addr(circuit, conn); - - return; } void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp) @@ -460,26 +453,19 @@ void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp) if (circuit->ip_addrs) { assert(listcount(circuit->ip_addrs) == 0); list_delete_and_null(&circuit->ip_addrs); - circuit->ip_addrs = NULL; } if (circuit->ipv6_link) { assert(listcount(circuit->ipv6_link) == 0); list_delete_and_null(&circuit->ipv6_link); - circuit->ipv6_link = NULL; } if (circuit->ipv6_non_link) { assert(listcount(circuit->ipv6_non_link) == 0); list_delete_and_null(&circuit->ipv6_non_link); - circuit->ipv6_non_link = NULL; } circuit->circ_type = CIRCUIT_T_UNKNOWN; - _ISIS_CLEAR_FLAG(isis->circuit_ids_used, circuit->circuit_id); - circuit->circuit_id = 0; - - return; } void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp) @@ -593,6 +579,12 @@ int isis_circuit_up(struct isis_circuit *circuit) } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + circuit->circuit_id = isis_circuit_id_gen(isis, circuit->interface); + if (!circuit->circuit_id) { + zlog_err("There are already 255 broadcast circuits active!"); + return ISIS_ERROR; + } + /* * Get the Hardware Address */ @@ -737,6 +729,9 @@ void isis_circuit_down(struct isis_circuit *circuit) THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[1]); circuit->lsp_regenerate_pending[0] = 0; circuit->lsp_regenerate_pending[1] = 0; + + _ISIS_CLEAR_FLAG(isis->circuit_ids_used, circuit->circuit_id); + circuit->circuit_id = 0; } else if (circuit->circ_type == CIRCUIT_T_P2P) { isis_delete_adj(circuit->u.p2p.neighbor); circuit->u.p2p.neighbor = NULL; @@ -1046,6 +1041,11 @@ int isis_interface_config_write(struct vty *vty) write++; } + if (circuit->disable_threeway_adj) { + vty_out(vty, " no isis three-way-handshake\n"); + write++; + } + /* ISIS - Hello interval */ if (circuit->hello_interval[0] == circuit->hello_interval[1]) { diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 0d392036e9..246279c6f3 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -32,8 +32,6 @@ #include "isis_constants.h" #include "isis_common.h" -#define CIRCUIT_MAX 255 - struct isis_lsp; struct password { @@ -69,7 +67,7 @@ struct isis_p2p_info { struct isis_circuit { int state; - u_char circuit_id; /* l1/l2 p2p/bcast CircuitID */ + u_char circuit_id; /* l1/l2 bcast CircuitID */ struct isis_area *area; /* back pointer to the area */ struct interface *interface; /* interface info from z */ int fd; /* IS-IS l1/2 socket */ @@ -82,9 +80,8 @@ struct isis_circuit { struct thread *t_send_csnp[2]; struct thread *t_send_psnp[2]; struct thread *t_send_lsp; - struct list *lsp_queue; /* LSPs to be txed (both levels) */ - struct isis_lsp_hash - *lsp_hash; /* Hashtable synchronized with lsp_queue */ + struct list *lsp_queue; /* LSPs to be txed (both levels) */ + struct isis_lsp_hash *lsp_hash; /* Hashtable synchronized with lsp_queue */ time_t lsp_queue_last_push[2]; /* timestamp used to enforce transmit * interval; * for scalability, use one timestamp per @@ -135,6 +132,7 @@ struct isis_circuit { u_int16_t upadjcount[2]; #define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01 u_char flags; + bool disable_threeway_adj; /* * Counters as in 10589--11.2.5.9 */ diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index a283260d92..10870d5c50 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -86,13 +86,6 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) case IF_UP_FROM_Z: circuit = isis_circuit_new(); isis_circuit_if_add(circuit, (struct interface *)arg); - if (!circuit->circuit_id) { - isis_circuit_if_del(circuit, - (struct interface *)arg); - isis_circuit_del(circuit); - circuit = NULL; - break; - } listnode_add(isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; break; @@ -143,8 +136,6 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) break; case IF_UP_FROM_Z: isis_circuit_if_add(circuit, (struct interface *)arg); - if (!circuit->circuit_id) - break; if (isis_circuit_up(circuit) != ISIS_OK) { zlog_err( "Could not bring up %s because of invalid config.", diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 55888bd389..b2ba8b3932 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1034,7 +1034,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) break; case CIRCUIT_T_P2P: { struct isis_adjacency *nei = circuit->u.p2p.neighbor; - if (nei && (level & nei->circuit_t)) { + if (nei && nei->adj_state == ISIS_ADJ_UP + && (level & nei->circuit_t)) { uint8_t ne_id[7]; memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID(ne_id) = 0; @@ -1875,15 +1876,12 @@ int lsp_tick(struct thread *thread) if (!circuit->lsp_queue) continue; - if (now - - circuit->lsp_queue_last_push - [level] + if (now - circuit->lsp_queue_last_push[level] < MIN_LSP_RETRANS_INTERVAL) { continue; } - circuit->lsp_queue_last_push[level] = - now; + circuit->lsp_queue_last_push[level] = now; for (ALL_LIST_ELEMENTS_RO( lsp_list, lspnode, lsp)) { diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 20c39a624f..bcbda33088 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -120,6 +120,32 @@ struct iih_info { static int process_p2p_hello(struct iih_info *iih) { + struct isis_threeway_adj *tw_adj = iih->tlvs->threeway_adj; + if (tw_adj) { + if (tw_adj->state > ISIS_THREEWAY_DOWN) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d\n", + iih->circuit->area->area_tag, + iih->circuit->interface->name, + tw_adj->state); + } + return ISIS_WARNING; + } + + if (tw_adj->neighbor_set + && (memcmp(tw_adj->neighbor_id, isis->sysid, ISIS_SYS_ID_LEN) + || tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) { + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.\n", + iih->circuit->area->area_tag, + iih->circuit->interface->name); + } + + return ISIS_WARNING; + } + } + /* * My interpertation of the ISO, if no adj exists we will create one for * the circuit @@ -155,6 +181,9 @@ static int process_p2p_hello(struct iih_info *iih) adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } + if (tw_adj && adj->threeway_state == ISIS_THREEWAY_DOWN) + adj->ext_circuit_id = tw_adj->local_circuit_id; + /* 8.2.6 Monitoring point-to-point adjacencies */ adj->hold_time = iih->holdtime; adj->last_upd = time(NULL); @@ -183,14 +212,10 @@ static int process_p2p_hello(struct iih_info *iih) switch (iih->circ_type) { case IS_LEVEL_1: case IS_LEVEL_1_AND_2: - if (adj->adj_state != ISIS_ADJ_UP) { - /* (4) adj state up */ - isis_adj_state_change(adj, ISIS_ADJ_UP, - NULL); - /* (5) adj usage level 1 */ - adj->adj_usage = ISIS_ADJ_LEVEL1; - } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { - ; /* accept */ + if (adj->adj_state != ISIS_ADJ_UP + || adj->adj_usage == ISIS_ADJ_LEVEL1) { + isis_adj_process_threeway(adj, tw_adj, + ISIS_ADJ_LEVEL1); } break; case IS_LEVEL_2: @@ -213,14 +238,10 @@ static int process_p2p_hello(struct iih_info *iih) if (iih->circuit->area->is_type == IS_LEVEL_1_AND_2) { switch (iih->circ_type) { case IS_LEVEL_1: - if (adj->adj_state != ISIS_ADJ_UP) { - /* (6) adj state up */ - isis_adj_state_change(adj, ISIS_ADJ_UP, - NULL); - /* (7) adj usage level 1 */ - adj->adj_usage = ISIS_ADJ_LEVEL1; - } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { - ; /* accept */ + if (adj->adj_state != ISIS_ADJ_UP + || adj->adj_usage == ISIS_ADJ_LEVEL1) { + isis_adj_process_threeway(adj, tw_adj, + ISIS_ADJ_LEVEL1); } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage @@ -232,12 +253,10 @@ static int process_p2p_hello(struct iih_info *iih) } break; case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP) { - /* (6) adj state up */ - isis_adj_state_change(adj, ISIS_ADJ_UP, - NULL); - /* (9) adj usage level 2 */ - adj->adj_usage = ISIS_ADJ_LEVEL2; + if (adj->adj_state != ISIS_ADJ_UP + || adj->adj_usage == ISIS_ADJ_LEVEL2) { + isis_adj_process_threeway(adj, tw_adj, + ISIS_ADJ_LEVEL2); } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)) { @@ -245,17 +264,13 @@ static int process_p2p_hello(struct iih_info *iih) isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Wrong System"); - } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { - ; /* Accept */ } break; case IS_LEVEL_1_AND_2: - if (adj->adj_state != ISIS_ADJ_UP) { - /* (6) adj state up */ - isis_adj_state_change(adj, ISIS_ADJ_UP, - NULL); - /* (10) adj usage level 1 */ - adj->adj_usage = ISIS_ADJ_LEVEL1AND2; + if (adj->adj_state != ISIS_ADJ_UP + || adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { + isis_adj_process_threeway(adj, tw_adj, + ISIS_ADJ_LEVEL1AND2); } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { @@ -263,9 +278,6 @@ static int process_p2p_hello(struct iih_info *iih) isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Wrong System"); - } else if (adj->adj_usage - == ISIS_ADJ_LEVEL1AND2) { - ; /* Accept */ } break; } @@ -292,20 +304,16 @@ static int process_p2p_hello(struct iih_info *iih) break; case IS_LEVEL_1_AND_2: case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP) { - /* (7) adj state up */ - isis_adj_state_change(adj, ISIS_ADJ_UP, - NULL); - /* (8) adj usage level 2 */ - adj->adj_usage = ISIS_ADJ_LEVEL2; + if (adj->adj_state != ISIS_ADJ_UP + || adj->adj_usage == ISIS_ADJ_LEVEL2) { + isis_adj_process_threeway(adj, tw_adj, + ISIS_ADJ_LEVEL2); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { /* (6) down - wrong system */ isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Wrong System"); - } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { - ; /* Accept */ } break; } @@ -350,12 +358,10 @@ static int process_p2p_hello(struct iih_info *iih) break; case IS_LEVEL_1_AND_2: case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP) { - /* (8) adj state up */ - isis_adj_state_change(adj, ISIS_ADJ_UP, - NULL); - /* (9) adj usage level 2 */ - adj->adj_usage = ISIS_ADJ_LEVEL2; + if (adj->adj_state != ISIS_ADJ_UP + || adj->adj_usage == ISIS_ADJ_LEVEL2) { + isis_adj_process_threeway(adj, tw_adj, + ISIS_ADJ_LEVEL2); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - wrong system */ isis_adj_state_change(adj, @@ -374,8 +380,6 @@ static int process_p2p_hello(struct iih_info *iih) adj, ISIS_ADJ_DOWN, "Area Mismatch"); } - } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { - ; /* Accept */ } break; } @@ -415,7 +419,7 @@ static int process_p2p_hello(struct iih_info *iih) if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug( "ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," - " cir id %02d, length %d", + " cir id %hhu, length %" PRIu16, iih->circuit->area->area_tag, iih->circuit->interface->name, circuit_t2string(iih->circuit->is_type), @@ -1184,8 +1188,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, entry = entry->next) { zlog_debug( "ISIS-Snp (%s): %cSNP entry %s, seq 0x%08" PRIx32 - ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 - "s", + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s", circuit->area->area_tag, typechar, rawlspid_print(entry->id), entry->seqno, entry->checksum, entry->rem_lifetime); @@ -1244,12 +1247,10 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT(lspid) = 0; lsp0 = lsp_search( - lspid, - circuit->area - ->lspdb[level - 1]); + lspid, + circuit->area->lspdb[level - 1]); if (!lsp0) { - zlog_debug( - "Got lsp frag in snp, while zero not in database"); + zlog_debug("Got lsp frag in snp, while zero not in database"); continue; } } @@ -1555,9 +1556,25 @@ int send_hello(struct isis_circuit *circuit, int level) isis_tlvs_add_area_addresses(tlvs, circuit->area->area_addrs); - if (circuit->circ_type == CIRCUIT_T_BROADCAST) + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { isis_tlvs_add_lan_neighbors( tlvs, circuit->u.bc.lan_neighs[level - 1]); + } else if (circuit->circ_type == CIRCUIT_T_P2P + && !circuit->disable_threeway_adj) { + uint32_t ext_circuit_id = circuit->idx; + if (circuit->u.p2p.neighbor) { + isis_tlvs_add_threeway_adj(tlvs, + circuit->u.p2p.neighbor->threeway_state, + ext_circuit_id, + circuit->u.p2p.neighbor->sysid, + circuit->u.p2p.neighbor->ext_circuit_id); + } else { + isis_tlvs_add_threeway_adj(tlvs, + ISIS_THREEWAY_DOWN, + ext_circuit_id, + NULL, 0); + } + } isis_tlvs_set_protocols_supported(tlvs, &circuit->nlpids); diff --git a/isisd/isis_route.c b/isisd/isis_route.c index b9605018ed..ad769f9886 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -100,26 +100,6 @@ static int nexthoplookup(struct list *nexthops, struct in_addr *ip, return 0; } -#ifdef EXTREME_DEBUG -static void nexthop_print(struct isis_nexthop *nh) -{ - u_char buf[BUFSIZ]; - - inet_ntop(AF_INET, &nh->ip, (char *)buf, BUFSIZ); - - zlog_debug(" %s %u", buf, nh->ifindex); -} - -static void nexthops_print(struct list *nhs) -{ - struct listnode *node; - struct isis_nexthop *nh; - - for (ALL_LIST_ELEMENTS_RO(nhs, node, nh)) - nexthop_print(nh); -} -#endif /* EXTREME_DEBUG */ - static struct isis_nexthop6 *isis_nexthop6_new(struct in6_addr *ip6, ifindex_t ifindex) { @@ -184,26 +164,6 @@ static int nexthop6lookup(struct list *nexthops6, struct in6_addr *ip6, return 0; } -#ifdef EXTREME_DEBUG -static void nexthop6_print(struct isis_nexthop6 *nh6) -{ - u_char buf[BUFSIZ]; - - inet_ntop(AF_INET6, &nh6->ip6, (char *)buf, BUFSIZ); - - zlog_debug(" %s %u", buf, nh6->ifindex); -} - -static void nexthops6_print(struct list *nhs6) -{ - struct listnode *node; - struct isis_nexthop6 *nh6; - - for (ALL_LIST_ELEMENTS_RO(nhs6, node, nh6)) - nexthop6_print(nh6); -} -#endif /* EXTREME_DEBUG */ - static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj) { struct isis_nexthop *nh; diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 0eabcb7e47..dc86d4c105 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -85,10 +85,10 @@ struct isis_vertex { struct prefix prefix; } N; - u_int32_t d_N; /* d(N) Distance from this IS */ - u_int16_t depth; /* The depth in the imaginary tree */ - struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ - struct list *parents; /* list of parents for ECMP */ + u_int32_t d_N; /* d(N) Distance from this IS */ + u_int16_t depth; /* The depth in the imaginary tree */ + struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ + struct list *parents; /* list of parents for ECMP */ uint64_t insert_counter; }; @@ -276,12 +276,11 @@ static void isis_vertex_queue_delete(struct isis_vertex_queue *queue, struct isis_spftree { struct isis_vertex_queue paths; /* the SPT */ struct isis_vertex_queue tents; /* TENT */ - struct isis_area *area; /* back pointer to area */ - unsigned int runcount; /* number of runs since uptime */ - time_t last_run_timestamp; /* last run timestamp as wall time for - display */ - time_t last_run_monotime; /* last run as monotime for scheduling */ - time_t last_run_duration; /* last run duration in msec */ + struct isis_area *area; /* back pointer to area */ + unsigned int runcount; /* number of runs since uptime */ + time_t last_run_timestamp; /* last run timestamp as wall time for display */ + time_t last_run_monotime; /* last run as monotime for scheduling */ + time_t last_run_duration; /* last run duration in msec */ uint16_t mtid; int family; @@ -335,12 +334,12 @@ static void remove_excess_adjs(struct list *adjs) if (comp < 0) continue; - if (candidate->circuit->circuit_id > adj->circuit->circuit_id) { + if (candidate->circuit->idx > adj->circuit->idx) { excess = node; continue; } - if (candidate->circuit->circuit_id < adj->circuit->circuit_id) + if (candidate->circuit->idx < adj->circuit->idx) continue; comp = memcmp(candidate->snpa, adj->snpa, ETH_ALEN); @@ -831,10 +830,10 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, return ISIS_OK; /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ - bool no_overload = - (pseudo_lsp || (spftree->mtid == ISIS_MT_IPV4_UNICAST + bool no_overload = (pseudo_lsp + || (spftree->mtid == ISIS_MT_IPV4_UNICAST && !ISIS_MASK_LSP_OL_BIT(lsp->hdr.lsp_bits)) - || (mt_router_info && !mt_router_info->overload)); + || (mt_router_info && !mt_router_info->overload)); lspfragloop: if (lsp->hdr.seqno == 0) { @@ -1153,7 +1152,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree, root_sysid, parent); } else if (circuit->circ_type == CIRCUIT_T_P2P) { adj = circuit->u.p2p.neighbor; - if (!adj) + if (!adj || adj->adj_state != ISIS_ADJ_UP) continue; if (!adj_has_mt(adj, spftree->mtid)) continue; @@ -1430,8 +1429,7 @@ int isis_spf_schedule(struct isis_area *area, int level) /* wait configured min_spf_interval before doing the SPF */ long timer; if (diff >= area->min_spf_interval[level - 1]) { - /* Last run is more than min interval ago, schedule immediate - * run */ + /* Last run is more than min interval ago, schedule immediate run */ timer = 0; } else { timer = area->min_spf_interval[level - 1] - diff; @@ -1549,9 +1547,7 @@ DEFUN (show_isis_topology, continue; if (area->ip_circuits > 0 && area->spftree[level - 1] - && isis_vertex_queue_count( - &area->spftree[level - 1]->paths) - > 0) { + && isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) { vty_out(vty, "IS-IS paths to level-%d routers that speak IP\n", level); @@ -1561,9 +1557,7 @@ DEFUN (show_isis_topology, vty_out(vty, "\n"); } if (area->ipv6_circuits > 0 && area->spftree6[level - 1] - && isis_vertex_queue_count( - &area->spftree6[level - 1]->paths) - > 0) { + && isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) { vty_out(vty, "IS-IS paths to level-%d routers that speak IPv6\n", level); diff --git a/isisd/isis_te.c b/isisd/isis_te.c index df0b8b62d6..5de936a6ea 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -549,7 +549,8 @@ void isis_link_params_update(struct isis_circuit *circuit, if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) && (circuit->circ_type == CIRCUIT_T_P2P)) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; - if (adj->ipv4_address_count) { + if (adj && adj->adj_state == ISIS_ADJ_UP + && adj->ipv4_address_count) { set_circuitparams_rmt_ipaddr( mtc, adj->ipv4_addresses[0]); } @@ -805,8 +806,7 @@ static u_char print_subtlv_mm_delay(struct sbuf *buf, int indent, A = (u_int32_t)ntohl(tlv->low) & TE_EXT_ANORMAL; high = (u_int32_t)ntohl(tlv->high) & TE_EXT_MASK; - sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32 - " (micro-sec)\n", + sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32 " (micro-sec)\n", A ? "Anomalous" : "Normal", low, high); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); @@ -913,8 +913,8 @@ static u_char print_unknown_tlv(struct sbuf *buf, int indent, } /* Main Show function */ -void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs, - uint8_t subtlv_len) +void mpls_te_print_detail(struct sbuf *buf, int indent, + uint8_t *subtlvs, uint8_t subtlv_len) { struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs; uint16_t sum = 0; @@ -922,8 +922,7 @@ void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs, for (; sum < subtlv_len; tlvh = SUBTLV_HDR_NEXT(tlvh)) { switch (tlvh->type) { case TE_SUBTLV_ADMIN_GRP: - sum += print_subtlv_admin_grp( - buf, indent, + sum += print_subtlv_admin_grp(buf, indent, (struct te_subtlv_admin_grp *)tlvh); break; case TE_SUBTLV_LLRI: @@ -931,31 +930,27 @@ void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs, (struct te_subtlv_llri *)tlvh); break; case TE_SUBTLV_LOCAL_IPADDR: - sum += print_subtlv_local_ipaddr( - buf, indent, + sum += print_subtlv_local_ipaddr(buf, indent, (struct te_subtlv_local_ipaddr *)tlvh); break; case TE_SUBTLV_RMT_IPADDR: - sum += print_subtlv_rmt_ipaddr( - buf, indent, + sum += print_subtlv_rmt_ipaddr(buf, indent, (struct te_subtlv_rmt_ipaddr *)tlvh); break; case TE_SUBTLV_MAX_BW: - sum += print_subtlv_max_bw( - buf, indent, (struct te_subtlv_max_bw *)tlvh); + sum += print_subtlv_max_bw(buf, indent, + (struct te_subtlv_max_bw *)tlvh); break; case TE_SUBTLV_MAX_RSV_BW: - sum += print_subtlv_max_rsv_bw( - buf, indent, + sum += print_subtlv_max_rsv_bw(buf, indent, (struct te_subtlv_max_rsv_bw *)tlvh); break; case TE_SUBTLV_UNRSV_BW: - sum += print_subtlv_unrsv_bw( - buf, indent, (struct te_subtlv_unrsv_bw *)tlvh); + sum += print_subtlv_unrsv_bw(buf, indent, + (struct te_subtlv_unrsv_bw *)tlvh); break; case TE_SUBTLV_TE_METRIC: - sum += print_subtlv_te_metric( - buf, indent, + sum += print_subtlv_te_metric(buf, indent, (struct te_subtlv_te_metric *)tlvh); break; case TE_SUBTLV_RAS: @@ -967,33 +962,32 @@ void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs, (struct te_subtlv_rip *)tlvh); break; case TE_SUBTLV_AV_DELAY: - sum += print_subtlv_av_delay( - buf, indent, (struct te_subtlv_av_delay *)tlvh); + sum += print_subtlv_av_delay(buf, indent, + (struct te_subtlv_av_delay *)tlvh); break; case TE_SUBTLV_MM_DELAY: - sum += print_subtlv_mm_delay( - buf, indent, (struct te_subtlv_mm_delay *)tlvh); + sum += print_subtlv_mm_delay(buf, indent, + (struct te_subtlv_mm_delay *)tlvh); break; case TE_SUBTLV_DELAY_VAR: - sum += print_subtlv_delay_var( - buf, indent, + sum += print_subtlv_delay_var(buf, indent, (struct te_subtlv_delay_var *)tlvh); break; case TE_SUBTLV_PKT_LOSS: - sum += print_subtlv_pkt_loss( - buf, indent, (struct te_subtlv_pkt_loss *)tlvh); + sum += print_subtlv_pkt_loss(buf, indent, + (struct te_subtlv_pkt_loss *)tlvh); break; case TE_SUBTLV_RES_BW: - sum += print_subtlv_res_bw( - buf, indent, (struct te_subtlv_res_bw *)tlvh); + sum += print_subtlv_res_bw(buf, indent, + (struct te_subtlv_res_bw *)tlvh); break; case TE_SUBTLV_AVA_BW: - sum += print_subtlv_ava_bw( - buf, indent, (struct te_subtlv_ava_bw *)tlvh); + sum += print_subtlv_ava_bw(buf, indent, + (struct te_subtlv_ava_bw *)tlvh); break; case TE_SUBTLV_USE_BW: - sum += print_subtlv_use_bw( - buf, indent, (struct te_subtlv_use_bw *)tlvh); + sum += print_subtlv_use_bw(buf, indent, + (struct te_subtlv_use_bw *)tlvh); break; default: sum += print_unknown_tlv(buf, indent, tlvh); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 8e0fd74b73..66a19e150f 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -161,11 +161,9 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context, sbuf_push(log, indent, "Unpacking IPv6 Source Prefix Sub-TLV...\n"); if (tlv_len < 1) { - sbuf_push( - log, indent, - "Not enough data left. (expected 1 or more bytes, got %" PRIu8 - ")\n", - tlv_len); + sbuf_push(log, indent, + "Not enough data left. (expected 1 or more bytes, got %" PRIu8 ")\n", + tlv_len); return 1; } @@ -625,11 +623,10 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len, (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt"); if (len < 11) { - sbuf_push( - log, indent, - "Not enough data left. (expected 11 or more bytes, got %" PRIu8 - ")\n", - len); + sbuf_push(log, indent, + "Not enough data left. (expected 11 or more bytes, got %" + PRIu8 ")\n", + len); goto out; } @@ -977,7 +974,8 @@ static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i, struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; sbuf_push(buf, indent, "MT Router Info: %s%s%s\n", - isis_mtid2str(info->mtid), info->overload ? " Overload" : "", + isis_mtid2str(info->mtid), + info->overload ? " Overload" : "", info->attached ? " Attached" : ""); } @@ -1126,8 +1124,8 @@ static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i, sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s", (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), - r->metric, r->down ? " Down" : ""); + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric, + r->down ? " Down" : ""); if (mtid != ISIS_MT_IPV4_UNICAST) sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); sbuf_push(buf, 0, "\n"); @@ -1180,11 +1178,9 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len, consume = 5; if (len < consume) { - sbuf_push( - log, indent, - "Not enough data left. (expected 5 or more bytes, got %" PRIu8 - ")\n", - len); + sbuf_push(log, indent, + "Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n", + len); goto out; } @@ -1203,10 +1199,9 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len, consume += PSIZE(rv->prefix.prefixlen); if (len < consume) { - sbuf_push( - log, indent, - "Expected %u bytes of prefix, but only %u bytes available.\n", - PSIZE(rv->prefix.prefixlen), len - 5); + sbuf_push(log, indent, + "Expected %u bytes of prefix, but only %u bytes available.\n", + PSIZE(rv->prefix.prefixlen), len - 5); goto out; } stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen)); @@ -1221,26 +1216,23 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len, if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) { consume += 1; if (len < consume) { - sbuf_push( - log, indent, - "Expected 1 byte of subtlv len, but no more data present.\n"); + sbuf_push(log, indent, + "Expected 1 byte of subtlv len, but no more data present.\n"); goto out; } subtlv_len = stream_getc(s); if (!subtlv_len) { - sbuf_push( - log, indent + 2, - " WARNING: subtlv bit is set, but there are no subtlvs.\n"); + sbuf_push(log, indent + 2, + " WARNING: subtlv bit is set, but there are no subtlvs.\n"); } consume += subtlv_len; if (len < consume) { - sbuf_push( - log, indent, - "Expected %" PRIu8 - " bytes of subtlvs, but only %u bytes available.\n", - subtlv_len, - len - 6 - PSIZE(rv->prefix.prefixlen)); + sbuf_push(log, indent, + "Expected %" PRIu8 + " bytes of subtlvs, but only %u bytes available.\n", + subtlv_len, + len - 6 - PSIZE(rv->prefix.prefixlen)); goto out; } sbuf_push(log, indent, "Skipping %" PRIu8 " bytes of subvls", @@ -1337,6 +1329,119 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context, return 0; } +/* Functions related to TLV 240 P2P Three-Way Adjacency */ + +const char *isis_threeway_state_name(enum isis_threeway_state state) +{ + switch (state) { + case ISIS_THREEWAY_DOWN: + return "Down"; + case ISIS_THREEWAY_INITIALIZING: + return "Initializing"; + case ISIS_THREEWAY_UP: + return "Up"; + default: + return "Invalid!"; + } +} + +static struct isis_threeway_adj *copy_tlv_threeway_adj( + const struct isis_threeway_adj *threeway_adj) +{ + if (!threeway_adj) + return NULL; + + struct isis_threeway_adj *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + memcpy(rv, threeway_adj, sizeof(*rv)); + + return rv; +} + +static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, + struct sbuf *buf, int indent) +{ + if (!threeway_adj) + return; + + sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n"); + sbuf_push(buf, indent, " State: %s (%d)\n", + isis_threeway_state_name(threeway_adj->state), + threeway_adj->state); + sbuf_push(buf, indent, " Extended Local Circuit ID: %" PRIu32 "\n", + threeway_adj->local_circuit_id); + if (!threeway_adj->neighbor_set) + return; + + sbuf_push(buf, indent, " Neighbor System ID: %s\n", + isis_format_id(threeway_adj->neighbor_id, 6)); + sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %" PRIu32 "\n", + threeway_adj->neighbor_circuit_id); +} + +static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj) +{ + XFREE(MTYPE_ISIS_TLV, threeway_adj); +} + +static int pack_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, + struct stream *s) +{ + if (!threeway_adj) + return 0; + + uint8_t tlv_len = (threeway_adj->neighbor_set) ? 15 : 5; + + if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len)) + return 1; + + stream_putc(s, ISIS_TLV_THREE_WAY_ADJ); + stream_putc(s, tlv_len); + stream_putc(s, threeway_adj->state); + stream_putl(s, threeway_adj->local_circuit_id); + + if (threeway_adj->neighbor_set) { + stream_put(s, threeway_adj->neighbor_id, 6); + stream_putl(s, threeway_adj->neighbor_circuit_id); + } + + return 0; +} + +static int unpack_tlv_threeway_adj(enum isis_tlv_context context, + uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpacking P2P Three-Way Adjacency TLV...\n"); + if (tlv_len != 5 && tlv_len != 15) { + sbuf_push(log, indent, "WARNING: Unexepected TLV size\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + if (tlvs->threeway_adj) { + sbuf_push(log, indent, + "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj)); + + tlvs->threeway_adj->state = stream_getc(s); + tlvs->threeway_adj->local_circuit_id = stream_getl(s); + + if (tlv_len == 15) { + tlvs->threeway_adj->neighbor_set = true; + stream_get(tlvs->threeway_adj->neighbor_id, s, 6); + tlvs->threeway_adj->neighbor_circuit_id = stream_getl(s); + } + + return 0; +} + /* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */ static struct isis_item *copy_item_ipv6_reach(struct isis_item *i) @@ -1361,7 +1466,8 @@ static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s", (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ", prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), - r->metric, r->down ? " Down" : "", + r->metric, + r->down ? " Down" : "", r->external ? " External" : ""); if (mtid != ISIS_MT_IPV4_UNICAST) sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); @@ -1426,11 +1532,10 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt "); consume = 6; if (len < consume) { - sbuf_push( - log, indent, - "Not enough data left. (expected 6 or more bytes, got %" PRIu8 - ")\n", - len); + sbuf_push(log, indent, + "Not enough data left. (expected 6 or more bytes, got %" + PRIu8 ")\n", + len); goto out; } @@ -1451,10 +1556,9 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, consume += PSIZE(rv->prefix.prefixlen); if (len < consume) { - sbuf_push( - log, indent, - "Expected %u bytes of prefix, but only %u bytes available.\n", - PSIZE(rv->prefix.prefixlen), len - 6); + sbuf_push(log, indent, + "Expected %u bytes of prefix, but only %u bytes available.\n", + PSIZE(rv->prefix.prefixlen), len - 6); goto out; } stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen)); @@ -1468,26 +1572,23 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, if (control & ISIS_IPV6_REACH_SUBTLV) { consume += 1; if (len < consume) { - sbuf_push( - log, indent, - "Expected 1 byte of subtlv len, but no more data persent.\n"); + sbuf_push(log, indent, + "Expected 1 byte of subtlv len, but no more data persent.\n"); goto out; } subtlv_len = stream_getc(s); if (!subtlv_len) { - sbuf_push( - log, indent + 2, - " WARNING: subtlv bit set, but there are no subtlvs.\n"); + sbuf_push(log, indent + 2, + " WARNING: subtlv bit set, but there are no subtlvs.\n"); } consume += subtlv_len; if (len < consume) { - sbuf_push( - log, indent, - "Expected %" PRIu8 - " bytes of subtlvs, but only %u bytes available.\n", - subtlv_len, - len - 6 - PSIZE(rv->prefix.prefixlen)); + sbuf_push(log, indent, + "Expected %" PRIu8 + " bytes of subtlvs, but only %u bytes available.\n", + subtlv_len, + len - 6 - PSIZE(rv->prefix.prefixlen)); goto out; } @@ -1710,19 +1811,16 @@ static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type, return 1; } -static void add_item_to_fragment(struct isis_item *i, - struct pack_order_entry *pe, +static void add_item_to_fragment(struct isis_item *i, struct pack_order_entry *pe, struct isis_tlvs *fragment_tlvs, uint16_t mtid) { struct isis_item_list *l; if (pe->how_to_pack == ISIS_ITEMS) { - l = (struct isis_item_list *)(((char *)fragment_tlvs) - + pe->what_to_pack); + l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack); } else { struct isis_mt_item_list *m; - m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) - + pe->what_to_pack); + m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack); l = isis_get_mt_items(m, mtid); } @@ -2082,6 +2180,8 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs) copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, &tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach); + rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj); + return rv; } @@ -2143,6 +2243,8 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent) format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, &tlvs->mt_ipv6_reach, buf, indent); + + format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent); } const char *isis_format_tlvs(struct isis_tlvs *tlvs) @@ -2193,6 +2295,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs) free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach); free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, &tlvs->mt_ipv6_reach); + free_tlv_threeway_adj(tlvs->threeway_adj); XFREE(MTYPE_ISIS_TLV, tlvs); } @@ -2364,6 +2467,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream, copy_tlv_te_router_id(tlvs->te_router_id); } + rv = pack_tlv_threeway_adj(tlvs->threeway_adj, stream); + if (rv) + return rv; + if (fragment_tlvs) { + fragment_tlvs->threeway_adj = + copy_tlv_threeway_adj(tlvs->threeway_adj); + } + for (size_t pack_idx = 0; pack_idx < array_size(pack_order); pack_idx++) { rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream, @@ -2459,11 +2570,9 @@ static int unpack_tlv(enum isis_tlv_context context, size_t avail_len, tlv_type, tlv_len); if (avail_len < ((size_t)tlv_len) + 2) { - sbuf_push( - log, indent + 2, - "Available data %zu too short for claimed TLV len %" PRIu8 - ".\n", - avail_len - 2, tlv_len); + sbuf_push(log, indent + 2, + "Available data %zu too short for claimed TLV len %" PRIu8 ".\n", + avail_len - 2, tlv_len); return 1; } @@ -2541,7 +2650,7 @@ int isis_unpack_tlvs(size_t avail_len, struct stream *stream, static const struct tlv_ops tlv_##_name_##_ops = { \ .name = _desc_, \ .unpack = unpack_tlv_with_items, \ - \ + \ .pack_item = pack_item_##_name_, \ .free_item = free_item_##_name_, \ .unpack_item = unpack_item_##_name_, \ @@ -2566,54 +2675,41 @@ TLV_OPS(te_router_id, "TLV 134 TE Router ID"); ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability"); TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname"); ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information"); +TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency"); ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address"); ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability"); SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix"); -static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = - {[ISIS_CONTEXT_LSP] = - { - [ISIS_TLV_AREA_ADDRESSES] = - &tlv_area_address_ops, - [ISIS_TLV_OLDSTYLE_REACH] = - &tlv_oldstyle_reach_ops, - [ISIS_TLV_LAN_NEIGHBORS] = - &tlv_lan_neighbor_ops, - [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops, - [ISIS_TLV_AUTH] = &tlv_auth_ops, - [ISIS_TLV_EXTENDED_REACH] = - &tlv_extended_reach_ops, - [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops, - [ISIS_TLV_OLDSTYLE_IP_REACH] = - &tlv_oldstyle_ip_reach_ops, - [ISIS_TLV_PROTOCOLS_SUPPORTED] = - &tlv_protocols_supported_ops, - [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = - &tlv_oldstyle_ip_reach_ops, - [ISIS_TLV_IPV4_ADDRESS] = - &tlv_ipv4_address_ops, - [ISIS_TLV_TE_ROUTER_ID] = - &tlv_te_router_id_ops, - [ISIS_TLV_EXTENDED_IP_REACH] = - &tlv_extended_ip_reach_ops, - [ISIS_TLV_MT_IP_REACH] = - &tlv_extended_ip_reach_ops, - [ISIS_TLV_DYNAMIC_HOSTNAME] = - &tlv_dynamic_hostname_ops, - [ISIS_TLV_MT_ROUTER_INFO] = - &tlv_mt_router_info_ops, - [ISIS_TLV_IPV6_ADDRESS] = - &tlv_ipv6_address_ops, - [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops, - [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops, - }, - [ISIS_CONTEXT_SUBTLV_NE_REACH] = {}, - [ISIS_CONTEXT_SUBTLV_IP_REACH] = {}, - [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = { - [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = - &subtlv_ipv6_source_prefix_ops, - }}; +static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { + [ISIS_CONTEXT_LSP] = { + [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops, + [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops, + [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops, + [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops, + [ISIS_TLV_AUTH] = &tlv_auth_ops, + [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops, + [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops, + [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops, + [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops, + [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops, + [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops, + [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops, + [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops, + [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops, + [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops, + [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops, + [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops, + [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops, + [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops, + [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops, + }, + [ISIS_CONTEXT_SUBTLV_NE_REACH] = {}, + [ISIS_CONTEXT_SUBTLV_IP_REACH] = {}, + [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = { + [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops, + } +}; /* Accessor functions */ @@ -3104,6 +3200,25 @@ void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, append_item(l, (struct isis_item *)r); } +void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs, + enum isis_threeway_state state, + uint32_t local_circuit_id, + const uint8_t *neighbor_id, + uint32_t neighbor_circuit_id) +{ + assert(!tlvs->threeway_adj); + + tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj)); + tlvs->threeway_adj->state = state; + tlvs->threeway_adj->local_circuit_id = local_circuit_id; + + if (neighbor_id) { + tlvs->threeway_adj->neighbor_set = true; + memcpy(tlvs->threeway_adj->neighbor_id, neighbor_id, 6); + tlvs->threeway_adj->neighbor_circuit_id = neighbor_circuit_id; + } +} + struct isis_mt_router_info * isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid) { diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 6ade0af28c..98edbf14e7 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -103,6 +103,20 @@ struct isis_protocols_supported { uint8_t *protocols; }; +enum isis_threeway_state { + ISIS_THREEWAY_DOWN = 2, + ISIS_THREEWAY_INITIALIZING = 1, + ISIS_THREEWAY_UP = 0 +}; + +struct isis_threeway_adj { + enum isis_threeway_state state; + uint32_t local_circuit_id; + bool neighbor_set; + uint8_t neighbor_id[6]; + uint32_t neighbor_circuit_id; +}; + struct isis_item; struct isis_item { struct isis_item *next; @@ -190,6 +204,7 @@ struct isis_tlvs { char *hostname; struct isis_item_list ipv6_reach; struct isis_mt_item_list mt_ipv6_reach; + struct isis_threeway_adj *threeway_adj; }; struct isis_subtlvs { @@ -227,6 +242,7 @@ enum isis_tlv_type { ISIS_TLV_MT_IP_REACH = 235, ISIS_TLV_IPV6_REACH = 236, ISIS_TLV_MT_IPV6_REACH = 237, + ISIS_TLV_THREE_WAY_ADJ = 240, ISIS_TLV_MAX = 256, ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22 @@ -303,6 +319,14 @@ void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, uint8_t *id, uint32_t metric, uint8_t *subtlvs, uint8_t subtlv_len); +const char *isis_threeway_state_name(enum isis_threeway_state state); + +void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs, + enum isis_threeway_state state, + uint32_t local_circuit_id, + const uint8_t *neighbor_id, + uint32_t neighbor_circuit_id); + struct isis_mt_router_info * isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid); #endif diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 02e28a73fe..66d79b2e9f 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -927,6 +927,21 @@ DEFUN (no_isis_hello_padding, return CMD_SUCCESS; } +DEFUN (isis_threeway_adj, + isis_threeway_adj_cmd, + "[no] isis three-way-handshake", + NO_STR + "IS-IS commands\n" + "Enable/Disable three-way handshake\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup(vty); + if (!circuit) + return CMD_ERR_NO_MATCH; + + circuit->disable_threeway_adj = !strcmp(argv[0]->text, "no"); + return CMD_SUCCESS; +} + DEFUN (csnp_interval, csnp_interval_cmd, "isis csnp-interval (1-600)", @@ -2085,6 +2100,8 @@ void isis_vty_init(void) install_element(INTERFACE_NODE, &isis_hello_padding_cmd); install_element(INTERFACE_NODE, &no_isis_hello_padding_cmd); + install_element(INTERFACE_NODE, &isis_threeway_adj_cmd); + install_element(INTERFACE_NODE, &csnp_interval_cmd); install_element(INTERFACE_NODE, &no_csnp_interval_cmd); install_element(INTERFACE_NODE, &csnp_interval_l1_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index a8dcc8adaf..85d3974fa6 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -52,9 +52,8 @@ struct isis { struct area_addr *man_area_addrs; /* manualAreaAddresses */ u_int32_t debugs; /* bitmap for debug */ time_t uptime; /* when did we start */ - struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */ - uint32_t circuit_ids_used - [8]; /* 256 bits to track circuit ids 0 through 255 */ + struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */ + uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */ struct route_table *ext_info[REDIST_PROTOCOL_COUNT]; diff --git a/lib/strlcat.c b/lib/strlcat.c index 8186304437..be211f82a8 100644 --- a/lib/strlcat.c +++ b/lib/strlcat.c @@ -28,23 +28,25 @@ #ifndef HAVE_STRLCAT #undef strlcat -size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size); +size_t strlcat(char *__restrict dest, + const char *__restrict src, size_t destsize); -size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size) +size_t strlcat(char *__restrict dest, + const char *__restrict src, size_t destsize) { size_t src_length = strlen(src); /* Our implementation strlcat supports dest == NULL if size == 0 (for consistency with snprintf and strlcpy), but strnlen does not, so we have to cover this case explicitly. */ - if (size == 0) + if (destsize == 0) return src_length; - size_t dest_length = strnlen(dest, size); - if (dest_length != size) { + size_t dest_length = strnlen(dest, destsize); + if (dest_length != destsize) { /* Copy at most the remaining number of characters in the destination buffer. Leave for the NUL terminator. */ - size_t to_copy = size - dest_length - 1; + size_t to_copy = destsize - dest_length - 1; /* But not more than what is available in the source string. */ if (to_copy > src_length) to_copy = src_length; diff --git a/lib/strlcpy.c b/lib/strlcpy.c index b7681754aa..b0c33ca7f4 100644 --- a/lib/strlcpy.c +++ b/lib/strlcpy.c @@ -27,23 +27,26 @@ #ifndef HAVE_STRLCPY #undef strlcpy -size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size); +size_t strlcpy(char *__restrict dest, + const char *__restrict src, size_t destsize); -size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size) +size_t strlcpy(char *__restrict dest, + const char *__restrict src, size_t destsize) { size_t src_length = strlen(src); - if (__builtin_expect(src_length >= size, 0)) { - if (size > 0) { - /* Copy the leading portion of the string. The last - character is subsequently overwritten with the NUL - terminator, but the destination size is usually a - multiple of a small power of two, so writing it twice - should be more efficient than copying an odd number - of - bytes. */ - memcpy(dest, src, size); - dest[size - 1] = '\0'; + if (__builtin_expect(src_length >= destsize, 0)) { + if (destsize > 0) { + /* + * Copy the leading portion of the string. The last + * character is subsequently overwritten with the NUL + * terminator, but the destination destsize is usually + * a multiple of a small power of two, so writing it + * twice should be more efficient than copying an odd + * number of bytes. + */ + memcpy(dest, src, destsize); + dest[destsize - 1] = '\0'; } } else /* Copy the string and its terminating NUL character. */ diff --git a/lib/zebra.h b/lib/zebra.h index 262ad2e43d..923f6f77c6 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -232,10 +232,12 @@ typedef unsigned char u_int8_t; #include "zassert.h" #ifndef HAVE_STRLCAT -size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size); +size_t strlcat(char *__restrict dest, + const char *__restrict src, size_t destsize); #endif #ifndef HAVE_STRLCPY -size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size); +size_t strlcpy(char *__restrict dest, + const char *__restrict src, size_t destsize); #endif #ifdef HAVE_BROKEN_CMSG_FIRSTHDR diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index b75d5b70fa..f32cd6e7e3 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1573,7 +1573,8 @@ int ospf6_receive(struct thread *thread) oi = ospf6_interface_lookup_by_ifindex(ifindex); if (oi == NULL || oi->area == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { - zlog_debug("Message received on disabled interface"); + if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug("Message received on disabled interface"); return 0; } if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)) { diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz Binary files differindex 3eb0205a5d..cca702b138 100644 --- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 0b7e80962c..208fb116e6 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -413,7 +413,7 @@ end ctx_keys = [] current_context_lines = [] - elif line == "exit-address-family" or line == "exit" or line == "exit-vni": + elif line in ["exit-address-family", "exit", "exit-vnc", "exit-vni"]: # if this exit is for address-family ipv4 unicast, ignore the pop if main_ctx_key: self.save_contexts(ctx_keys, current_context_lines) @@ -433,26 +433,14 @@ end current_context_lines = [] new_ctx = False log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) - - # The 'vni' keyword under 'router bgp X/address-family l2vpn evpn' creates - # a sub-context but the 'vni' keyword in other places (such as 'vrf BLUE') - # does not. - elif ("vni " in line and - len(ctx_keys) == 2 and - ctx_keys[0].startswith('router bgp') and - ctx_keys[1] == 'address-family l2vpn evpn'): - - main_ctx_key = [] - - # Save old context first - self.save_contexts(ctx_keys, current_context_lines) - current_context_lines = [] - main_ctx_key = copy.deepcopy(ctx_keys) - log.debug('LINE %-50s: entering sub-context, append to ctx_keys', line) - - ctx_keys.append(line) - - elif "address-family " in line: + elif (line.startswith("address-family ") or + line.startswith("vnc defaults") or + line.startswith("vnc l2-group") or + line.startswith("vnc nve-group") or + (line.startswith("vni ") and + len(ctx_keys) == 2 and + ctx_keys[0].startswith('router bgp') and + ctx_keys[1] == 'address-family l2vpn evpn')): main_ctx_key = [] # Save old context first diff --git a/zebra/rib.h b/zebra/rib.h index 5dd444dce0..0ee89e015a 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -447,6 +447,8 @@ DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason), extern void zebra_vty_init(void); extern int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, safi_t safi, const char *cmd); +extern void static_config_install_delayed_routes(struct zebra_vrf *zvrf); + extern pid_t pid; #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 64585c4c1a..f7877f71b6 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -162,6 +162,12 @@ static int zebra_vrf_enable(struct vrf *vrf) } } + /* + * We may have static routes that are now possible to + * insert into the appropriate tables + */ + static_config_install_delayed_routes(zvrf); + /* Kick off any VxLAN-EVPN processing. */ zebra_vxlan_vrf_enable(zvrf); @@ -569,7 +575,6 @@ static int vrf_config_write(struct vty *vty) ? " prefix-routes-only" : ""); zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt); - vty_out(vty, "!\n"); } static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 9fe3c707bb..32d5286d5e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -29,6 +29,7 @@ #include "rib.h" #include "nexthop.h" #include "vrf.h" +#include "linklist.h" #include "mpls.h" #include "routemap.h" #include "srcdest_table.h" @@ -76,7 +77,186 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, /* VNI range as per RFC 7432 */ #define CMD_VNI_RANGE "(1-16777215)" +struct static_hold_route { + char *vrf_name; + char *nhvrf_name; + afi_t afi; + safi_t safi; + char *dest_str; + char *mask_str; + char *src_str; + char *gate_str; + char *ifname; + char *flag_str; + char *tag_str; + char *distance_str; + char *label_str; +}; + +static struct list *static_list; + +static int static_list_compare_helper(const char *s1, const char *s2) +{ + /* Are Both NULL */ + if (s1 == s2) + return 0; + + if (!s1 && s2) + return -1; + + if (s1 && !s2) + return 1; + + return strcmp(s1, s2); +} + +static void static_list_delete(struct static_hold_route *shr) +{ + if (shr->vrf_name) + XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name); + if (shr->nhvrf_name) + XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name); + if (shr->dest_str) + XFREE(MTYPE_STATIC_ROUTE, shr->dest_str); + if (shr->mask_str) + XFREE(MTYPE_STATIC_ROUTE, shr->mask_str); + if (shr->src_str) + XFREE(MTYPE_STATIC_ROUTE, shr->src_str); + if (shr->gate_str) + XFREE(MTYPE_STATIC_ROUTE, shr->gate_str); + if (shr->ifname) + XFREE(MTYPE_STATIC_ROUTE, shr->ifname); + if (shr->flag_str) + XFREE(MTYPE_STATIC_ROUTE, shr->flag_str); + if (shr->tag_str) + XFREE(MTYPE_STATIC_ROUTE, shr->tag_str); + if (shr->distance_str) + XFREE(MTYPE_STATIC_ROUTE, shr->distance_str); + if (shr->label_str) + XFREE(MTYPE_STATIC_ROUTE, shr->label_str); + + XFREE(MTYPE_STATIC_ROUTE, shr); +} + +static int static_list_compare(void *arg1, void *arg2) +{ + struct static_hold_route *shr1 = arg1; + struct static_hold_route *shr2 = arg2; + int ret; + + ret = strcmp(shr1->vrf_name, shr2->vrf_name); + if (ret) + return ret; + + ret = strcmp(shr2->nhvrf_name, shr2->nhvrf_name); + if (ret) + return ret; + + ret = shr1->afi - shr2->afi; + if (ret) + return ret; + + ret = shr1->safi - shr2->afi; + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->dest_str, shr2->dest_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->mask_str, shr2->mask_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->src_str, shr2->src_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->ifname, shr2->ifname); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->distance_str, + shr2->distance_str); + if (ret) + return ret; + + return static_list_compare_helper(shr1->label_str, shr2->label_str); +} + + /* General function for static route. */ +static int zebra_static_route_holdem(struct zebra_vrf *zvrf, + struct zebra_vrf *nh_zvrf, + afi_t afi, safi_t safi, + const char *negate, const char *dest_str, + const char *mask_str, const char *src_str, + const char *gate_str, const char *ifname, + const char *flag_str, const char *tag_str, + const char *distance_str, + const char *label_str) +{ + struct static_hold_route *shr, *lookup; + struct listnode *node; + + shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr)); + shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, zvrf->vrf->name); + shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_zvrf->vrf->name); + shr->afi = afi; + shr->safi = safi; + if (dest_str) + shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str); + if (mask_str) + shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str); + if (src_str) + shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str); + if (gate_str) + shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str); + if (ifname) + shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname); + if (flag_str) + shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str); + if (tag_str) + shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str); + if (distance_str) + shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str); + if (label_str) + shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str); + + for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) { + if (static_list_compare(shr, lookup) == 0) + break; + } + + if (lookup) { + if (negate) { + listnode_delete(static_list, lookup); + static_list_delete(shr); + static_list_delete(lookup); + + return CMD_SUCCESS; + } + + assert(!"We should not have found a duplicate and not remove it"); + } + + listnode_add_sort(static_list, shr); + + return CMD_SUCCESS; +} + static int zebra_static_route_leak( struct vty *vty, struct zebra_vrf *zvrf, struct zebra_vrf *nh_zvrf, afi_t afi, safi_t safi, const char *negate, const char *dest_str, @@ -98,17 +278,34 @@ static int zebra_static_route_leak( ret = str2prefix(dest_str, &p); if (ret <= 0) { - vty_out(vty, "%% Malformed address\n"); + if (vty) + vty_out(vty, "%% Malformed address\n"); + else + zlog_warn("%s: Malformed address: %s", + __PRETTY_FUNCTION__, dest_str); return CMD_WARNING_CONFIG_FAILED; } + if (zvrf->vrf->vrf_id == VRF_UNKNOWN + || nh_zvrf->vrf->vrf_id == VRF_UNKNOWN) { + vrf_set_user_cfged(zvrf->vrf); + return zebra_static_route_holdem( + zvrf, nh_zvrf, afi, safi, negate, dest_str, mask_str, + src_str, gate_str, ifname, flag_str, tag_str, + distance_str, label_str); + } switch (afi) { case AFI_IP: /* Cisco like mask notation. */ if (mask_str) { ret = inet_aton(mask_str, &mask); if (ret == 0) { - vty_out(vty, "%% Malformed address\n"); + if (vty) + vty_out(vty, "%% Malformed address\n"); + else + zlog_warn("%s: Malformed address: %s", + __PRETTY_FUNCTION__, + mask_str); return CMD_WARNING_CONFIG_FAILED; } p.prefixlen = ip_masklen(mask); @@ -119,7 +316,13 @@ static int zebra_static_route_leak( if (src_str) { ret = str2prefix(src_str, &src); if (ret <= 0 || src.family != AF_INET6) { - vty_out(vty, "%% Malformed source address\n"); + if (vty) + vty_out(vty, + "%% Malformed source address\n"); + else + zlog_warn( + "%s: Malformed Source address: %s", + __PRETTY_FUNCTION__, src_str); return CMD_WARNING_CONFIG_FAILED; } src_p = (struct prefix_ipv6 *)&src; @@ -146,8 +349,13 @@ static int zebra_static_route_leak( memset(&snh_label, 0, sizeof(struct static_nh_label)); if (label_str) { if (!mpls_enabled) { - vty_out(vty, - "%% MPLS not turned on in kernel, ignoring command\n"); + if (vty) + vty_out(vty, + "%% MPLS not turned on in kernel, ignoring command\n"); + else + zlog_warn( + "%s: MPLS not turned on in kernel ignoring static route to %s", + __PRETTY_FUNCTION__, dest_str); return CMD_WARNING_CONFIG_FAILED; } int rc = mpls_str2label(label_str, &snh_label.num_labels, @@ -155,18 +363,37 @@ static int zebra_static_route_leak( if (rc < 0) { switch (rc) { case -1: - vty_out(vty, "%% Malformed label(s)\n"); + if (vty) + vty_out(vty, "%% Malformed label(s)\n"); + else + zlog_warn( + "%s: Malformed labels specified for route %s", + __PRETTY_FUNCTION__, dest_str); break; case -2: - vty_out(vty, - "%% Cannot use reserved label(s) (%d-%d)\n", - MPLS_LABEL_RESERVED_MIN, - MPLS_LABEL_RESERVED_MAX); + if (vty) + vty_out(vty, + "%% Cannot use reserved label(s) (%d-%d)\n", + MPLS_LABEL_RESERVED_MIN, + MPLS_LABEL_RESERVED_MAX); + else + zlog_warn( + "%s: Cannot use reserved labels (%d-%d) for %s", + __PRETTY_FUNCTION__, + MPLS_LABEL_RESERVED_MIN, + MPLS_LABEL_RESERVED_MAX, + dest_str); break; case -3: - vty_out(vty, - "%% Too many labels. Enter %d or fewer\n", - MPLS_MAX_LABELS); + if (vty) + vty_out(vty, + "%% Too many labels. Enter %d or fewer\n", + MPLS_MAX_LABELS); + else + zlog_warn( + "%s: Too many labels, Enter %d or fewer for %s", + __PRETTY_FUNCTION__, + MPLS_MAX_LABELS, dest_str); break; } return CMD_WARNING_CONFIG_FAILED; @@ -178,8 +405,13 @@ static int zebra_static_route_leak( if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0 || strncasecmp(ifname, "reject", strlen(ifname)) == 0 || strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) { - vty_out(vty, - "%% Nexthop interface cannot be Null0, reject or blackhole\n"); + if (vty) + vty_out(vty, + "%% Nexthop interface cannot be Null0, reject or blackhole\n"); + else + zlog_warn( + "%s: Nexthop interface cannot be Null0, reject or blackhole for %s", + __PRETTY_FUNCTION__, dest_str); return CMD_WARNING_CONFIG_FAILED; } } @@ -197,15 +429,28 @@ static int zebra_static_route_leak( bh_type = STATIC_BLACKHOLE_NULL; break; default: - vty_out(vty, "%% Malformed flag %s \n", flag_str); + if (vty) + vty_out(vty, "%% Malformed flag %s \n", + flag_str); + else + zlog_warn("%s: Malformed flag %s for %s", + __PRETTY_FUNCTION__, flag_str, + dest_str); return CMD_WARNING_CONFIG_FAILED; } } if (gate_str) { if (inet_pton(afi2family(afi), gate_str, &gate) != 1) { - vty_out(vty, "%% Malformed nexthop address %s\n", - gate_str); + if (vty) + vty_out(vty, + "%% Malformed nexthop address %s\n", + gate_str); + else + zlog_warn( + "%s: Malformed nexthop address %s for %s", + __PRETTY_FUNCTION__, gate_str, + dest_str); return CMD_WARNING_CONFIG_FAILED; } gatep = &gate; @@ -287,7 +532,38 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, gate_str, ifname, flag_str, tag_str, distance_str, label_str); } +void static_config_install_delayed_routes(struct zebra_vrf *zvrf) +{ + struct listnode *node, *nnode; + struct static_hold_route *shr; + struct zebra_vrf *ozvrf, *nh_zvrf; + int installed; + + for (ALL_LIST_ELEMENTS(static_list, node, nnode, shr)) { + ozvrf = zebra_vrf_lookup_by_name(shr->vrf_name); + nh_zvrf = zebra_vrf_lookup_by_name(shr->nhvrf_name); + + if (ozvrf != zvrf && nh_zvrf != zvrf) + continue; + + if (ozvrf->vrf->vrf_id == VRF_UNKNOWN + || nh_zvrf->vrf->vrf_id == VRF_UNKNOWN) + continue; + installed = zebra_static_route_leak( + NULL, ozvrf, nh_zvrf, shr->afi, shr->safi, NULL, + shr->dest_str, shr->mask_str, shr->src_str, + shr->gate_str, shr->ifname, shr->flag_str, shr->tag_str, + shr->distance_str, shr->label_str); + + if (installed != CMD_SUCCESS) + zlog_debug( + "%s: Attempt to install %s as a route and it was rejected", + __PRETTY_FUNCTION__, shr->dest_str); + listnode_delete(static_list, shr); + static_list_delete(shr); + } +} /* Static unicast routes for multicast RPF lookup. */ DEFPY (ip_mroute_dist, ip_mroute_dist_cmd, @@ -1894,6 +2170,8 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, safi_t safi, const char *cmd) { + struct static_hold_route *shr; + struct listnode *node; char spacing[100]; struct route_node *rn; struct static_route *si; @@ -1907,6 +2185,40 @@ int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, sprintf(spacing, "%s%s", (zvrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", cmd); + /* + * Static routes for vrfs not fully inited + */ + for (ALL_LIST_ELEMENTS_RO(static_list, node, shr)) { + if (shr->afi != afi || shr->safi != safi) + continue; + + if (strcmp(zvrf->vrf->name, shr->vrf_name) != 0) + continue; + + vty_out(vty, "%s ", spacing); + if (shr->dest_str) + vty_out(vty, "%s ", shr->dest_str); + if (shr->mask_str) + vty_out(vty, "%s ", shr->mask_str); + if (shr->src_str) + vty_out(vty, "from %s ", shr->src_str); + if (shr->gate_str) + vty_out(vty, "%s ", shr->gate_str); + if (shr->ifname) + vty_out(vty, "%s ", shr->ifname); + if (shr->flag_str) + vty_out(vty, "%s ", shr->flag_str); + if (shr->tag_str) + vty_out(vty, "tag %s", shr->tag_str); + if (shr->distance_str) + vty_out(vty, "%s ", shr->distance_str); + if (shr->label_str) + vty_out(vty, "label %s ", shr->label_str); + if (strcmp(shr->vrf_name, shr->nhvrf_name) != 0) + vty_out(vty, "nexthop-vrf %s", shr->nhvrf_name); + vty_out(vty, "\n"); + } + for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) for (si = rn->info; si; si = si->next) { vty_out(vty, "%s %s", spacing, @@ -3409,4 +3721,8 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd); install_element(VRF_NODE, &vrf_vni_mapping_cmd); install_element(VRF_NODE, &no_vrf_vni_mapping_cmd); + + static_list = list_new(); + static_list->cmp = (int (*)(void *, void *))static_list_compare; + static_list->del = (void (*)(void *))static_list_delete; } |
