diff options
| author | Christian Franke <chris@opensourcerouting.org> | 2017-04-27 13:56:41 +0200 | 
|---|---|---|
| committer | Christian Franke <chris@opensourcerouting.org> | 2017-04-28 12:03:23 +0200 | 
| commit | d8fba7d9742b93545a49b5e280825ecdf083d1a0 (patch) | |
| tree | 035f80aeb7c4c32c4f498c49e935474d8e0f9118 /isisd | |
| parent | 99894f9a17b319ca80d4a667b13cbc1a87814d2d (diff) | |
isisd: track intersecting set of supported MTs for each adj
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Diffstat (limited to 'isisd')
| -rw-r--r-- | isisd/isis_adjacency.c | 19 | ||||
| -rw-r--r-- | isisd/isis_adjacency.h | 3 | ||||
| -rw-r--r-- | isisd/isis_mt.c | 84 | ||||
| -rw-r--r-- | isisd/isis_mt.h | 5 | ||||
| -rw-r--r-- | isisd/isis_pdu.c | 14 | 
5 files changed, 124 insertions, 1 deletions
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index f550924874..c6fc6b008d 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -148,6 +148,8 @@ isis_delete_adj (void *arg)    if (adj->ipv6_addrs)      list_delete (adj->ipv6_addrs); +  adj_mt_finish(adj); +    XFREE (MTYPE_ISIS_ADJACENCY, adj);    return;  } @@ -521,3 +523,20 @@ isis_adj_build_up_list (struct list *adjdb, struct list *list)    return;  } + +int +isis_adj_usage2levels(enum isis_adj_usage usage) +{ +  switch (usage) +    { +    case ISIS_ADJ_LEVEL1: +      return IS_LEVEL_1; +    case ISIS_ADJ_LEVEL2: +      return IS_LEVEL_2; +    case ISIS_ADJ_LEVEL1AND2: +      return IS_LEVEL_1 | IS_LEVEL_2; +    default: +      break; +    } +  return 0; +} diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 8539b03d6b..4f89e30960 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -97,6 +97,8 @@ struct isis_adjacency    int flaps;			/* number of adjacency flaps  */    struct thread *t_expire;	/* expire after hold_time  */    struct isis_circuit *circuit;	/* back pointer */ +  uint16_t *mt_set;             /* Topologies this adjacency is valid for */ +  unsigned int mt_count;              /* Number of entries in mt_set */  };  struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb); @@ -112,5 +114,6 @@ int isis_adj_expire (struct thread *thread);  void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail);  void isis_adj_build_neigh_list (struct list *adjdb, struct list *list);  void isis_adj_build_up_list (struct list *adjdb, struct list *list); +int isis_adj_usage2levels(enum isis_adj_usage usage);  #endif /* ISIS_ADJACENCY_H */ diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 6d43fdf03a..4e36b91433 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -24,14 +24,19 @@  #include "isisd/isisd.h"  #include "isisd/isis_memory.h"  #include "isisd/isis_circuit.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_tlv.h"  #include "isisd/isis_mt.h"  DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")  DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") +DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")  /* MT naming api */  const char *isis_mtid2str(uint16_t mtid)  { +  static char buf[sizeof("65535")]; +    switch(mtid)      {        case ISIS_MT_IPV4_UNICAST: @@ -47,7 +52,8 @@ const char *isis_mtid2str(uint16_t mtid)        case ISIS_MT_IPV6_MGMT:          return "ipv6-mgmt";        default: -        return NULL; +        snprintf(buf, sizeof(buf), "%" PRIu16, mtid); +        return buf;      }  } @@ -355,3 +361,79 @@ circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)    *mt_count = count;    return rv;  } + +static void adj_mt_set(struct isis_adjacency *adj, unsigned int index, +                       uint16_t mtid) +{ +  if (adj->mt_count < index + 1) +    { +      adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set, +                             (index + 1) * sizeof(*adj->mt_set)); +      adj->mt_count = index + 1; +    } +  adj->mt_set[index] = mtid; +} + +bool +tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, +                   struct isis_adjacency *adj) +{ +  struct isis_circuit_mt_setting **mt_settings; +  unsigned int circuit_mt_count; + +  unsigned int intersect_count = 0; + +  uint16_t *old_mt_set; +  unsigned int old_mt_count; + +  old_mt_count = adj->mt_count; +  if (old_mt_count) +    { +      old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set)); +      memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set)); +    } + +  mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count); +  for (unsigned int i = 0; i < circuit_mt_count; i++) +    { +      if (!tlvs->mt_router_info) +        { +          /* Other end does not have MT enabled */ +          if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST) +            adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST); +        } +      else +        { +          struct listnode *node; +          struct mt_router_info *info; +          for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info)) +            { +              if (mt_settings[i]->mtid == info->mtid) +                adj_mt_set(adj, intersect_count++, info->mtid); +            } +        } +    } +  adj->mt_count = intersect_count; + +  bool changed = false; + +  if (adj->mt_count != old_mt_count) +    changed = true; + +  if (!changed && old_mt_count +      && memcmp(adj->mt_set, old_mt_set, +                old_mt_count * sizeof(*old_mt_set))) +    changed = true; + +  if (old_mt_count) +    XFREE(MTYPE_TMP, old_mt_set); + +  return changed; +} + +void +adj_mt_finish(struct isis_adjacency *adj) +{ +  XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set); +  adj->mt_count = 0; +} diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 6b1711f4c8..3ad8c05e47 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -67,8 +67,10 @@ struct isis_circuit_mt_setting {  const char *isis_mtid2str(uint16_t mtid);  uint16_t isis_str2mtid(const char *name); +struct isis_adjacency;  struct isis_area;  struct isis_circuit; +struct tlvs;  struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area,                                                      uint16_t mtid); @@ -102,4 +104,7 @@ struct isis_circuit_mt_setting* circuit_get_mt_setting(  int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty);  struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit,                                                       unsigned int *mt_count); +bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, +                        struct isis_adjacency *adj); +void adj_mt_finish(struct isis_adjacency *adj);  #endif diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 8909eb31e0..9e90acf2e0 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -635,6 +635,8 @@ process_p2p_hello (struct isis_circuit *circuit)    if (found & TLVFLAG_IPV6_ADDR)      tlvs_to_adj_ipv6_addrs (&tlvs, adj); +  bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj); +    /* lets take care of the expiry */    THREAD_TIMER_OFF (adj->t_expire);    THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, @@ -871,6 +873,13 @@ process_p2p_hello (struct isis_circuit *circuit)        /* down - area mismatch */        isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");      } + +  if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) +    { +      lsp_regenerate_schedule(adj->circuit->area, +                              isis_adj_usage2levels(adj->adj_usage), 0); +    } +    /* 8.2.5.2 c) if the action was up - comparing circuit IDs */    /* FIXME - Missing parts */ @@ -1226,6 +1235,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)    adj->circuit_t = hdr.circuit_t; +  bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj); +    /* lets take care of the expiry */    THREAD_TIMER_OFF (adj->t_expire);    THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, @@ -1269,6 +1280,9 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)                             "no LAN Neighbours TLV found");    } +  if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) +    lsp_regenerate_schedule(adj->circuit->area, level, 0); +  out:    if (isis->debugs & DEBUG_ADJ_PACKETS)      {  | 
