mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-02 08:28:27 +00:00
Merge pull request #423 from opensourcerouting/feature/isis-mt
IS-IS multi topology
This commit is contained in:
commit
ed8ba2e920
@ -16,7 +16,7 @@ libisis_a_SOURCES = \
|
||||
isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
|
||||
isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
|
||||
isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \
|
||||
isis_vty.c
|
||||
isis_vty.c isis_mt.c
|
||||
|
||||
|
||||
noinst_HEADERS = \
|
||||
@ -25,7 +25,7 @@ noinst_HEADERS = \
|
||||
isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
|
||||
isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
|
||||
iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
|
||||
isis_route.h isis_routemap.h isis_te.h
|
||||
isis_route.h isis_routemap.h isis_te.h isis_mt.h
|
||||
|
||||
isisd_SOURCES = \
|
||||
isis_main.c $(libisis_a_SOURCES) \
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "isisd/isis_lsp.h"
|
||||
#include "isisd/isis_spf.h"
|
||||
#include "isisd/isis_events.h"
|
||||
#include "isisd/isis_mt.h"
|
||||
|
||||
extern struct isis *isis;
|
||||
|
||||
@ -148,6 +149,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 +524,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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -212,16 +212,11 @@ isis_sock_init (struct isis_circuit *circuit)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
|
||||
if (if_is_broadcast(circuit->interface))
|
||||
{
|
||||
circuit->tx = isis_send_pdu_bcast;
|
||||
circuit->rx = isis_recv_pdu_bcast;
|
||||
}
|
||||
else if (circuit->circ_type == CIRCUIT_T_P2P)
|
||||
{
|
||||
circuit->tx = isis_send_pdu_p2p;
|
||||
circuit->rx = isis_recv_pdu_p2p;
|
||||
}
|
||||
else
|
||||
{
|
||||
zlog_warn ("isis_sock_init(): unknown circuit type");
|
||||
@ -283,23 +278,6 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
|
||||
{
|
||||
int bytesread;
|
||||
|
||||
bytesread = stream_read (circuit->rcv_stream, circuit->fd,
|
||||
circuit->interface->mtu);
|
||||
|
||||
if (bytesread < 0)
|
||||
{
|
||||
zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno));
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
|
||||
{
|
||||
@ -327,7 +305,8 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
|
||||
else
|
||||
memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
|
||||
memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
|
||||
eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
|
||||
size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
|
||||
eth->ether_type = htons(isis_ethertype(frame_size));
|
||||
|
||||
/*
|
||||
* Then the LLC
|
||||
@ -354,10 +333,4 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
|
||||
{
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
#endif /* ISIS_METHOD == ISIS_METHOD_BPF */
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "isisd/isis_csm.h"
|
||||
#include "isisd/isis_events.h"
|
||||
#include "isisd/isis_te.h"
|
||||
#include "isisd/isis_mt.h"
|
||||
|
||||
DEFINE_QOBJ_TYPE(isis_circuit)
|
||||
|
||||
@ -102,6 +103,8 @@ isis_circuit_new ()
|
||||
|
||||
circuit->mtc = mpls_te_circuit_new();
|
||||
|
||||
circuit_mt_init(circuit);
|
||||
|
||||
QOBJ_REG (circuit, isis_circuit);
|
||||
|
||||
return circuit;
|
||||
@ -117,6 +120,8 @@ isis_circuit_del (struct isis_circuit *circuit)
|
||||
|
||||
isis_circuit_if_unbind (circuit, circuit->interface);
|
||||
|
||||
circuit_mt_finish(circuit);
|
||||
|
||||
/* and lastly the circuit itself */
|
||||
XFREE (MTYPE_ISIS_CIRCUIT, circuit);
|
||||
|
||||
@ -1215,6 +1220,7 @@ isis_interface_config_write (struct vty *vty)
|
||||
VTY_NEWLINE);
|
||||
write++;
|
||||
}
|
||||
write += circuit_write_mt_settings(circuit, vty);
|
||||
}
|
||||
vty_out (vty, "!%s", VTY_NEWLINE);
|
||||
}
|
||||
@ -1382,6 +1388,22 @@ isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid,
|
||||
bool enabled)
|
||||
{
|
||||
struct isis_circuit_mt_setting *setting;
|
||||
|
||||
setting = circuit_get_mt_setting(circuit, mtid);
|
||||
if (setting->enabled != enabled)
|
||||
{
|
||||
setting->enabled = enabled;
|
||||
lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
isis_if_new_hook (struct interface *ifp)
|
||||
{
|
||||
|
@ -123,6 +123,7 @@ struct isis_circuit
|
||||
struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */
|
||||
int ip_router; /* Route IP ? */
|
||||
int is_passive; /* Is Passive ? */
|
||||
struct list *mt_settings; /* IS-IS MT Settings */
|
||||
struct list *ip_addrs; /* our IP addresses */
|
||||
int ipv6_router; /* Route IPv6 ? */
|
||||
struct list *ipv6_link; /* our link local IPv6 addresses */
|
||||
@ -187,4 +188,6 @@ int isis_circuit_passwd_unset (struct isis_circuit *circuit);
|
||||
int isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd);
|
||||
int isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd);
|
||||
|
||||
int isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid, bool enabled);
|
||||
|
||||
#endif /* _ZEBRA_ISIS_CIRCUIT_H */
|
||||
|
@ -171,4 +171,14 @@
|
||||
#define ETH_ALEN 6
|
||||
#endif
|
||||
|
||||
#define MAX_LLC_LEN 0x5ff
|
||||
#define ETHERTYPE_EXT_LLC 0x8870
|
||||
|
||||
static inline uint16_t isis_ethertype(size_t len)
|
||||
{
|
||||
if (len > MAX_LLC_LEN)
|
||||
return ETHERTYPE_EXT_LLC;
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif /* ISIS_CONSTANTS_H */
|
||||
|
424
isisd/isis_lsp.c
424
isisd/isis_lsp.c
@ -53,6 +53,7 @@
|
||||
#include "isisd/isis_adjacency.h"
|
||||
#include "isisd/isis_spf.h"
|
||||
#include "isisd/isis_te.h"
|
||||
#include "isisd/isis_mt.h"
|
||||
|
||||
/* staticly assigned vars for printing purposes */
|
||||
char lsp_bits_string[200]; /* FIXME: enough ? */
|
||||
@ -501,6 +502,7 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
|
||||
expected |= TLVFLAG_TE_IPV4_REACHABILITY;
|
||||
expected |= TLVFLAG_TE_ROUTER_ID;
|
||||
}
|
||||
expected |= TLVFLAG_MT_ROUTER_INFORMATION;
|
||||
expected |= TLVFLAG_IPV4_ADDR;
|
||||
expected |= TLVFLAG_IPV4_INT_REACHABILITY;
|
||||
expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
|
||||
@ -826,6 +828,107 @@ lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
|
||||
lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static void
|
||||
lsp_print_mt_reach(struct list *list, struct vty *vty,
|
||||
char dynhost, uint16_t mtid)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct te_is_neigh *neigh;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (list, node, neigh))
|
||||
{
|
||||
u_char lspid[255];
|
||||
|
||||
lspid_print(neigh->neigh_id, lspid, dynhost, 0);
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
vty_out(vty, " Metric : %-8d IS-Extended : %s%s",
|
||||
GET_TE_METRIC(neigh), lspid, VTY_NEWLINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
vty_out(vty, " Metric : %-8d MT-Reach : %s %s%s",
|
||||
GET_TE_METRIC(neigh), lspid,
|
||||
isis_mtid2str(mtid), VTY_NEWLINE);
|
||||
}
|
||||
if (IS_MPLS_TE(isisMplsTE))
|
||||
mpls_te_print_detail(vty, neigh);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty, uint16_t mtid)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct ipv6_reachability *ipv6_reach;
|
||||
struct in6_addr in6;
|
||||
u_char buff[BUFSIZ];
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (list, node, ipv6_reach))
|
||||
{
|
||||
memset (&in6, 0, sizeof (in6));
|
||||
memcpy (in6.s6_addr, ipv6_reach->prefix,
|
||||
PSIZE (ipv6_reach->prefix_len));
|
||||
inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
if ((ipv6_reach->control_info &
|
||||
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
|
||||
vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
|
||||
ntohl (ipv6_reach->metric),
|
||||
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
|
||||
else
|
||||
vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
|
||||
ntohl (ipv6_reach->metric),
|
||||
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((ipv6_reach->control_info &
|
||||
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
|
||||
vty_out (vty, " Metric : %-8d IPv6-MT-Int : %s/%d %s%s",
|
||||
ntohl (ipv6_reach->metric),
|
||||
buff, ipv6_reach->prefix_len,
|
||||
isis_mtid2str(mtid), VTY_NEWLINE);
|
||||
else
|
||||
vty_out (vty, " Metric : %-8d IPv6-MT-Ext : %s/%d %s%s",
|
||||
ntohl (ipv6_reach->metric),
|
||||
buff, ipv6_reach->prefix_len,
|
||||
isis_mtid2str(mtid), VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty, uint16_t mtid)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct te_ipv4_reachability *te_ipv4_reach;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (list, node, te_ipv4_reach))
|
||||
{
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
/* FIXME: There should be better way to output this stuff. */
|
||||
vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
|
||||
ntohl (te_ipv4_reach->te_metric),
|
||||
inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
|
||||
te_ipv4_reach->control)),
|
||||
te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: There should be better way to output this stuff. */
|
||||
vty_out (vty, " Metric : %-8d IPv4-MT : %s/%d %s%s",
|
||||
ntohl (te_ipv4_reach->te_metric),
|
||||
inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
|
||||
te_ipv4_reach->control)),
|
||||
te_ipv4_reach->control & 0x3F,
|
||||
isis_mtid2str(mtid), VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
|
||||
{
|
||||
@ -833,13 +936,12 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
|
||||
int i;
|
||||
struct listnode *lnode;
|
||||
struct is_neigh *is_neigh;
|
||||
struct te_is_neigh *te_is_neigh;
|
||||
struct ipv4_reachability *ipv4_reach;
|
||||
struct in_addr *ipv4_addr;
|
||||
struct te_ipv4_reachability *te_ipv4_reach;
|
||||
struct ipv6_reachability *ipv6_reach;
|
||||
struct in6_addr in6;
|
||||
u_char buff[BUFSIZ];
|
||||
struct mt_router_info *mt_router_info;
|
||||
struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
|
||||
struct tlv_mt_neighbors *mt_is_neigh;
|
||||
struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
|
||||
u_char LSPid[255];
|
||||
u_char hostname[255];
|
||||
u_char ipv4_reach_prefix[20];
|
||||
@ -877,6 +979,14 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
|
||||
}
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, mt_router_info))
|
||||
{
|
||||
vty_out (vty, " MT : %s%s%s",
|
||||
isis_mtid2str(mt_router_info->mtid),
|
||||
mt_router_info->overload ? " (overload)" : "",
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
/* for the hostname tlv */
|
||||
if (lsp->tlv_data.hostname)
|
||||
{
|
||||
@ -946,49 +1056,31 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
|
||||
ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
|
||||
ipv4_reach_mask, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
|
||||
/* IPv6 tlv */
|
||||
if (lsp->tlv_data.ipv6_reachs)
|
||||
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
|
||||
{
|
||||
memset (&in6, 0, sizeof (in6));
|
||||
memcpy (in6.s6_addr, ipv6_reach->prefix,
|
||||
PSIZE (ipv6_reach->prefix_len));
|
||||
inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
|
||||
if ((ipv6_reach->control_info &
|
||||
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
|
||||
vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
|
||||
ntohl (ipv6_reach->metric),
|
||||
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
|
||||
else
|
||||
vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
|
||||
ntohl (ipv6_reach->metric),
|
||||
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
|
||||
}
|
||||
lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty,
|
||||
ISIS_MT_IPV4_UNICAST);
|
||||
|
||||
/* MT IPv6 reachability tlv */
|
||||
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv6_reachs, lnode, mt_ipv6_reachs))
|
||||
lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty, mt_ipv6_reachs->mtid);
|
||||
|
||||
/* TE IS neighbor tlv */
|
||||
if (lsp->tlv_data.te_is_neighs)
|
||||
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
|
||||
{
|
||||
lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
|
||||
vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
|
||||
GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
|
||||
if (IS_MPLS_TE(isisMplsTE))
|
||||
mpls_te_print_detail(vty, te_is_neigh);
|
||||
}
|
||||
lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty,
|
||||
dynhost, ISIS_MT_IPV4_UNICAST);
|
||||
|
||||
/* MT IS neighbor tlv */
|
||||
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_is_neighs, lnode, mt_is_neigh))
|
||||
lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost, mt_is_neigh->mtid);
|
||||
|
||||
/* TE IPv4 tlv */
|
||||
if (lsp->tlv_data.te_ipv4_reachs)
|
||||
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
|
||||
te_ipv4_reach))
|
||||
{
|
||||
/* FIXME: There should be better way to output this stuff. */
|
||||
vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
|
||||
ntohl (te_ipv4_reach->te_metric),
|
||||
inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
|
||||
te_ipv4_reach->control)),
|
||||
te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
|
||||
}
|
||||
lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty,
|
||||
ISIS_MT_IPV4_UNICAST);
|
||||
|
||||
/* MT IPv4 reachability tlv */
|
||||
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv4_reachs, lnode, mt_ipv4_reachs))
|
||||
lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty, mt_ipv4_reachs->mtid);
|
||||
|
||||
vty_out (vty, "%s", VTY_NEWLINE);
|
||||
|
||||
return;
|
||||
@ -1028,6 +1120,42 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
|
||||
return lsp_count;
|
||||
}
|
||||
|
||||
static void
|
||||
_lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
|
||||
int frag_thold,
|
||||
unsigned int tlv_build_func (struct list *, struct stream *,
|
||||
void *arg),
|
||||
void *arg)
|
||||
{
|
||||
while (*from && listcount(*from))
|
||||
{
|
||||
unsigned int count;
|
||||
|
||||
count = tlv_build_func(*from, lsp->pdu, arg);
|
||||
|
||||
if (listcount(*to) != 0 || count != listcount(*from))
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
void *elem;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(*from, node, nnode, elem))
|
||||
{
|
||||
if (!count)
|
||||
break;
|
||||
listnode_add (*to, elem);
|
||||
list_delete_node (*from, node);
|
||||
--count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
list_free (*to);
|
||||
*to = *from;
|
||||
*from = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define FRAG_THOLD(S,T) \
|
||||
((STREAM_SIZE(S)*T)/100)
|
||||
|
||||
@ -1085,64 +1213,6 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process IS_NEIGHBOURS TLV with TE subTLVs */
|
||||
void
|
||||
lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold)
|
||||
{
|
||||
int count, size = 0;
|
||||
struct listnode *node, *nextnode;
|
||||
struct te_is_neigh *elem;
|
||||
|
||||
/* Start computing real size of TLVs */
|
||||
for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
|
||||
size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN;
|
||||
|
||||
/* can we fit all ? */
|
||||
if (!FRAG_NEEDED (lsp->pdu, frag_thold, size))
|
||||
{
|
||||
tlv_add_te_is_neighs (*from, lsp->pdu);
|
||||
if (listcount (*to) != 0)
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
|
||||
{
|
||||
listnode_add (*to, elem);
|
||||
list_delete_node (*from, node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
list_free (*to);
|
||||
*to = *from;
|
||||
*from = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fit all we can */
|
||||
/* Compute remaining place in LSP PDU */
|
||||
count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
|
||||
(STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
|
||||
/* Determine size of TE SubTLVs */
|
||||
elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
|
||||
count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
|
||||
if (count > 0)
|
||||
{
|
||||
while (count > 0)
|
||||
{
|
||||
listnode_add (*to, listgetdata ((struct listnode *)listhead (*from)));
|
||||
listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from)));
|
||||
|
||||
elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
|
||||
count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
|
||||
}
|
||||
|
||||
tlv_add_te_is_neighs (*to, lsp->pdu);
|
||||
}
|
||||
}
|
||||
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
|
||||
return;
|
||||
}
|
||||
|
||||
static u_int16_t
|
||||
lsp_rem_lifetime (struct isis_area *area, int level)
|
||||
{
|
||||
@ -1278,6 +1348,24 @@ lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
|
||||
}
|
||||
}
|
||||
|
||||
static struct list *
|
||||
tlv_get_ipv6_reach_list(struct isis_area *area, struct tlvs *tlv_data)
|
||||
{
|
||||
uint16_t mtid = isis_area_ipv6_topology(area);
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
if (!tlv_data->ipv6_reachs)
|
||||
{
|
||||
tlv_data->ipv6_reachs = list_new();
|
||||
tlv_data->ipv6_reachs->del = free_tlv;
|
||||
}
|
||||
return tlv_data->ipv6_reachs;
|
||||
}
|
||||
|
||||
struct tlv_mt_ipv6_reachs *reachs = tlvs_get_mt_ipv6_reachs(tlv_data, mtid);
|
||||
return reachs->list;
|
||||
}
|
||||
|
||||
static void
|
||||
lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
|
||||
struct tlvs *tlv_data)
|
||||
@ -1287,6 +1375,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
|
||||
struct prefix_ipv6 *ipv6;
|
||||
struct isis_ext_info *info;
|
||||
struct ipv6_reachability *ip6reach;
|
||||
struct list *reach_list = NULL;
|
||||
|
||||
er_table = get_ext_reach(area, AF_INET6, lsp->level);
|
||||
if (!er_table)
|
||||
@ -1300,11 +1389,9 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
|
||||
ipv6 = (struct prefix_ipv6*)&rn->p;
|
||||
info = rn->info;
|
||||
|
||||
if (tlv_data->ipv6_reachs == NULL)
|
||||
{
|
||||
tlv_data->ipv6_reachs = list_new();
|
||||
tlv_data->ipv6_reachs->del = free_tlv;
|
||||
}
|
||||
if (!reach_list)
|
||||
reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
|
||||
|
||||
ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
|
||||
if (info->metric > MAX_WIDE_PATH_METRIC)
|
||||
ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
|
||||
@ -1313,7 +1400,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
|
||||
ip6reach->control_info = DISTRIBUTION_EXTERNAL;
|
||||
ip6reach->prefix_len = ipv6->prefixlen;
|
||||
memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
|
||||
listnode_add(tlv_data->ipv6_reachs, ip6reach);
|
||||
listnode_add(reach_list, ip6reach);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1342,6 +1429,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
||||
struct te_ipv4_reachability *te_ipreach;
|
||||
struct isis_adjacency *nei;
|
||||
struct prefix_ipv6 *ipv6, ip6prefix;
|
||||
struct list *ipv6_reachs = NULL;
|
||||
struct ipv6_reachability *ip6reach;
|
||||
struct tlvs tlv_data;
|
||||
struct isis_lsp *lsp0 = lsp;
|
||||
@ -1402,6 +1490,32 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
||||
tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
|
||||
}
|
||||
|
||||
if (area_is_mt(area))
|
||||
{
|
||||
lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
|
||||
lsp->tlv_data.mt_router_info = list_new();
|
||||
lsp->tlv_data.mt_router_info->del = free_tlv;
|
||||
|
||||
struct isis_area_mt_setting **mt_settings;
|
||||
unsigned int mt_count;
|
||||
|
||||
mt_settings = area_mt_settings(area, &mt_count);
|
||||
for (unsigned int i = 0; i < mt_count; i++)
|
||||
{
|
||||
struct mt_router_info *info;
|
||||
|
||||
info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
|
||||
info->mtid = mt_settings[i]->mtid;
|
||||
info->overload = mt_settings[i]->overload;
|
||||
listnode_add(lsp->tlv_data.mt_router_info, info);
|
||||
lsp_debug("ISIS (%s): MT %s", area->area_tag, isis_mtid2str(info->mtid));
|
||||
}
|
||||
tlv_add_mt_router_info (lsp->tlv_data.mt_router_info, lsp->pdu);
|
||||
}
|
||||
else
|
||||
{
|
||||
lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area->area_tag);
|
||||
}
|
||||
/* Dynamic Hostname */
|
||||
if (area->dynhostname)
|
||||
{
|
||||
@ -1551,12 +1665,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
||||
if (circuit->ipv6_router && circuit->ipv6_non_link &&
|
||||
circuit->ipv6_non_link->count > 0)
|
||||
{
|
||||
if (!ipv6_reachs)
|
||||
ipv6_reachs = tlv_get_ipv6_reach_list(area, &tlv_data);
|
||||
|
||||
if (tlv_data.ipv6_reachs == NULL)
|
||||
{
|
||||
tlv_data.ipv6_reachs = list_new ();
|
||||
tlv_data.ipv6_reachs->del = free_tlv;
|
||||
}
|
||||
for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
|
||||
{
|
||||
ip6reach =
|
||||
@ -1579,7 +1690,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
||||
|
||||
memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
|
||||
sizeof (ip6reach->prefix));
|
||||
listnode_add (tlv_data.ipv6_reachs, ip6reach);
|
||||
listnode_add (ipv6_reachs, ip6reach);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1658,10 +1769,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
||||
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
|
||||
te_is_neigh->sub_tlvs_length = 0;
|
||||
|
||||
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
|
||||
lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
|
||||
area->area_tag, sysid_print(te_is_neigh->neigh_id),
|
||||
LSP_PSEUDO_ID(te_is_neigh->neigh_id));
|
||||
tlvs_add_mt_bcast(&tlv_data, circuit, level, te_is_neigh);
|
||||
XFREE(MTYPE_ISIS_TLV, te_is_neigh);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1718,9 +1827,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
||||
else
|
||||
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
|
||||
te_is_neigh->sub_tlvs_length = 0;
|
||||
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
|
||||
lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
|
||||
sysid_print(te_is_neigh->neigh_id));
|
||||
|
||||
tlvs_add_mt_p2p(&tlv_data, circuit, te_is_neigh);
|
||||
XFREE(MTYPE_ISIS_TLV, te_is_neigh);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1766,35 +1875,62 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
||||
lsp0, area, level);
|
||||
}
|
||||
|
||||
/* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
|
||||
* for now. lsp_tlv_fit() needs to be fixed to deal with variable length
|
||||
* TLVs (sub TLVs!). */
|
||||
while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
|
||||
{
|
||||
if (lsp->tlv_data.te_ipv4_reachs == NULL)
|
||||
lsp->tlv_data.te_ipv4_reachs = list_new ();
|
||||
lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
|
||||
&lsp->tlv_data.te_ipv4_reachs,
|
||||
TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
|
||||
tlv_add_te_ipv4_reachs);
|
||||
_lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, &lsp->tlv_data.te_ipv4_reachs,
|
||||
area->lsp_frag_threshold, tlv_add_te_ipv4_reachs, NULL);
|
||||
if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
|
||||
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
||||
lsp0, area, level);
|
||||
}
|
||||
|
||||
struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
|
||||
for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node, mt_ipv4_reachs))
|
||||
{
|
||||
while (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list))
|
||||
{
|
||||
struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs;
|
||||
|
||||
frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(&lsp->tlv_data, mt_ipv4_reachs->mtid);
|
||||
_lsp_tlv_fit (lsp, &mt_ipv4_reachs->list, &frag_mt_ipv4_reachs->list,
|
||||
area->lsp_frag_threshold, tlv_add_te_ipv4_reachs,
|
||||
&mt_ipv4_reachs->mtid);
|
||||
if (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list))
|
||||
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
||||
lsp0, area, level);
|
||||
}
|
||||
}
|
||||
|
||||
while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
|
||||
{
|
||||
if (lsp->tlv_data.ipv6_reachs == NULL)
|
||||
lsp->tlv_data.ipv6_reachs = list_new ();
|
||||
lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
|
||||
&lsp->tlv_data.ipv6_reachs,
|
||||
IPV6_REACH_LEN, area->lsp_frag_threshold,
|
||||
tlv_add_ipv6_reachs);
|
||||
_lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
|
||||
area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
|
||||
if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
|
||||
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
||||
lsp0, area, level);
|
||||
}
|
||||
|
||||
struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
|
||||
for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node, mt_ipv6_reachs))
|
||||
{
|
||||
while (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list))
|
||||
{
|
||||
struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs;
|
||||
|
||||
frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(&lsp->tlv_data, mt_ipv6_reachs->mtid);
|
||||
_lsp_tlv_fit (lsp, &mt_ipv6_reachs->list, &frag_mt_ipv6_reachs->list,
|
||||
area->lsp_frag_threshold, tlv_add_ipv6_reachs,
|
||||
&mt_ipv6_reachs->mtid);
|
||||
if (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list))
|
||||
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
||||
lsp0, area, level);
|
||||
}
|
||||
}
|
||||
|
||||
while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
|
||||
{
|
||||
if (lsp->tlv_data.is_neighs == NULL)
|
||||
@ -1812,13 +1948,31 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
|
||||
{
|
||||
if (lsp->tlv_data.te_is_neighs == NULL)
|
||||
lsp->tlv_data.te_is_neighs = list_new ();
|
||||
lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
|
||||
IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
|
||||
tlv_add_te_is_neighs);
|
||||
_lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
|
||||
area->lsp_frag_threshold, tlv_add_te_is_neighs, NULL);
|
||||
if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
|
||||
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
||||
lsp0, area, level);
|
||||
}
|
||||
|
||||
struct tlv_mt_neighbors *mt_neighs;
|
||||
for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs))
|
||||
{
|
||||
while (mt_neighs->list && listcount(mt_neighs->list))
|
||||
{
|
||||
struct tlv_mt_neighbors *frag_mt_neighs;
|
||||
|
||||
frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data, mt_neighs->mtid);
|
||||
_lsp_tlv_fit (lsp, &mt_neighs->list, &frag_mt_neighs->list,
|
||||
area->lsp_frag_threshold, tlv_add_te_is_neighs,
|
||||
&mt_neighs->mtid);
|
||||
if (mt_neighs->list && listcount(mt_neighs->list))
|
||||
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
|
||||
lsp0, area, level);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
|
||||
|
||||
free_tlvs (&tlv_data);
|
||||
@ -2255,7 +2409,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
|
||||
tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
|
||||
|
||||
if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
|
||||
tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
|
||||
tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu, NULL);
|
||||
|
||||
if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
|
||||
tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
|
||||
|
@ -108,8 +108,6 @@ void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost);
|
||||
int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail,
|
||||
char dynhost);
|
||||
const char *lsp_bits2string (u_char *);
|
||||
void lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from,
|
||||
struct list **to, int frag_thold);
|
||||
|
||||
/* sets SRMflags for all active circuits of an lsp */
|
||||
void lsp_set_all_srmflags (struct isis_lsp *lsp);
|
||||
|
724
isisd/isis_mt.c
Normal file
724
isisd/isis_mt.c
Normal file
@ -0,0 +1,724 @@
|
||||
/*
|
||||
* IS-IS Rout(e)ing protocol - Multi Topology Support
|
||||
*
|
||||
* Copyright (C) 2017 Christian Franke
|
||||
*
|
||||
* This file is part of FreeRangeRouting (FRR)
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
#include <zebra.h>
|
||||
#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_misc.h"
|
||||
#include "isisd/isis_lsp.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")
|
||||
DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
|
||||
DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, "ISIS MT IPv4 Reachabilities for TLV")
|
||||
DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, "ISIS MT IPv6 Reachabilities for TLV")
|
||||
|
||||
uint16_t isis_area_ipv6_topology(struct isis_area *area)
|
||||
{
|
||||
struct isis_area_mt_setting *area_mt_setting;
|
||||
area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_UNICAST);
|
||||
|
||||
if (area_mt_setting && area_mt_setting->enabled)
|
||||
return ISIS_MT_IPV6_UNICAST;
|
||||
return ISIS_MT_IPV4_UNICAST;
|
||||
}
|
||||
|
||||
/* MT naming api */
|
||||
const char *isis_mtid2str(uint16_t mtid)
|
||||
{
|
||||
static char buf[sizeof("65535")];
|
||||
|
||||
switch(mtid)
|
||||
{
|
||||
case ISIS_MT_IPV4_UNICAST:
|
||||
return "ipv4-unicast";
|
||||
case ISIS_MT_IPV4_MGMT:
|
||||
return "ipv4-mgmt";
|
||||
case ISIS_MT_IPV6_UNICAST:
|
||||
return "ipv6-unicast";
|
||||
case ISIS_MT_IPV4_MULTICAST:
|
||||
return "ipv4-multicast";
|
||||
case ISIS_MT_IPV6_MULTICAST:
|
||||
return "ipv6-multicast";
|
||||
case ISIS_MT_IPV6_MGMT:
|
||||
return "ipv6-mgmt";
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t isis_str2mtid(const char *name)
|
||||
{
|
||||
if (!strcmp(name,"ipv4-unicast"))
|
||||
return ISIS_MT_IPV4_UNICAST;
|
||||
if (!strcmp(name,"ipv4-mgmt"))
|
||||
return ISIS_MT_IPV4_MGMT;
|
||||
if (!strcmp(name,"ipv6-unicast"))
|
||||
return ISIS_MT_IPV6_UNICAST;
|
||||
if (!strcmp(name,"ipv4-multicast"))
|
||||
return ISIS_MT_IPV4_MULTICAST;
|
||||
if (!strcmp(name,"ipv6-multicast"))
|
||||
return ISIS_MT_IPV6_MULTICAST;
|
||||
if (!strcmp(name,"ipv6-mgmt"))
|
||||
return ISIS_MT_IPV6_MGMT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* General MT settings api */
|
||||
|
||||
struct mt_setting {
|
||||
ISIS_MT_INFO_FIELDS;
|
||||
};
|
||||
|
||||
static void *
|
||||
lookup_mt_setting(struct list *mt_list, uint16_t mtid)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct mt_setting *setting;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(mt_list, node, setting))
|
||||
{
|
||||
if (setting->mtid == mtid)
|
||||
return setting;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
add_mt_setting(struct list **mt_list, void *setting)
|
||||
{
|
||||
if (!*mt_list)
|
||||
*mt_list = list_new();
|
||||
listnode_add(*mt_list, setting);
|
||||
}
|
||||
|
||||
/* Area specific MT settings api */
|
||||
|
||||
struct isis_area_mt_setting*
|
||||
area_lookup_mt_setting(struct isis_area *area, uint16_t mtid)
|
||||
{
|
||||
return lookup_mt_setting(area->mt_settings, mtid);
|
||||
}
|
||||
|
||||
struct isis_area_mt_setting*
|
||||
area_new_mt_setting(struct isis_area *area, uint16_t mtid)
|
||||
{
|
||||
struct isis_area_mt_setting *setting;
|
||||
|
||||
setting = XCALLOC(MTYPE_MT_AREA_SETTING, sizeof(*setting));
|
||||
setting->mtid = mtid;
|
||||
return setting;
|
||||
}
|
||||
|
||||
static void
|
||||
area_free_mt_setting(void *setting)
|
||||
{
|
||||
XFREE(MTYPE_MT_AREA_SETTING, setting);
|
||||
}
|
||||
|
||||
void
|
||||
area_add_mt_setting(struct isis_area *area, struct isis_area_mt_setting *setting)
|
||||
{
|
||||
add_mt_setting(&area->mt_settings, setting);
|
||||
}
|
||||
|
||||
void
|
||||
area_mt_init(struct isis_area *area)
|
||||
{
|
||||
struct isis_area_mt_setting *v4_unicast_setting;
|
||||
|
||||
/* MTID 0 is always enabled */
|
||||
v4_unicast_setting = area_new_mt_setting(area, ISIS_MT_IPV4_UNICAST);
|
||||
v4_unicast_setting->enabled = true;
|
||||
add_mt_setting(&area->mt_settings, v4_unicast_setting);
|
||||
area->mt_settings->del = area_free_mt_setting;
|
||||
}
|
||||
|
||||
void
|
||||
area_mt_finish(struct isis_area *area)
|
||||
{
|
||||
list_delete(area->mt_settings);
|
||||
area->mt_settings = NULL;
|
||||
}
|
||||
|
||||
struct isis_area_mt_setting *
|
||||
area_get_mt_setting(struct isis_area *area, uint16_t mtid)
|
||||
{
|
||||
struct isis_area_mt_setting *setting;
|
||||
|
||||
setting = area_lookup_mt_setting(area, mtid);
|
||||
if (!setting)
|
||||
{
|
||||
setting = area_new_mt_setting(area, mtid);
|
||||
area_add_mt_setting(area, setting);
|
||||
}
|
||||
return setting;
|
||||
}
|
||||
|
||||
int
|
||||
area_write_mt_settings(struct isis_area *area, struct vty *vty)
|
||||
{
|
||||
int written = 0;
|
||||
struct listnode *node;
|
||||
struct isis_area_mt_setting *setting;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
|
||||
{
|
||||
const char *name = isis_mtid2str(setting->mtid);
|
||||
if (name && setting->enabled)
|
||||
{
|
||||
if (setting->mtid == ISIS_MT_IPV4_UNICAST)
|
||||
continue; /* always enabled, no need to write out config */
|
||||
vty_out (vty, " topology %s%s%s", name,
|
||||
setting->overload ? " overload" : "",
|
||||
VTY_NEWLINE);
|
||||
written++;
|
||||
}
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
bool area_is_mt(struct isis_area *area)
|
||||
{
|
||||
struct listnode *node, *node2;
|
||||
struct isis_area_mt_setting *setting;
|
||||
struct isis_circuit *circuit;
|
||||
struct isis_circuit_mt_setting *csetting;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
|
||||
{
|
||||
if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
|
||||
return true;
|
||||
}
|
||||
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting))
|
||||
{
|
||||
if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct isis_area_mt_setting**
|
||||
area_mt_settings(struct isis_area *area, unsigned int *mt_count)
|
||||
{
|
||||
static unsigned int size = 0;
|
||||
static struct isis_area_mt_setting **rv = NULL;
|
||||
|
||||
unsigned int count = 0;
|
||||
struct listnode *node;
|
||||
struct isis_area_mt_setting *setting;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
|
||||
{
|
||||
if (!setting->enabled)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
if (count > size)
|
||||
{
|
||||
rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
|
||||
size = count;
|
||||
}
|
||||
rv[count-1] = setting;
|
||||
}
|
||||
|
||||
*mt_count = count;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Circuit specific MT settings api */
|
||||
|
||||
struct isis_circuit_mt_setting*
|
||||
circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
|
||||
{
|
||||
return lookup_mt_setting(circuit->mt_settings, mtid);
|
||||
}
|
||||
|
||||
struct isis_circuit_mt_setting*
|
||||
circuit_new_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
|
||||
{
|
||||
struct isis_circuit_mt_setting *setting;
|
||||
|
||||
setting = XCALLOC(MTYPE_MT_CIRCUIT_SETTING, sizeof(*setting));
|
||||
setting->mtid = mtid;
|
||||
setting->enabled = true; /* Enabled is default for circuit */
|
||||
return setting;
|
||||
}
|
||||
|
||||
static void
|
||||
circuit_free_mt_setting(void *setting)
|
||||
{
|
||||
XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
|
||||
}
|
||||
|
||||
void
|
||||
circuit_add_mt_setting(struct isis_circuit *circuit,
|
||||
struct isis_circuit_mt_setting *setting)
|
||||
{
|
||||
add_mt_setting(&circuit->mt_settings, setting);
|
||||
}
|
||||
|
||||
void
|
||||
circuit_mt_init(struct isis_circuit *circuit)
|
||||
{
|
||||
circuit->mt_settings = list_new();
|
||||
circuit->mt_settings->del = circuit_free_mt_setting;
|
||||
}
|
||||
|
||||
void
|
||||
circuit_mt_finish(struct isis_circuit *circuit)
|
||||
{
|
||||
list_delete(circuit->mt_settings);
|
||||
circuit->mt_settings = NULL;
|
||||
}
|
||||
|
||||
struct isis_circuit_mt_setting*
|
||||
circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
|
||||
{
|
||||
struct isis_circuit_mt_setting *setting;
|
||||
|
||||
setting = circuit_lookup_mt_setting(circuit, mtid);
|
||||
if (!setting)
|
||||
{
|
||||
setting = circuit_new_mt_setting(circuit, mtid);
|
||||
circuit_add_mt_setting(circuit, setting);
|
||||
}
|
||||
return setting;
|
||||
}
|
||||
|
||||
int
|
||||
circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
|
||||
{
|
||||
int written = 0;
|
||||
struct listnode *node;
|
||||
struct isis_circuit_mt_setting *setting;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (circuit->mt_settings, node, setting))
|
||||
{
|
||||
const char *name = isis_mtid2str(setting->mtid);
|
||||
if (name && !setting->enabled)
|
||||
{
|
||||
vty_out (vty, " no isis topology %s%s", name, VTY_NEWLINE);
|
||||
written++;
|
||||
}
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
struct isis_circuit_mt_setting**
|
||||
circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
|
||||
{
|
||||
static unsigned int size = 0;
|
||||
static struct isis_circuit_mt_setting **rv = NULL;
|
||||
|
||||
struct isis_area_mt_setting **area_settings;
|
||||
unsigned int area_count;
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
struct listnode *node;
|
||||
struct isis_circuit_mt_setting *setting;
|
||||
|
||||
area_settings = area_mt_settings(circuit->area, &area_count);
|
||||
|
||||
for (unsigned int i = 0; i < area_count; i++)
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting))
|
||||
{
|
||||
if (setting->mtid != area_settings[i]->mtid)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (!setting)
|
||||
setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid);
|
||||
|
||||
if (!setting->enabled)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
if (count > size)
|
||||
{
|
||||
rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
|
||||
size = count;
|
||||
}
|
||||
rv[count-1] = setting;
|
||||
}
|
||||
|
||||
*mt_count = count;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* ADJ specific MT API */
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
|
||||
{
|
||||
for (unsigned int i = 0; i < adj->mt_count; i++)
|
||||
if (adj->mt_set[i] == mtid)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
adj_mt_finish(struct isis_adjacency *adj)
|
||||
{
|
||||
XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
|
||||
adj->mt_count = 0;
|
||||
}
|
||||
|
||||
/* TLV Router info api */
|
||||
struct mt_router_info*
|
||||
tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
|
||||
{
|
||||
return lookup_mt_setting(tlvs->mt_router_info, mtid);
|
||||
}
|
||||
|
||||
/* TLV MT Neighbors api */
|
||||
struct tlv_mt_neighbors*
|
||||
tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
|
||||
{
|
||||
return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
|
||||
}
|
||||
|
||||
static struct tlv_mt_neighbors*
|
||||
tlvs_new_mt_neighbors(uint16_t mtid)
|
||||
{
|
||||
struct tlv_mt_neighbors *rv;
|
||||
|
||||
rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
|
||||
rv->mtid = mtid;
|
||||
rv->list = list_new();
|
||||
|
||||
return rv;
|
||||
};
|
||||
|
||||
static void
|
||||
tlvs_free_mt_neighbors(void *arg)
|
||||
{
|
||||
struct tlv_mt_neighbors *neighbors = arg;
|
||||
|
||||
if (neighbors && neighbors->list)
|
||||
list_delete(neighbors->list);
|
||||
XFREE(MTYPE_MT_NEIGHBORS, neighbors);
|
||||
}
|
||||
|
||||
static void
|
||||
tlvs_add_mt_neighbors(struct tlvs *tlvs, struct tlv_mt_neighbors *neighbors)
|
||||
{
|
||||
add_mt_setting(&tlvs->mt_is_neighs, neighbors);
|
||||
tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
|
||||
}
|
||||
|
||||
struct tlv_mt_neighbors*
|
||||
tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
|
||||
{
|
||||
struct tlv_mt_neighbors *neighbors;
|
||||
|
||||
neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
|
||||
if (!neighbors)
|
||||
{
|
||||
neighbors = tlvs_new_mt_neighbors(mtid);
|
||||
tlvs_add_mt_neighbors(tlvs, neighbors);
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
/* TLV MT IPv4 reach api */
|
||||
struct tlv_mt_ipv4_reachs*
|
||||
tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
|
||||
{
|
||||
return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
|
||||
}
|
||||
|
||||
static struct tlv_mt_ipv4_reachs*
|
||||
tlvs_new_mt_ipv4_reachs(uint16_t mtid)
|
||||
{
|
||||
struct tlv_mt_ipv4_reachs *rv;
|
||||
|
||||
rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
|
||||
rv->mtid = mtid;
|
||||
rv->list = list_new();
|
||||
|
||||
return rv;
|
||||
};
|
||||
|
||||
static void
|
||||
tlvs_free_mt_ipv4_reachs(void *arg)
|
||||
{
|
||||
struct tlv_mt_ipv4_reachs *reachs = arg;
|
||||
|
||||
if (reachs && reachs->list)
|
||||
list_delete(reachs->list);
|
||||
XFREE(MTYPE_MT_IPV4_REACHS, reachs);
|
||||
}
|
||||
|
||||
static void
|
||||
tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, struct tlv_mt_ipv4_reachs *reachs)
|
||||
{
|
||||
add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
|
||||
tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
|
||||
}
|
||||
|
||||
struct tlv_mt_ipv4_reachs*
|
||||
tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
|
||||
{
|
||||
struct tlv_mt_ipv4_reachs *reachs;
|
||||
|
||||
reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
|
||||
if (!reachs)
|
||||
{
|
||||
reachs = tlvs_new_mt_ipv4_reachs(mtid);
|
||||
tlvs_add_mt_ipv4_reachs(tlvs, reachs);
|
||||
}
|
||||
return reachs;
|
||||
}
|
||||
|
||||
/* TLV MT IPv6 reach api */
|
||||
struct tlv_mt_ipv6_reachs*
|
||||
tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
|
||||
{
|
||||
return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
|
||||
}
|
||||
|
||||
static struct tlv_mt_ipv6_reachs*
|
||||
tlvs_new_mt_ipv6_reachs(uint16_t mtid)
|
||||
{
|
||||
struct tlv_mt_ipv6_reachs *rv;
|
||||
|
||||
rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
|
||||
rv->mtid = mtid;
|
||||
rv->list = list_new();
|
||||
|
||||
return rv;
|
||||
};
|
||||
|
||||
static void
|
||||
tlvs_free_mt_ipv6_reachs(void *arg)
|
||||
{
|
||||
struct tlv_mt_ipv6_reachs *reachs = arg;
|
||||
|
||||
if (reachs && reachs->list)
|
||||
list_delete(reachs->list);
|
||||
XFREE(MTYPE_MT_IPV6_REACHS, reachs);
|
||||
}
|
||||
|
||||
static void
|
||||
tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, struct tlv_mt_ipv6_reachs *reachs)
|
||||
{
|
||||
add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
|
||||
tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
|
||||
}
|
||||
|
||||
struct tlv_mt_ipv6_reachs*
|
||||
tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
|
||||
{
|
||||
struct tlv_mt_ipv6_reachs *reachs;
|
||||
|
||||
reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
|
||||
if (!reachs)
|
||||
{
|
||||
reachs = tlvs_new_mt_ipv6_reachs(mtid);
|
||||
tlvs_add_mt_ipv6_reachs(tlvs, reachs);
|
||||
}
|
||||
return reachs;
|
||||
}
|
||||
|
||||
static void
|
||||
mt_set_add(uint16_t **mt_set, unsigned int *size,
|
||||
unsigned int *index, uint16_t mtid)
|
||||
{
|
||||
for (unsigned int i = 0; i < *index; i++)
|
||||
{
|
||||
if ((*mt_set)[i] == mtid)
|
||||
return;
|
||||
}
|
||||
|
||||
if (*index >= *size)
|
||||
{
|
||||
*mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1));
|
||||
*size = (*index) + 1;
|
||||
}
|
||||
|
||||
(*mt_set)[*index] = mtid;
|
||||
*index = (*index) + 1;
|
||||
}
|
||||
|
||||
static uint16_t *
|
||||
circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
|
||||
unsigned int *mt_count)
|
||||
{
|
||||
static uint16_t *rv;
|
||||
static unsigned int size;
|
||||
struct listnode *node;
|
||||
struct isis_adjacency *adj;
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
if (circuit->circ_type != CIRCUIT_T_BROADCAST)
|
||||
{
|
||||
*mt_count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj))
|
||||
{
|
||||
if (adj->adj_state != ISIS_ADJ_UP)
|
||||
continue;
|
||||
for (unsigned int i = 0; i < adj->mt_count; i++)
|
||||
mt_set_add(&rv, &size, &count, adj->mt_set[i]);
|
||||
}
|
||||
|
||||
*mt_count = count;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
tlvs_add_mt_set(struct isis_area *area,
|
||||
struct tlvs *tlvs, unsigned int mt_count,
|
||||
uint16_t *mt_set, struct te_is_neigh *neigh)
|
||||
{
|
||||
for (unsigned int i = 0; i < mt_count; i++)
|
||||
{
|
||||
uint16_t mtid = mt_set[i];
|
||||
struct te_is_neigh *ne_copy;
|
||||
|
||||
ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
|
||||
memcpy(ne_copy, neigh, sizeof(*ne_copy));
|
||||
|
||||
if (mt_set[i] == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
listnode_add(tlvs->te_is_neighs, ne_copy);
|
||||
lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor",
|
||||
area->area_tag, sysid_print(ne_copy->neigh_id),
|
||||
LSP_PSEUDO_ID(ne_copy->neigh_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
struct tlv_mt_neighbors *neighbors;
|
||||
|
||||
neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
|
||||
neighbors->list->del = free_tlv;
|
||||
listnode_add(neighbors->list, ne_copy);
|
||||
lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
|
||||
area->area_tag, sysid_print(ne_copy->neigh_id),
|
||||
LSP_PSEUDO_ID(ne_copy->neigh_id), isis_mtid2str(mtid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
|
||||
int level, struct te_is_neigh *neigh)
|
||||
{
|
||||
unsigned int mt_count;
|
||||
uint16_t *mt_set = circuit_bcast_mt_set(circuit, level,
|
||||
&mt_count);
|
||||
|
||||
tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh);
|
||||
}
|
||||
|
||||
void
|
||||
tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
|
||||
struct te_is_neigh *neigh)
|
||||
{
|
||||
struct isis_adjacency *adj = circuit->u.p2p.neighbor;
|
||||
|
||||
tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
|
||||
}
|
146
isisd/isis_mt.h
Normal file
146
isisd/isis_mt.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* IS-IS Rout(e)ing protocol - Multi Topology Support
|
||||
*
|
||||
* Copyright (C) 2017 Christian Franke
|
||||
*
|
||||
* This file is part of FreeRangeRouting (FRR)
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
#ifndef ISIS_MT_H
|
||||
#define ISIS_MT_H
|
||||
|
||||
#define ISIS_MT_MASK 0x0fff
|
||||
#define ISIS_MT_OL_MASK 0x8000
|
||||
|
||||
#define ISIS_MT_IPV4_UNICAST 0
|
||||
#define ISIS_MT_IPV4_MGMT 1
|
||||
#define ISIS_MT_IPV6_UNICAST 2
|
||||
#define ISIS_MT_IPV4_MULTICAST 3
|
||||
#define ISIS_MT_IPV6_MULTICAST 4
|
||||
#define ISIS_MT_IPV6_MGMT 5
|
||||
|
||||
#define ISIS_MT_NAMES \
|
||||
"<ipv4-unicast" \
|
||||
"|ipv4-mgmt" \
|
||||
"|ipv6-unicast" \
|
||||
"|ipv4-multicast" \
|
||||
"|ipv6-multicast" \
|
||||
"|ipv6-mgmt" \
|
||||
">"
|
||||
|
||||
#define ISIS_MT_DESCRIPTIONS \
|
||||
"IPv4 unicast topology\n" \
|
||||
"IPv4 management topology\n" \
|
||||
"IPv6 unicast topology\n" \
|
||||
"IPv4 multicast topology\n" \
|
||||
"IPv6 multicast topology\n" \
|
||||
"IPv6 management topology\n"
|
||||
|
||||
#define ISIS_MT_INFO_FIELDS \
|
||||
uint16_t mtid;
|
||||
|
||||
struct list;
|
||||
|
||||
struct isis_area_mt_setting {
|
||||
ISIS_MT_INFO_FIELDS
|
||||
bool enabled;
|
||||
bool overload;
|
||||
};
|
||||
|
||||
struct isis_circuit_mt_setting {
|
||||
ISIS_MT_INFO_FIELDS
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct tlv_mt_neighbors {
|
||||
ISIS_MT_INFO_FIELDS
|
||||
struct list *list;
|
||||
};
|
||||
|
||||
struct tlv_mt_ipv4_reachs {
|
||||
ISIS_MT_INFO_FIELDS
|
||||
struct list *list;
|
||||
};
|
||||
|
||||
struct tlv_mt_ipv6_reachs {
|
||||
ISIS_MT_INFO_FIELDS
|
||||
struct list *list;
|
||||
};
|
||||
|
||||
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 te_is_neigh;
|
||||
|
||||
uint16_t isis_area_ipv6_topology(struct isis_area *area);
|
||||
|
||||
struct mt_router_info* tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid);
|
||||
|
||||
struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
|
||||
struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
|
||||
|
||||
struct tlv_mt_ipv4_reachs* tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid);
|
||||
struct tlv_mt_ipv4_reachs* tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid);
|
||||
|
||||
struct tlv_mt_ipv6_reachs* tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid);
|
||||
struct tlv_mt_ipv6_reachs* tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid);
|
||||
|
||||
struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area,
|
||||
uint16_t mtid);
|
||||
struct isis_area_mt_setting* area_new_mt_setting(struct isis_area *area,
|
||||
uint16_t mtid);
|
||||
void area_add_mt_setting(struct isis_area *area,
|
||||
struct isis_area_mt_setting *setting);
|
||||
|
||||
void area_mt_init(struct isis_area *area);
|
||||
void area_mt_finish(struct isis_area *area);
|
||||
struct isis_area_mt_setting* area_get_mt_setting(struct isis_area *area,
|
||||
uint16_t mtid);
|
||||
int area_write_mt_settings(struct isis_area *area, struct vty *vty);
|
||||
bool area_is_mt(struct isis_area *area);
|
||||
struct isis_area_mt_setting** area_mt_settings(struct isis_area *area,
|
||||
unsigned int *mt_count);
|
||||
|
||||
struct isis_circuit_mt_setting* circuit_lookup_mt_setting(
|
||||
struct isis_circuit *circuit,
|
||||
uint16_t mtid);
|
||||
struct isis_circuit_mt_setting* circuit_new_mt_setting(
|
||||
struct isis_circuit *circuit,
|
||||
uint16_t mtid);
|
||||
void circuit_add_mt_setting(struct isis_circuit *circuit,
|
||||
struct isis_circuit_mt_setting *setting);
|
||||
void circuit_mt_init(struct isis_circuit *circuit);
|
||||
void circuit_mt_finish(struct isis_circuit *circuit);
|
||||
struct isis_circuit_mt_setting* circuit_get_mt_setting(
|
||||
struct isis_circuit *circuit,
|
||||
uint16_t mtid);
|
||||
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);
|
||||
bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid);
|
||||
void adj_mt_finish(struct isis_adjacency *adj);
|
||||
void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
|
||||
int level, struct te_is_neigh *neigh);
|
||||
void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
|
||||
struct te_is_neigh *neigh);
|
||||
#endif
|
@ -53,6 +53,7 @@
|
||||
#include "isisd/isis_csm.h"
|
||||
#include "isisd/isis_events.h"
|
||||
#include "isisd/isis_te.h"
|
||||
#include "isisd/isis_mt.h"
|
||||
|
||||
#define ISIS_MINIMUM_FIXED_HDR_LEN 15
|
||||
#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
|
||||
@ -471,6 +472,7 @@ process_p2p_hello (struct isis_circuit *circuit)
|
||||
expected |= TLVFLAG_NLPID;
|
||||
expected |= TLVFLAG_IPV4_ADDR;
|
||||
expected |= TLVFLAG_IPV6_ADDR;
|
||||
expected |= TLVFLAG_MT_ROUTER_INFORMATION;
|
||||
|
||||
auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
|
||||
retval = parse_tlvs (circuit->area->area_tag,
|
||||
@ -633,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,
|
||||
@ -869,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 */
|
||||
|
||||
@ -1021,6 +1032,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
|
||||
expected |= TLVFLAG_NLPID;
|
||||
expected |= TLVFLAG_IPV4_ADDR;
|
||||
expected |= TLVFLAG_IPV6_ADDR;
|
||||
expected |= TLVFLAG_MT_ROUTER_INFORMATION;
|
||||
|
||||
auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
|
||||
retval = parse_tlvs (circuit->area->area_tag,
|
||||
@ -1223,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,
|
||||
@ -1266,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)
|
||||
{
|
||||
@ -2337,6 +2354,37 @@ send_hello (struct isis_circuit *circuit, int level)
|
||||
if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
|
||||
return ISIS_WARNING;
|
||||
|
||||
/*
|
||||
* MT Supported TLV
|
||||
*
|
||||
* TLV gets included if no topology is enabled on the interface,
|
||||
* if one topology other than #0 is enabled, or if multiple topologies
|
||||
* are enabled.
|
||||
*/
|
||||
struct isis_circuit_mt_setting **mt_settings;
|
||||
unsigned int mt_count;
|
||||
|
||||
mt_settings = circuit_mt_settings(circuit, &mt_count);
|
||||
if ((mt_count == 0 && area_is_mt(circuit->area))
|
||||
|| (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST)
|
||||
|| (mt_count > 1))
|
||||
{
|
||||
struct list *mt_info = list_new();
|
||||
mt_info->del = free_tlv;
|
||||
|
||||
for (unsigned int i = 0; i < mt_count; i++)
|
||||
{
|
||||
struct mt_router_info *info;
|
||||
|
||||
info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
|
||||
info->mtid = mt_settings[i]->mtid;
|
||||
/* overload info is not valid in IIH, so it's not included here */
|
||||
listnode_add(mt_info, info);
|
||||
}
|
||||
tlv_add_mt_router_info (mt_info, circuit->snd_stream);
|
||||
list_free(mt_info);
|
||||
}
|
||||
|
||||
/* IPv6 Interface Address TLV */
|
||||
if (circuit->ipv6_router && circuit->ipv6_link &&
|
||||
listcount (circuit->ipv6_link) > 0)
|
||||
|
@ -371,7 +371,9 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
|
||||
stream_set_getp (circuit->snd_stream, 0);
|
||||
memset (&sa, 0, sizeof (struct sockaddr_ll));
|
||||
sa.sll_family = AF_PACKET;
|
||||
sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
|
||||
|
||||
size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
|
||||
sa.sll_protocol = htons(isis_ethertype(frame_size));
|
||||
sa.sll_ifindex = circuit->interface->ifindex;
|
||||
sa.sll_halen = ETH_ALEN;
|
||||
/* RFC5309 section 4.1 recommends ALL_ISS */
|
||||
@ -418,7 +420,6 @@ isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
|
||||
stream_set_getp (circuit->snd_stream, 0);
|
||||
memset (&sa, 0, sizeof (struct sockaddr_ll));
|
||||
sa.sll_family = AF_PACKET;
|
||||
sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
|
||||
sa.sll_ifindex = circuit->interface->ifindex;
|
||||
sa.sll_halen = ETH_ALEN;
|
||||
if (level == 1)
|
||||
|
720
isisd/isis_spf.c
720
isisd/isis_spf.c
File diff suppressed because it is too large
Load Diff
@ -38,6 +38,10 @@ enum vertextype
|
||||
VTYPE_IP6REACH_EXTERNAL
|
||||
};
|
||||
|
||||
#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
|
||||
#define VTYPE_ES(t) ((t) == VTYPE_ES)
|
||||
#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
|
||||
|
||||
/*
|
||||
* Triple <N, d(N), {Adj(N)}>
|
||||
*/
|
||||
@ -66,12 +70,14 @@ struct isis_spftree
|
||||
unsigned int runcount; /* number of runs since uptime */
|
||||
time_t last_run_timestamp; /* last run timestamp for scheduling */
|
||||
time_t last_run_duration; /* last run duration in msec */
|
||||
|
||||
uint16_t mtid;
|
||||
int family;
|
||||
int level;
|
||||
};
|
||||
|
||||
struct isis_spftree * isis_spftree_new (struct isis_area *area);
|
||||
void isis_spftree_del (struct isis_spftree *spftree);
|
||||
void isis_spftree_adj_del (struct isis_spftree *spftree,
|
||||
struct isis_adjacency *adj);
|
||||
void spftree_area_init (struct isis_area *area);
|
||||
void spftree_area_del (struct isis_area *area);
|
||||
void spftree_area_adj_del (struct isis_area *area,
|
||||
|
685
isisd/isis_tlv.c
685
isisd/isis_tlv.c
@ -43,6 +43,7 @@
|
||||
#include "isisd/isis_pdu.h"
|
||||
#include "isisd/isis_lsp.h"
|
||||
#include "isisd/isis_te.h"
|
||||
#include "isisd/isis_mt.h"
|
||||
|
||||
void
|
||||
free_tlv (void *val)
|
||||
@ -61,10 +62,14 @@ free_tlvs (struct tlvs *tlvs)
|
||||
{
|
||||
if (tlvs->area_addrs)
|
||||
list_delete (tlvs->area_addrs);
|
||||
if (tlvs->mt_router_info)
|
||||
list_delete (tlvs->mt_router_info);
|
||||
if (tlvs->is_neighs)
|
||||
list_delete (tlvs->is_neighs);
|
||||
if (tlvs->te_is_neighs)
|
||||
list_delete (tlvs->te_is_neighs);
|
||||
if (tlvs->mt_is_neighs)
|
||||
list_delete (tlvs->mt_is_neighs);
|
||||
if (tlvs->es_neighs)
|
||||
list_delete (tlvs->es_neighs);
|
||||
if (tlvs->lsp_entries)
|
||||
@ -81,16 +86,293 @@ free_tlvs (struct tlvs *tlvs)
|
||||
list_delete (tlvs->ipv4_ext_reachs);
|
||||
if (tlvs->te_ipv4_reachs)
|
||||
list_delete (tlvs->te_ipv4_reachs);
|
||||
if (tlvs->mt_ipv4_reachs)
|
||||
list_delete (tlvs->mt_ipv4_reachs);
|
||||
if (tlvs->ipv6_addrs)
|
||||
list_delete (tlvs->ipv6_addrs);
|
||||
if (tlvs->ipv6_reachs)
|
||||
list_delete (tlvs->ipv6_reachs);
|
||||
if (tlvs->mt_ipv6_reachs)
|
||||
list_delete (tlvs->mt_ipv6_reachs);
|
||||
|
||||
memset (tlvs, 0, sizeof (struct tlvs));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_mtid(uint16_t *mtid, bool read_mtid,
|
||||
unsigned int *length, u_char **pnt)
|
||||
{
|
||||
if (!read_mtid)
|
||||
{
|
||||
*mtid = ISIS_MT_IPV4_UNICAST;
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
uint16_t mtid_buf;
|
||||
|
||||
if (*length < sizeof(mtid_buf))
|
||||
{
|
||||
zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
memcpy(&mtid_buf, *pnt, sizeof(mtid_buf));
|
||||
*pnt += sizeof(mtid_buf);
|
||||
*length -= sizeof(mtid_buf);
|
||||
|
||||
*mtid = ntohs(mtid_buf) & ISIS_MT_MASK;
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid,
|
||||
unsigned int length, u_char *pnt)
|
||||
{
|
||||
struct list *neigh_list;
|
||||
uint16_t mtid;
|
||||
int rv;
|
||||
|
||||
rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
|
||||
if (rv != ISIS_OK)
|
||||
return rv;
|
||||
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
if (!tlvs->te_is_neighs)
|
||||
{
|
||||
tlvs->te_is_neighs = list_new();
|
||||
tlvs->te_is_neighs->del = free_tlv;
|
||||
}
|
||||
neigh_list = tlvs->te_is_neighs;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct tlv_mt_neighbors *neighbors;
|
||||
|
||||
neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
|
||||
neighbors->list->del = free_tlv;
|
||||
neigh_list = neighbors->list;
|
||||
}
|
||||
|
||||
while (length >= IS_NEIGHBOURS_LEN)
|
||||
{
|
||||
struct te_is_neigh *neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh));
|
||||
|
||||
memcpy(neigh, pnt, IS_NEIGHBOURS_LEN);
|
||||
pnt += IS_NEIGHBOURS_LEN;
|
||||
length -= IS_NEIGHBOURS_LEN;
|
||||
|
||||
if (neigh->sub_tlvs_length > length)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: neighbor subtlv length exceeds TLV size");
|
||||
XFREE(MTYPE_ISIS_TLV, neigh);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length);
|
||||
pnt += neigh->sub_tlvs_length;
|
||||
length -= neigh->sub_tlvs_length;
|
||||
|
||||
listnode_add(neigh_list, neigh);
|
||||
}
|
||||
|
||||
if (length)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid,
|
||||
unsigned int length, u_char *pnt)
|
||||
{
|
||||
struct list *reach_list;
|
||||
uint16_t mtid;
|
||||
int rv;
|
||||
|
||||
rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
|
||||
if (rv != ISIS_OK)
|
||||
return rv;
|
||||
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
if (!tlvs->te_ipv4_reachs)
|
||||
{
|
||||
tlvs->te_ipv4_reachs = list_new();
|
||||
tlvs->te_ipv4_reachs->del = free_tlv;
|
||||
}
|
||||
reach_list = tlvs->te_ipv4_reachs;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct tlv_mt_ipv4_reachs *reachs;
|
||||
|
||||
reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid);
|
||||
reachs->list->del = free_tlv;
|
||||
reach_list = reachs->list;
|
||||
}
|
||||
|
||||
while (length >= 5) /* Metric + Control */
|
||||
{
|
||||
struct te_ipv4_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN);
|
||||
|
||||
memcpy(reach, pnt, 5); /* Metric + Control */
|
||||
pnt += 5;
|
||||
length -= 5;
|
||||
|
||||
unsigned char prefixlen = reach->control & 0x3F;
|
||||
|
||||
if (prefixlen > IPV4_MAX_BITLEN)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix length %d", prefixlen);
|
||||
XFREE(MTYPE_ISIS_TLV, reach);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
if (length < (unsigned int)PSIZE(prefixlen))
|
||||
{
|
||||
zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
|
||||
XFREE(MTYPE_ISIS_TLV, reach);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen));
|
||||
pnt += PSIZE(prefixlen);
|
||||
length -= PSIZE(prefixlen);
|
||||
|
||||
if (reach->control & TE_IPV4_HAS_SUBTLV)
|
||||
{
|
||||
if (length < 1)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
|
||||
XFREE(MTYPE_ISIS_TLV, reach);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
u_char subtlv_len = *pnt;
|
||||
pnt++;
|
||||
length--;
|
||||
|
||||
if (length < subtlv_len)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
|
||||
XFREE(MTYPE_ISIS_TLV, reach);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
/* Skip Sub-TLVs for now */
|
||||
pnt += subtlv_len;
|
||||
length -= subtlv_len;
|
||||
}
|
||||
listnode_add(reach_list, reach);
|
||||
}
|
||||
|
||||
if (length)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid,
|
||||
unsigned int length, u_char *pnt)
|
||||
{
|
||||
struct list *reach_list;
|
||||
uint16_t mtid;
|
||||
int rv;
|
||||
|
||||
rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
|
||||
if (rv != ISIS_OK)
|
||||
return rv;
|
||||
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
if (!tlvs->ipv6_reachs)
|
||||
{
|
||||
tlvs->ipv6_reachs = list_new();
|
||||
tlvs->ipv6_reachs->del = free_tlv;
|
||||
}
|
||||
reach_list = tlvs->ipv6_reachs;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct tlv_mt_ipv6_reachs *reachs;
|
||||
|
||||
reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid);
|
||||
reachs->list->del = free_tlv;
|
||||
reach_list = reachs->list;
|
||||
}
|
||||
|
||||
while (length >= 6) /* Metric + Control + Prefixlen */
|
||||
{
|
||||
struct ipv6_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach));
|
||||
|
||||
memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */
|
||||
pnt += 6;
|
||||
length -= 6;
|
||||
|
||||
if (reach->prefix_len > IPV6_MAX_BITLEN)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix length %d", reach->prefix_len);
|
||||
XFREE(MTYPE_ISIS_TLV, reach);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
if (length < (unsigned int)PSIZE(reach->prefix_len))
|
||||
{
|
||||
zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
|
||||
XFREE(MTYPE_ISIS_TLV, reach);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len));
|
||||
pnt += PSIZE(reach->prefix_len);
|
||||
length -= PSIZE(reach->prefix_len);
|
||||
|
||||
if (reach->control_info & CTRL_INFO_SUBTLVS)
|
||||
{
|
||||
if (length < 1)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLV missing");
|
||||
XFREE(MTYPE_ISIS_TLV, reach);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
u_char subtlv_len = *pnt;
|
||||
pnt++;
|
||||
length--;
|
||||
|
||||
if (length < subtlv_len)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
|
||||
XFREE(MTYPE_ISIS_TLV, reach);
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
/* Skip Sub-TLVs for now */
|
||||
pnt += subtlv_len;
|
||||
length -= subtlv_len;
|
||||
}
|
||||
listnode_add(reach_list, reach);
|
||||
}
|
||||
|
||||
if (length)
|
||||
{
|
||||
zlog_warn("ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
|
||||
return ISIS_WARNING;
|
||||
}
|
||||
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the tlvs found in the variant length part of the PDU.
|
||||
* Caller tells with flags in "expected" which TLV's it is interested in.
|
||||
@ -103,17 +385,13 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
|
||||
struct lan_neigh *lan_nei;
|
||||
struct area_addr *area_addr;
|
||||
struct is_neigh *is_nei;
|
||||
struct te_is_neigh *te_is_nei;
|
||||
struct es_neigh *es_nei;
|
||||
struct lsp_entry *lsp_entry;
|
||||
struct in_addr *ipv4_addr;
|
||||
struct ipv4_reachability *ipv4_reach;
|
||||
struct te_ipv4_reachability *te_ipv4_reach;
|
||||
struct in6_addr *ipv6_addr;
|
||||
struct ipv6_reachability *ipv6_reach;
|
||||
int prefix_octets;
|
||||
int value_len, retval = ISIS_OK;
|
||||
u_char *start = stream, *pnt = stream, *endpnt;
|
||||
u_char *start = stream, *pnt = stream;
|
||||
|
||||
*found = 0;
|
||||
memset (tlvs, 0, sizeof (struct tlvs));
|
||||
@ -207,54 +485,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
|
||||
break;
|
||||
|
||||
case TE_IS_NEIGHBOURS:
|
||||
/* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | Neighbour ID | 7
|
||||
* +---------------------------------------------------------------+
|
||||
* | TE Metric | 3
|
||||
* +---------------------------------------------------------------+
|
||||
* | SubTLVs Length | 1
|
||||
* +---------------------------------------------------------------+
|
||||
* : :
|
||||
*/
|
||||
*found |= TLVFLAG_TE_IS_NEIGHS;
|
||||
#ifdef EXTREME_TLV_DEBUG
|
||||
zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
|
||||
areatag, length);
|
||||
#endif /* EXTREME_TLV_DEBUG */
|
||||
if (TLVFLAG_TE_IS_NEIGHS & *expected)
|
||||
{
|
||||
while (length > value_len)
|
||||
{
|
||||
te_is_nei = (struct te_is_neigh *) pnt;
|
||||
value_len += IS_NEIGHBOURS_LEN;
|
||||
pnt += IS_NEIGHBOURS_LEN;
|
||||
/* FIXME - subtlvs are handled here, for now we skip */
|
||||
/* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
|
||||
/* So, it must be copied in a new te_is_neigh structure */
|
||||
/* rather than just initialize pointer to the original LSP PDU */
|
||||
/* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
|
||||
if (IS_MPLS_TE(isisMplsTE))
|
||||
{
|
||||
struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
|
||||
memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1);
|
||||
memcpy(new->te_metric, te_is_nei->te_metric, 3);
|
||||
new->sub_tlvs_length = te_is_nei->sub_tlvs_length;
|
||||
memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length);
|
||||
te_is_nei = new;
|
||||
}
|
||||
/* Skip SUB TLVs payload */
|
||||
value_len += te_is_nei->sub_tlvs_length;
|
||||
pnt += te_is_nei->sub_tlvs_length;
|
||||
retval = parse_mt_is_neighs(tlvs, false, length, pnt);
|
||||
pnt += length;
|
||||
break;
|
||||
|
||||
if (!tlvs->te_is_neighs)
|
||||
tlvs->te_is_neighs = list_new ();
|
||||
listnode_add (tlvs->te_is_neighs, te_is_nei);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pnt += length;
|
||||
}
|
||||
case MT_IS_NEIGHBOURS:
|
||||
*found |= TLVFLAG_TE_IS_NEIGHS;
|
||||
#ifdef EXTREME_TLV_DEBUG
|
||||
zlog_debug ("ISIS-TLV (%s): MT IS Neighbours length %d",
|
||||
areatag, length);
|
||||
#endif
|
||||
if (TLVFLAG_TE_IS_NEIGHS & *expected)
|
||||
retval = parse_mt_is_neighs(tlvs, true, length, pnt);
|
||||
pnt += length;
|
||||
break;
|
||||
|
||||
case ES_NEIGHBOURS:
|
||||
@ -577,71 +826,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
|
||||
break;
|
||||
|
||||
case TE_IPV4_REACHABILITY:
|
||||
/* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | TE Metric | 4
|
||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | U/D | sTLV? | Prefix Mask Len | 1
|
||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | Prefix | 0-4
|
||||
* +---------------------------------------------------------------+
|
||||
* | sub tlvs |
|
||||
* +---------------------------------------------------------------+
|
||||
* : :
|
||||
*/
|
||||
*found |= TLVFLAG_TE_IPV4_REACHABILITY;
|
||||
#ifdef EXTREME_TLV_DEBUG
|
||||
zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
|
||||
areatag, length);
|
||||
areatag, length);
|
||||
#endif /* EXTREME_TLV_DEBUG */
|
||||
endpnt = pnt + length;
|
||||
if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
|
||||
{
|
||||
while (length > value_len)
|
||||
{
|
||||
te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
|
||||
if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
|
||||
{
|
||||
zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
|
||||
"ability prefix length %d", areatag,
|
||||
te_ipv4_reach->control & 0x3F);
|
||||
retval = ISIS_WARNING;
|
||||
break;
|
||||
}
|
||||
if (!tlvs->te_ipv4_reachs)
|
||||
tlvs->te_ipv4_reachs = list_new ();
|
||||
listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
|
||||
|
||||
/* Metric + Control-Byte + Prefix */
|
||||
unsigned int entry_len = 5 + PSIZE(te_ipv4_reach->control & 0x3F);
|
||||
value_len += entry_len;
|
||||
pnt += entry_len;
|
||||
|
||||
if (te_ipv4_reach->control & TE_IPV4_HAS_SUBTLV)
|
||||
{
|
||||
if (length <= value_len)
|
||||
{
|
||||
zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLV missing",
|
||||
areatag);
|
||||
retval = ISIS_WARNING;
|
||||
break;
|
||||
}
|
||||
u_char subtlv_len = *pnt;
|
||||
value_len += subtlv_len + 1;
|
||||
pnt += subtlv_len + 1;
|
||||
if (length < value_len)
|
||||
{
|
||||
zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLVs have oversize",
|
||||
areatag);
|
||||
retval = ISIS_WARNING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pnt = endpnt;
|
||||
retval = parse_mt_ipv4_reachs(tlvs, false, length, pnt);
|
||||
pnt += length;
|
||||
break;
|
||||
case MT_IPV4_REACHABILITY:
|
||||
*found |= TLVFLAG_TE_IPV4_REACHABILITY;
|
||||
#ifdef EXTREME_TLV_DEBUG
|
||||
zlog_debug ("ISIS-TLV (%s): IPv4 MT Reachability length %d",
|
||||
areatag, length);
|
||||
#endif /* EXTREME_TLV_DEBUG */
|
||||
if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
|
||||
retval = parse_mt_ipv4_reachs(tlvs, true, length, pnt);
|
||||
pnt += length;
|
||||
break;
|
||||
|
||||
case IPV6_ADDR:
|
||||
/* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* + IP version 6 address + 16
|
||||
@ -672,67 +875,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
|
||||
break;
|
||||
|
||||
case IPV6_REACHABILITY:
|
||||
/* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | Default Metric | 4
|
||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | Control Informantion |
|
||||
* +---------------------------------------------------------------+
|
||||
* | IPv6 Prefix Length |--+
|
||||
* +---------------------------------------------------------------+ |
|
||||
* | IPv6 Prefix |<-+
|
||||
* +---------------------------------------------------------------+
|
||||
*/
|
||||
*found |= TLVFLAG_IPV6_REACHABILITY;
|
||||
endpnt = pnt + length;
|
||||
|
||||
#ifdef EXTREME_TLV_DEBUG
|
||||
zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d",
|
||||
areatag, length);
|
||||
#endif /* EXTREME_TLV_DEBUG */
|
||||
if (*expected & TLVFLAG_IPV6_REACHABILITY)
|
||||
{
|
||||
while (length > value_len)
|
||||
{
|
||||
ipv6_reach = (struct ipv6_reachability *) pnt;
|
||||
if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
|
||||
{
|
||||
zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
|
||||
"ability prefix length %d", areatag,
|
||||
ipv6_reach->prefix_len);
|
||||
retval = ISIS_WARNING;
|
||||
break;
|
||||
}
|
||||
|
||||
prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
|
||||
value_len += prefix_octets + 6;
|
||||
pnt += prefix_octets + 6;
|
||||
|
||||
if (ipv6_reach->control_info & CTRL_INFO_SUBTLVS)
|
||||
{
|
||||
if (length <= value_len)
|
||||
{
|
||||
zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLV missing",
|
||||
areatag);
|
||||
retval = ISIS_WARNING;
|
||||
break;
|
||||
}
|
||||
u_char subtlv_len = *pnt;
|
||||
value_len += subtlv_len + 1;
|
||||
pnt += subtlv_len + 1;
|
||||
if (length < value_len)
|
||||
{
|
||||
zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLVs have oversize",
|
||||
areatag);
|
||||
retval = ISIS_WARNING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* FIXME: sub-tlvs */
|
||||
if (!tlvs->ipv6_reachs)
|
||||
tlvs->ipv6_reachs = list_new ();
|
||||
listnode_add (tlvs->ipv6_reachs, ipv6_reach);
|
||||
}
|
||||
}
|
||||
|
||||
pnt = endpnt;
|
||||
retval = parse_mt_ipv6_reachs(tlvs, false, length, pnt);
|
||||
pnt += length;
|
||||
break;
|
||||
case MT_IPV6_REACHABILITY:
|
||||
*found |= TLVFLAG_IPV6_REACHABILITY;
|
||||
#ifdef EXTREME_TLV_DEBUG
|
||||
zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d",
|
||||
areatag, length);
|
||||
#endif /* EXTREME_TLV_DEBUG */
|
||||
if (*expected & TLVFLAG_IPV6_REACHABILITY)
|
||||
retval = parse_mt_ipv6_reachs(tlvs, true, length, pnt);
|
||||
pnt += length;
|
||||
break;
|
||||
|
||||
case WAY3_HELLO:
|
||||
/* +---------------------------------------------------------------+
|
||||
* | Adjacency state | 1
|
||||
@ -786,6 +947,42 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
|
||||
pnt += length;
|
||||
break;
|
||||
|
||||
case MT_ROUTER_INFORMATION:
|
||||
*found |= TLVFLAG_MT_ROUTER_INFORMATION;
|
||||
if (*expected & TLVFLAG_MT_ROUTER_INFORMATION)
|
||||
{
|
||||
if (!tlvs->mt_router_info)
|
||||
{
|
||||
tlvs->mt_router_info = list_new();
|
||||
tlvs->mt_router_info->del = free_tlv;
|
||||
}
|
||||
while (length > value_len)
|
||||
{
|
||||
uint16_t mt_info;
|
||||
struct mt_router_info *info;
|
||||
|
||||
if (value_len + sizeof(mt_info) > length) {
|
||||
zlog_warn("ISIS-TLV (%s): TLV 229 is truncated.", areatag);
|
||||
pnt += length - value_len;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(&mt_info, pnt, sizeof(mt_info));
|
||||
pnt += sizeof(mt_info);
|
||||
value_len += sizeof(mt_info);
|
||||
|
||||
mt_info = ntohs(mt_info);
|
||||
info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
|
||||
info->mtid = mt_info & ISIS_MT_MASK;
|
||||
info->overload = mt_info & ISIS_MT_OL_MASK;
|
||||
listnode_add(tlvs->mt_router_info, info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pnt += length;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
|
||||
areatag, type, length);
|
||||
@ -825,6 +1022,31 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
|
||||
return ISIS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct mt_router_info *info;
|
||||
|
||||
uint16_t value[127];
|
||||
uint16_t *pos = value;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info))
|
||||
{
|
||||
uint16_t mt_info;
|
||||
|
||||
mt_info = info->mtid;
|
||||
if (info->overload)
|
||||
mt_info |= ISIS_MT_OL_MASK;
|
||||
|
||||
*pos = htons(mt_info);
|
||||
pos++;
|
||||
}
|
||||
|
||||
return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
|
||||
(u_char*)value, stream);
|
||||
}
|
||||
|
||||
int
|
||||
tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
|
||||
{
|
||||
@ -887,26 +1109,44 @@ tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
|
||||
return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
|
||||
}
|
||||
|
||||
int
|
||||
tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
|
||||
static size_t
|
||||
max_tlv_size(struct stream *stream)
|
||||
{
|
||||
size_t avail = stream_get_size (stream) - stream_get_endp(stream);
|
||||
|
||||
if (avail < 2)
|
||||
return 0;
|
||||
|
||||
if (avail < 257)
|
||||
return avail - 2;
|
||||
|
||||
return 255;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct te_is_neigh *te_is_neigh;
|
||||
u_char value[255];
|
||||
u_char *pos = value;
|
||||
int retval;
|
||||
uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
|
||||
unsigned int consumed = 0;
|
||||
size_t max_size = max_tlv_size(stream);
|
||||
|
||||
if (mtid != ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
uint16_t mtid_conversion = ntohs(mtid);
|
||||
memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
|
||||
pos += sizeof(mtid_conversion);
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
|
||||
{
|
||||
/* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
|
||||
if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255)
|
||||
{
|
||||
retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
|
||||
if (retval != ISIS_OK)
|
||||
return retval;
|
||||
pos = value;
|
||||
}
|
||||
|
||||
if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > max_size)
|
||||
break;
|
||||
|
||||
memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
|
||||
pos += ISIS_SYS_ID_LEN + 1;
|
||||
memcpy (pos, te_is_neigh->te_metric, 3);
|
||||
@ -920,9 +1160,17 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
|
||||
memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length);
|
||||
pos += te_is_neigh->sub_tlvs_length;
|
||||
}
|
||||
consumed++;
|
||||
}
|
||||
|
||||
return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
|
||||
if (consumed)
|
||||
{
|
||||
int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IS_NEIGHBOURS
|
||||
: TE_IS_NEIGHBOURS,
|
||||
pos - value, value, stream);
|
||||
assert(rv == ISIS_OK);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
int
|
||||
@ -1100,37 +1348,49 @@ tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
|
||||
unsigned int
|
||||
tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct te_ipv4_reachability *te_reach;
|
||||
u_char value[255];
|
||||
u_char *pos = value;
|
||||
u_char prefix_size;
|
||||
int retval;
|
||||
uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
|
||||
unsigned int consumed = 0;
|
||||
size_t max_size = max_tlv_size(stream);
|
||||
|
||||
if (mtid != ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
uint16_t mtid_conversion = ntohs(mtid);
|
||||
memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
|
||||
pos += sizeof(mtid_conversion);
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
|
||||
{
|
||||
prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
|
||||
unsigned char prefixlen = te_reach->control & 0x3F;
|
||||
|
||||
if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size)
|
||||
break;
|
||||
|
||||
if (pos - value + (5 + prefix_size) > 255)
|
||||
{
|
||||
retval =
|
||||
add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
|
||||
if (retval != ISIS_OK)
|
||||
return retval;
|
||||
pos = value;
|
||||
}
|
||||
*(u_int32_t *) pos = te_reach->te_metric;
|
||||
pos += 4;
|
||||
*pos = te_reach->control;
|
||||
pos++;
|
||||
memcpy (pos, &te_reach->prefix_start, prefix_size);
|
||||
pos += prefix_size;
|
||||
memcpy (pos, &te_reach->prefix_start, PSIZE(prefixlen));
|
||||
pos += PSIZE(prefixlen);
|
||||
consumed++;
|
||||
}
|
||||
|
||||
return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
|
||||
if (consumed)
|
||||
{
|
||||
int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV4_REACHABILITY
|
||||
: TE_IPV4_REACHABILITY,
|
||||
pos - value, value, stream);
|
||||
assert(rv == ISIS_OK);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
int
|
||||
@ -1158,36 +1418,49 @@ tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
|
||||
return add_tlv (IPV6_ADDR, pos - value, value, stream);
|
||||
}
|
||||
|
||||
int
|
||||
tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
|
||||
unsigned int
|
||||
tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct ipv6_reachability *ip6reach;
|
||||
u_char value[255];
|
||||
u_char *pos = value;
|
||||
int retval, prefix_octets;
|
||||
uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
|
||||
unsigned int consumed = 0;
|
||||
size_t max_size = max_tlv_size(stream);
|
||||
|
||||
if (mtid != ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
uint16_t mtid_conversion = ntohs(mtid);
|
||||
memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
|
||||
pos += sizeof(mtid_conversion);
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
|
||||
{
|
||||
if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
|
||||
{
|
||||
retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
|
||||
if (retval != ISIS_OK)
|
||||
return retval;
|
||||
pos = value;
|
||||
}
|
||||
*(uint32_t *) pos = ip6reach->metric;
|
||||
if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len) > max_size)
|
||||
break;
|
||||
|
||||
*(uint32_t *)pos = ip6reach->metric;
|
||||
pos += 4;
|
||||
*pos = ip6reach->control_info;
|
||||
pos++;
|
||||
prefix_octets = ((ip6reach->prefix_len + 7) / 8);
|
||||
*pos = ip6reach->prefix_len;
|
||||
pos++;
|
||||
memcpy (pos, ip6reach->prefix, prefix_octets);
|
||||
pos += prefix_octets;
|
||||
memcpy (pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len));
|
||||
pos += PSIZE(ip6reach->prefix_len);
|
||||
consumed++;
|
||||
}
|
||||
|
||||
return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
|
||||
if (consumed)
|
||||
{
|
||||
int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV6_REACHABILITY
|
||||
: IPV6_REACHABILITY,
|
||||
pos - value, value, stream);
|
||||
assert(rv == ISIS_OK);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -24,6 +24,8 @@
|
||||
#ifndef _ZEBRA_ISIS_TLV_H
|
||||
#define _ZEBRA_ISIS_TLV_H
|
||||
|
||||
#include "isisd/isis_mt.h"
|
||||
|
||||
/*
|
||||
* The list of TLVs we (should) support.
|
||||
* ____________________________________________________________________________
|
||||
@ -109,8 +111,12 @@
|
||||
#define TE_IPV4_REACHABILITY 135
|
||||
#define DYNAMIC_HOSTNAME 137
|
||||
#define GRACEFUL_RESTART 211
|
||||
#define MT_IS_NEIGHBOURS 222
|
||||
#define MT_ROUTER_INFORMATION 229
|
||||
#define IPV6_ADDR 232
|
||||
#define MT_IPV4_REACHABILITY 235
|
||||
#define IPV6_REACHABILITY 236
|
||||
#define MT_IPV6_REACHABILITY 237
|
||||
#define WAY3_HELLO 240
|
||||
#define ROUTER_INFORMATION 242
|
||||
|
||||
@ -250,6 +256,12 @@ struct ipv6_reachability
|
||||
|
||||
#define CTRL_INFO_SUBTLVS 0x20
|
||||
|
||||
struct mt_router_info
|
||||
{
|
||||
ISIS_MT_INFO_FIELDS
|
||||
bool overload;
|
||||
};
|
||||
|
||||
/*
|
||||
* Pointer to each tlv type, filled by parse_tlvs()
|
||||
*/
|
||||
@ -260,8 +272,10 @@ struct tlvs
|
||||
struct nlpids *nlpids;
|
||||
struct te_router_id *router_id;
|
||||
struct list *area_addrs;
|
||||
struct list *mt_router_info;
|
||||
struct list *is_neighs;
|
||||
struct list *te_is_neighs;
|
||||
struct list *mt_is_neighs;
|
||||
struct list *es_neighs;
|
||||
struct list *lsp_entries;
|
||||
struct list *prefix_neighs;
|
||||
@ -270,8 +284,10 @@ struct tlvs
|
||||
struct list *ipv4_int_reachs;
|
||||
struct list *ipv4_ext_reachs;
|
||||
struct list *te_ipv4_reachs;
|
||||
struct list *mt_ipv4_reachs;
|
||||
struct list *ipv6_addrs;
|
||||
struct list *ipv6_reachs;
|
||||
struct list *mt_ipv6_reachs;
|
||||
struct isis_passwd auth_info;
|
||||
};
|
||||
|
||||
@ -301,6 +317,7 @@ struct tlvs
|
||||
#define TLVFLAG_TE_ROUTER_ID (1<<19)
|
||||
#define TLVFLAG_CHECKSUM (1<<20)
|
||||
#define TLVFLAG_GRACEFUL_RESTART (1<<21)
|
||||
#define TLVFLAG_MT_ROUTER_INFORMATION (1<<22)
|
||||
|
||||
void init_tlvs (struct tlvs *tlvs, uint32_t expected);
|
||||
void free_tlvs (struct tlvs *tlvs);
|
||||
@ -310,9 +327,10 @@ int parse_tlvs (char *areatag, u_char * stream, int size,
|
||||
int add_tlv (u_char, u_char, u_char *, struct stream *);
|
||||
void free_tlv (void *val);
|
||||
|
||||
int tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream);
|
||||
int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
|
||||
int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream);
|
||||
int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream);
|
||||
unsigned int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg);
|
||||
int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream);
|
||||
int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream);
|
||||
int tlv_add_checksum (struct checksum *checksum, struct stream *stream);
|
||||
@ -325,9 +343,9 @@ int tlv_add_dynamic_hostname (struct hostname *hostname,
|
||||
int tlv_add_lsp_entries (struct list *lsps, struct stream *stream);
|
||||
int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream);
|
||||
int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream);
|
||||
int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream);
|
||||
unsigned int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg);
|
||||
int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream);
|
||||
int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream);
|
||||
unsigned int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg);
|
||||
|
||||
int tlv_add_padding (struct stream *stream);
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "isis_circuit.h"
|
||||
#include "isis_csm.h"
|
||||
#include "isis_misc.h"
|
||||
#include "isis_mt.h"
|
||||
#include "isisd.h"
|
||||
|
||||
static struct isis_circuit *
|
||||
@ -1271,6 +1272,48 @@ DEFUN (no_psnp_interval_l2,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (circuit_topology,
|
||||
circuit_topology_cmd,
|
||||
"isis topology " ISIS_MT_NAMES,
|
||||
"IS-IS commands\n"
|
||||
"Configure interface IS-IS topologies\n"
|
||||
ISIS_MT_DESCRIPTIONS)
|
||||
{
|
||||
struct isis_circuit *circuit = isis_circuit_lookup (vty);
|
||||
if (!circuit)
|
||||
return CMD_ERR_NO_MATCH;
|
||||
const char *arg = argv[2]->arg;
|
||||
uint16_t mtid = isis_str2mtid(arg);
|
||||
if (mtid == (uint16_t)-1)
|
||||
{
|
||||
vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
|
||||
return CMD_ERR_AMBIGUOUS;
|
||||
}
|
||||
|
||||
return isis_circuit_mt_enabled_set(circuit, mtid, true);
|
||||
}
|
||||
|
||||
DEFUN (no_circuit_topology,
|
||||
no_circuit_topology_cmd,
|
||||
"no isis topology " ISIS_MT_NAMES,
|
||||
NO_STR
|
||||
"IS-IS commands\n"
|
||||
"Configure interface IS-IS topologies\n"
|
||||
ISIS_MT_DESCRIPTIONS)
|
||||
{
|
||||
struct isis_circuit *circuit = isis_circuit_lookup (vty);
|
||||
if (!circuit)
|
||||
return CMD_ERR_NO_MATCH;
|
||||
const char *arg = argv[3]->arg;
|
||||
uint16_t mtid = isis_str2mtid(arg);
|
||||
if (mtid == (uint16_t)-1)
|
||||
{
|
||||
vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
|
||||
return CMD_ERR_AMBIGUOUS;
|
||||
}
|
||||
|
||||
return isis_circuit_mt_enabled_set(circuit, mtid, false);
|
||||
}
|
||||
|
||||
static int
|
||||
validate_metric_style_narrow (struct vty *vty, struct isis_area *area)
|
||||
@ -2116,6 +2159,9 @@ isis_vty_init (void)
|
||||
install_element (INTERFACE_NODE, &psnp_interval_l2_cmd);
|
||||
install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd);
|
||||
|
||||
install_element (INTERFACE_NODE, &circuit_topology_cmd);
|
||||
install_element (INTERFACE_NODE, &no_circuit_topology_cmd);
|
||||
|
||||
install_element (ISIS_NODE, &metric_style_cmd);
|
||||
install_element (ISIS_NODE, &no_metric_style_cmd);
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "isisd/isis_zebra.h"
|
||||
#include "isisd/isis_events.h"
|
||||
#include "isisd/isis_te.h"
|
||||
#include "isisd/isis_mt.h"
|
||||
|
||||
struct isis *isis = NULL;
|
||||
|
||||
@ -156,6 +157,8 @@ isis_area_create (const char *area_tag)
|
||||
area->lsp_frag_threshold = 90;
|
||||
area->lsp_mtu = DEFAULT_LSP_MTU;
|
||||
|
||||
area_mt_init(area);
|
||||
|
||||
area->area_tag = strdup (area_tag);
|
||||
listnode_add (isis->area_list, area);
|
||||
area->isis = isis;
|
||||
@ -296,6 +299,8 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
|
||||
|
||||
free (area->area_tag);
|
||||
|
||||
area_mt_finish(area);
|
||||
|
||||
XFREE (MTYPE_ISIS_AREA, area);
|
||||
|
||||
if (listcount (isis->area_list) == 0)
|
||||
@ -307,6 +312,33 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
area_set_mt_enabled(struct isis_area *area, uint16_t mtid, bool enabled)
|
||||
{
|
||||
struct isis_area_mt_setting *setting;
|
||||
|
||||
setting = area_get_mt_setting(area, mtid);
|
||||
if (setting->enabled != enabled)
|
||||
{
|
||||
setting->enabled = enabled;
|
||||
lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
area_set_mt_overload(struct isis_area *area, uint16_t mtid, bool overload)
|
||||
{
|
||||
struct isis_area_mt_setting *setting;
|
||||
|
||||
setting = area_get_mt_setting(area, mtid);
|
||||
if (setting->overload != overload)
|
||||
{
|
||||
setting->overload = overload;
|
||||
if (setting->enabled)
|
||||
lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
area_net_title (struct vty *vty, const char *net_title)
|
||||
{
|
||||
@ -1626,6 +1658,61 @@ DEFUN (no_net,
|
||||
return area_clear_net_title (vty, argv[idx_word]->arg);
|
||||
}
|
||||
|
||||
DEFUN (isis_topology,
|
||||
isis_topology_cmd,
|
||||
"topology " ISIS_MT_NAMES " [overload]",
|
||||
"Configure IS-IS topologies\n"
|
||||
ISIS_MT_DESCRIPTIONS
|
||||
"Set overload bit for topology\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT (isis_area, area);
|
||||
|
||||
const char *arg = argv[1]->arg;
|
||||
uint16_t mtid = isis_str2mtid(arg);
|
||||
if (mtid == (uint16_t)-1)
|
||||
{
|
||||
vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
|
||||
return CMD_ERR_AMBIGUOUS;
|
||||
}
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE);
|
||||
return CMD_ERR_AMBIGUOUS;
|
||||
}
|
||||
|
||||
area_set_mt_enabled(area, mtid, true);
|
||||
area_set_mt_overload(area, mtid, (argc == 3));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_isis_topology,
|
||||
no_isis_topology_cmd,
|
||||
"no topology " ISIS_MT_NAMES " [overload]",
|
||||
NO_STR
|
||||
"Configure IS-IS topologies\n"
|
||||
ISIS_MT_DESCRIPTIONS
|
||||
"Set overload bit for topology\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT (isis_area, area);
|
||||
|
||||
const char *arg = argv[2]->arg;
|
||||
uint16_t mtid = isis_str2mtid(arg);
|
||||
if (mtid == (uint16_t)-1)
|
||||
{
|
||||
vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
|
||||
return CMD_ERR_AMBIGUOUS;
|
||||
}
|
||||
if (mtid == ISIS_MT_IPV4_UNICAST)
|
||||
{
|
||||
vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE);
|
||||
return CMD_ERR_AMBIGUOUS;
|
||||
}
|
||||
|
||||
area_set_mt_enabled(area, mtid, false);
|
||||
area_set_mt_overload(area, mtid, false);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu)
|
||||
{
|
||||
area->lsp_mtu = lsp_mtu;
|
||||
@ -2148,6 +2235,7 @@ isis_config_write (struct vty *vty)
|
||||
write++;
|
||||
}
|
||||
|
||||
write += area_write_mt_settings(area, vty);
|
||||
}
|
||||
isis_mpls_te_config_write_router(vty);
|
||||
}
|
||||
@ -2254,6 +2342,9 @@ isis_init ()
|
||||
install_element (ISIS_NODE, &net_cmd);
|
||||
install_element (ISIS_NODE, &no_net_cmd);
|
||||
|
||||
install_element (ISIS_NODE, &isis_topology_cmd);
|
||||
install_element (ISIS_NODE, &no_isis_topology_cmd);
|
||||
|
||||
install_element (ISIS_NODE, &log_adj_changes_cmd);
|
||||
install_element (ISIS_NODE, &no_log_adj_changes_cmd);
|
||||
|
||||
|
@ -120,6 +120,8 @@ struct isis_area
|
||||
int ip_circuits;
|
||||
/* logging adjacency changes? */
|
||||
u_char log_adj_changes;
|
||||
/* multi topology settings */
|
||||
struct list *mt_settings;
|
||||
int ipv6_circuits;
|
||||
/* Counters */
|
||||
u_int32_t circuit_state_changes;
|
||||
|
Loading…
Reference in New Issue
Block a user