]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: implement threeway adjacencies
authorChristian Franke <chris@opensourcerouting.org>
Mon, 5 Mar 2018 20:00:40 +0000 (21:00 +0100)
committerChristian Franke <chris@opensourcerouting.org>
Sat, 10 Mar 2018 17:38:03 +0000 (18:38 +0100)
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
isisd/isis_adjacency.c
isisd/isis_adjacency.h
isisd/isis_pdu.c

index 72e6d4bdb99693ba8f837f461a70140bbba4181a..ece080347dad513128be4a1bea1575f5b61af6d9 100644 (file)
@@ -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) {
+               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)
 {
index 98bb9838fa5170fb9f4fef3c150b7668ca2fecb7..2c3bd19af8563571ea8090cee1b34f8ec0065169 100644 (file)
@@ -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);
index 20a491ac187a26819edecf6afee19e4c82fc9d63..8dd43258fd9dfaa768060b15a427084ae70cf789 100644 (file)
@@ -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;
                        }
@@ -1552,9 +1556,24 @@ 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) {
+               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);