Vastly improved OSPF reconfiguration.
Now it can handle a change in iface pattern structure. It can add, remove and reconfigure interfaces, vlinks and areas.
This commit is contained in:
parent
93e868c730
commit
8e48831a97
12 changed files with 695 additions and 533 deletions
|
@ -22,8 +22,13 @@ static struct ospf_stubnet_config *this_stubnet;
|
||||||
|
|
||||||
#ifdef OSPFv2
|
#ifdef OSPFv2
|
||||||
static void
|
static void
|
||||||
finish_iface_config(struct ospf_iface_patt *ip)
|
ospf_iface_finish(void)
|
||||||
{
|
{
|
||||||
|
struct ospf_iface_patt *ip = OSPF_PATT;
|
||||||
|
|
||||||
|
if (ip->deadint == 0)
|
||||||
|
ip->deadint = ip->deadc * ip->helloint;
|
||||||
|
|
||||||
ip->passwords = get_passwords();
|
ip->passwords = get_passwords();
|
||||||
|
|
||||||
if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
|
if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
|
||||||
|
@ -36,13 +41,57 @@ finish_iface_config(struct ospf_iface_patt *ip)
|
||||||
|
|
||||||
#ifdef OSPFv3
|
#ifdef OSPFv3
|
||||||
static void
|
static void
|
||||||
finish_iface_config(struct ospf_iface_patt *ip)
|
ospf_iface_finish(void)
|
||||||
{
|
{
|
||||||
|
struct ospf_iface_patt *ip = OSPF_PATT;
|
||||||
|
|
||||||
|
if (ip->deadint == 0)
|
||||||
|
ip->deadint = ip->deadc * ip->helloint;
|
||||||
|
|
||||||
if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
|
if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
|
||||||
cf_error("Authentication not supported in OSPFv3");
|
cf_error("Authentication not supported in OSPFv3");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
ospf_area_finish(void)
|
||||||
|
{
|
||||||
|
if ((this_area->areaid == 0) && (this_area->stub != 0))
|
||||||
|
cf_error( "Backbone area cannot be stub");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ospf_proto_finish(void)
|
||||||
|
{
|
||||||
|
struct ospf_config *cf = OSPF_CFG;
|
||||||
|
|
||||||
|
if (EMPTY_LIST(cf->area_list))
|
||||||
|
cf_error( "No configured areas in OSPF");
|
||||||
|
|
||||||
|
int areano = 0;
|
||||||
|
int backbone = 0;
|
||||||
|
struct ospf_area_config *ac;
|
||||||
|
WALK_LIST(ac, cf->area_list)
|
||||||
|
{
|
||||||
|
areano++;
|
||||||
|
if (ac->areaid == 0)
|
||||||
|
backbone = 1;
|
||||||
|
}
|
||||||
|
cf->abr = areano > 1;
|
||||||
|
|
||||||
|
if (cf->abr && !backbone)
|
||||||
|
{
|
||||||
|
struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config));
|
||||||
|
add_head(&cf->area_list, NODE ac);
|
||||||
|
init_list(&ac->patt_list);
|
||||||
|
init_list(&ac->net_list);
|
||||||
|
init_list(&ac->stubnet_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
|
||||||
|
cf_error( "No configured areas in OSPF");
|
||||||
|
}
|
||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
|
CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
|
||||||
|
@ -58,12 +107,13 @@ CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT)
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
CF_ADDTO(proto, ospf_proto '}')
|
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
|
||||||
|
|
||||||
ospf_proto_start: proto_start OSPF {
|
ospf_proto_start: proto_start OSPF {
|
||||||
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config));
|
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config));
|
||||||
this_proto->preference = DEF_PREF_OSPF;
|
this_proto->preference = DEF_PREF_OSPF;
|
||||||
init_list(&OSPF_CFG->area_list);
|
init_list(&OSPF_CFG->area_list);
|
||||||
|
init_list(&OSPF_CFG->vlink_list);
|
||||||
OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
|
OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
|
||||||
OSPF_CFG->tick = DEFAULT_OSPFTICK;
|
OSPF_CFG->tick = DEFAULT_OSPFTICK;
|
||||||
}
|
}
|
||||||
|
@ -80,22 +130,21 @@ ospf_proto_item:
|
||||||
| ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; }
|
| ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; }
|
||||||
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
|
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
|
||||||
| TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
|
| TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
|
||||||
| ospf_area '}'
|
| ospf_area
|
||||||
;
|
;
|
||||||
|
|
||||||
ospf_area_start: AREA idval '{' {
|
ospf_area_start: AREA idval {
|
||||||
this_area = cfg_allocz(sizeof(struct ospf_area_config));
|
this_area = cfg_allocz(sizeof(struct ospf_area_config));
|
||||||
add_tail(&OSPF_CFG->area_list, NODE this_area);
|
add_tail(&OSPF_CFG->area_list, NODE this_area);
|
||||||
this_area->areaid = $2;
|
this_area->areaid = $2;
|
||||||
this_area->stub = 0;
|
this_area->stub = 0;
|
||||||
init_list(&this_area->patt_list);
|
init_list(&this_area->patt_list);
|
||||||
init_list(&this_area->vlink_list);
|
|
||||||
init_list(&this_area->net_list);
|
init_list(&this_area->net_list);
|
||||||
init_list(&this_area->stubnet_list);
|
init_list(&this_area->stubnet_list);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
ospf_area: ospf_area_start ospf_area_opts
|
ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
ospf_area_opts:
|
ospf_area_opts:
|
||||||
|
@ -138,7 +187,7 @@ ospf_stubnet_item:
|
||||||
;
|
;
|
||||||
|
|
||||||
ospf_vlink:
|
ospf_vlink:
|
||||||
ospf_vlink_start '{' ospf_vlink_opts '}' { finish_iface_config(OSPF_PATT); }
|
ospf_vlink_start '{' ospf_vlink_opts '}' { ospf_iface_finish(); }
|
||||||
| ospf_vlink_start
|
| ospf_vlink_start
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -152,7 +201,7 @@ ospf_vlink_item:
|
||||||
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
|
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
|
||||||
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
|
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
|
||||||
| WAIT expr { OSPF_PATT->waitint = $2 ; }
|
| WAIT expr { OSPF_PATT->waitint = $2 ; }
|
||||||
| DEAD expr { OSPF_PATT->dead = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
|
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
|
||||||
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
||||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
|
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
|
||||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
|
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
|
||||||
|
@ -164,15 +213,16 @@ ospf_vlink_start: VIRTUAL LINK idval
|
||||||
{
|
{
|
||||||
if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone");
|
if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone");
|
||||||
this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
|
this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
|
||||||
add_tail(&this_area->vlink_list, NODE this_ipatt);
|
add_tail(&OSPF_CFG->vlink_list, NODE this_ipatt);
|
||||||
init_list(&this_ipatt->ipn_list);
|
init_list(&this_ipatt->ipn_list);
|
||||||
|
OSPF_PATT->voa = this_area->areaid;
|
||||||
OSPF_PATT->vid = $3;
|
OSPF_PATT->vid = $3;
|
||||||
OSPF_PATT->helloint = HELLOINT_D;
|
OSPF_PATT->helloint = HELLOINT_D;
|
||||||
OSPF_PATT->rxmtint = RXMTINT_D;
|
OSPF_PATT->rxmtint = RXMTINT_D;
|
||||||
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
|
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
|
||||||
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
|
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
|
||||||
OSPF_PATT->deadc = DEADC_D;
|
OSPF_PATT->deadc = DEADC_D;
|
||||||
OSPF_PATT->dead = 0;
|
OSPF_PATT->deadint = 0;
|
||||||
OSPF_PATT->type = OSPF_IT_VLINK;
|
OSPF_PATT->type = OSPF_IT_VLINK;
|
||||||
init_list(&OSPF_PATT->nbma_list);
|
init_list(&OSPF_PATT->nbma_list);
|
||||||
OSPF_PATT->autype = OSPF_AUTH_NONE;
|
OSPF_PATT->autype = OSPF_AUTH_NONE;
|
||||||
|
@ -185,10 +235,8 @@ ospf_iface_item:
|
||||||
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
|
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
|
||||||
| POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); }
|
| POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); }
|
||||||
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
|
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
|
||||||
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
|
|
||||||
| PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); }
|
|
||||||
| WAIT expr { OSPF_PATT->waitint = $2 ; }
|
| WAIT expr { OSPF_PATT->waitint = $2 ; }
|
||||||
| DEAD expr { OSPF_PATT->dead = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
|
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
|
||||||
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
||||||
| TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
|
| TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
|
||||||
| TYPE BCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
|
| TYPE BCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
|
||||||
|
@ -198,6 +246,8 @@ ospf_iface_item:
|
||||||
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
|
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
|
||||||
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
|
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
|
||||||
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
|
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
|
||||||
|
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
|
||||||
|
| PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); }
|
||||||
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
|
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
|
||||||
| STUB bool { OSPF_PATT->stub = $2 ; }
|
| STUB bool { OSPF_PATT->stub = $2 ; }
|
||||||
| CHECK LINK bool { OSPF_PATT->check_link = $3; }
|
| CHECK LINK bool { OSPF_PATT->check_link = $3; }
|
||||||
|
@ -281,7 +331,7 @@ ospf_iface_start:
|
||||||
OSPF_PATT->priority = PRIORITY_D;
|
OSPF_PATT->priority = PRIORITY_D;
|
||||||
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
|
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
|
||||||
OSPF_PATT->deadc = DEADC_D;
|
OSPF_PATT->deadc = DEADC_D;
|
||||||
OSPF_PATT->dead = 0;
|
OSPF_PATT->deadint = 0;
|
||||||
OSPF_PATT->type = OSPF_IT_UNDEF;
|
OSPF_PATT->type = OSPF_IT_UNDEF;
|
||||||
init_list(&OSPF_PATT->nbma_list);
|
init_list(&OSPF_PATT->nbma_list);
|
||||||
OSPF_PATT->autype = OSPF_AUTH_NONE;
|
OSPF_PATT->autype = OSPF_AUTH_NONE;
|
||||||
|
@ -300,7 +350,7 @@ ospf_iface_opt_list:
|
||||||
;
|
;
|
||||||
|
|
||||||
ospf_iface:
|
ospf_iface:
|
||||||
ospf_iface_start iface_patt_list ospf_iface_opt_list { finish_iface_config(OSPF_PATT); }
|
ospf_iface_start iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
opttext:
|
opttext:
|
||||||
|
|
|
@ -88,7 +88,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||||
#else /* OSPFv3 */
|
#else /* OSPFv3 */
|
||||||
tmp = ntohs(ps->deadint);
|
tmp = ntohs(ps->deadint);
|
||||||
#endif
|
#endif
|
||||||
if (tmp != ifa->dead)
|
if (tmp != ifa->deadint)
|
||||||
{
|
{
|
||||||
log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
|
log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
|
||||||
return;
|
return;
|
||||||
|
@ -217,13 +217,13 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||||
if (ifa->type == OSPF_IT_NBMA)
|
if (ifa->type == OSPF_IT_NBMA)
|
||||||
{
|
{
|
||||||
if ((ifa->priority == 0) && (n->priority > 0))
|
if ((ifa->priority == 0) && (n->priority > 0))
|
||||||
ospf_hello_send(NULL, 0, n);
|
ospf_hello_send(NULL, OHS_HELLO, n);
|
||||||
}
|
}
|
||||||
ospf_neigh_sm(n, INM_HELLOREC);
|
ospf_neigh_sm(n, INM_HELLOREC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
|
ospf_hello_send(timer *timer, int kind, struct ospf_neighbor *dirn)
|
||||||
{
|
{
|
||||||
struct ospf_iface *ifa;
|
struct ospf_iface *ifa;
|
||||||
struct ospf_hello_packet *pkt;
|
struct ospf_hello_packet *pkt;
|
||||||
|
@ -231,7 +231,6 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
|
||||||
struct proto *p;
|
struct proto *p;
|
||||||
struct ospf_neighbor *neigh, *n1;
|
struct ospf_neighbor *neigh, *n1;
|
||||||
u16 length;
|
u16 length;
|
||||||
u32 *pp;
|
|
||||||
int i;
|
int i;
|
||||||
struct nbma_node *nb;
|
struct nbma_node *nb;
|
||||||
|
|
||||||
|
@ -276,27 +275,31 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
|
||||||
pkt->options = ifa->oa->options;
|
pkt->options = ifa->oa->options;
|
||||||
|
|
||||||
#ifdef OSPFv2
|
#ifdef OSPFv2
|
||||||
pkt->deadint = htonl(ifa->dead);
|
pkt->deadint = htonl(ifa->deadint);
|
||||||
pkt->dr = htonl(ipa_to_u32(ifa->drip));
|
pkt->dr = htonl(ipa_to_u32(ifa->drip));
|
||||||
pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
|
pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
|
||||||
#else /* OSPFv3 */
|
#else /* OSPFv3 */
|
||||||
pkt->deadint = htons(ifa->dead);
|
pkt->deadint = htons(ifa->deadint);
|
||||||
pkt->dr = htonl(ifa->drid);
|
pkt->dr = htonl(ifa->drid);
|
||||||
pkt->bdr = htonl(ifa->bdrid);
|
pkt->bdr = htonl(ifa->bdrid);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Fill all neighbors */
|
/* Fill all neighbors */
|
||||||
i = 0;
|
i = 0;
|
||||||
pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
|
|
||||||
WALK_LIST(neigh, ifa->neigh_list)
|
if (kind != OHS_SHUTDOWN)
|
||||||
{
|
{
|
||||||
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
|
u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
|
||||||
|
WALK_LIST(neigh, ifa->neigh_list)
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
|
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
|
||||||
break;
|
{
|
||||||
|
log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->iface->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*(pp + i) = htonl(neigh->rid);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
*(pp + i) = htonl(neigh->rid);
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
|
length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
|
||||||
|
@ -319,7 +322,7 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
|
||||||
int to_all = ifa->state > OSPF_IS_DROTHER;
|
int to_all = ifa->state > OSPF_IS_DROTHER;
|
||||||
int me_elig = ifa->priority > 0;
|
int me_elig = ifa->priority > 0;
|
||||||
|
|
||||||
if (poll) /* Poll timer */
|
if (kind == OHS_POLL) /* Poll timer */
|
||||||
{
|
{
|
||||||
WALK_LIST(nb, ifa->nbma_list)
|
WALK_LIST(nb, ifa->nbma_list)
|
||||||
if (!nb->found && (to_all || (me_elig && nb->eligible)))
|
if (!nb->found && (to_all || (me_elig && nb->eligible)))
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
|
|
||||||
void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||||
struct ospf_neighbor *n, ip_addr faddr);
|
struct ospf_neighbor *n, ip_addr faddr);
|
||||||
void ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn);
|
void ospf_hello_send(timer *timer, int kind, struct ospf_neighbor *dirn);
|
||||||
|
|
||||||
|
#define OHS_HELLO 0
|
||||||
|
#define OHS_POLL 1
|
||||||
|
#define OHS_SHUTDOWN 2
|
||||||
|
|
||||||
#endif /* _BIRD_OSPF_HELLO_H_ */
|
#endif /* _BIRD_OSPF_HELLO_H_ */
|
||||||
|
|
|
@ -21,13 +21,13 @@ char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" };
|
||||||
static void
|
static void
|
||||||
poll_timer_hook(timer * timer)
|
poll_timer_hook(timer * timer)
|
||||||
{
|
{
|
||||||
ospf_hello_send(timer, 1, NULL);
|
ospf_hello_send(timer, OHS_POLL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hello_timer_hook(timer * timer)
|
hello_timer_hook(timer * timer)
|
||||||
{
|
{
|
||||||
ospf_hello_send(timer, 0, NULL);
|
ospf_hello_send(timer, OHS_HELLO, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -40,6 +40,8 @@ wait_timer_hook(timer * timer)
|
||||||
ospf_iface_sm(ifa, ISM_WAITF);
|
ospf_iface_sm(ifa, ISM_WAITF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa);
|
||||||
|
|
||||||
u32
|
u32
|
||||||
rxbufsize(struct ospf_iface *ifa)
|
rxbufsize(struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
|
@ -163,7 +165,13 @@ ospf_iface_down(struct ospf_iface *ifa)
|
||||||
|
|
||||||
if (ifa->type != OSPF_IT_VLINK)
|
if (ifa->type != OSPF_IT_VLINK)
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
|
#ifdef OSPFv2
|
||||||
|
OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
|
||||||
|
ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
|
||||||
|
#else
|
||||||
|
OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
|
||||||
|
ifa->iface->name, ifa->instance_id, ifa->oa->areaid);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* First of all kill all the related vlinks */
|
/* First of all kill all the related vlinks */
|
||||||
WALK_LIST(iff, po->iface_list)
|
WALK_LIST(iff, po->iface_list)
|
||||||
|
@ -207,14 +215,25 @@ ospf_iface_down(struct ospf_iface *ifa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
void
|
||||||
ospf_iface_remove(struct ospf_iface *ifa)
|
ospf_iface_remove(struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
|
struct proto *p = &ifa->oa->po->proto;
|
||||||
|
if (ifa->type == OSPF_IT_VLINK)
|
||||||
|
OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);
|
||||||
|
|
||||||
ospf_iface_sm(ifa, ISM_DOWN);
|
ospf_iface_sm(ifa, ISM_DOWN);
|
||||||
rem_node(NODE ifa);
|
rem_node(NODE ifa);
|
||||||
rfree(ifa->pool);
|
rfree(ifa->pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ospf_iface_shutdown(struct ospf_iface *ifa)
|
||||||
|
{
|
||||||
|
if (ifa->state > OSPF_IS_DOWN)
|
||||||
|
ospf_hello_send(ifa->hello_timer, OHS_SHUTDOWN, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ospf_iface_chstate - handle changes of interface state
|
* ospf_iface_chstate - handle changes of interface state
|
||||||
* @ifa: OSPF interface
|
* @ifa: OSPF interface
|
||||||
|
@ -357,7 +376,7 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8
|
static u8
|
||||||
ospf_iface_classify(struct iface *ifa, struct ifa *addr)
|
ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
|
||||||
{
|
{
|
||||||
if (ipa_nonzero(addr->opposite))
|
if (ipa_nonzero(addr->opposite))
|
||||||
return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP : OSPF_IT_PTMP;
|
return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP : OSPF_IT_PTMP;
|
||||||
|
@ -372,6 +391,13 @@ ospf_iface_classify(struct iface *ifa, struct ifa *addr)
|
||||||
return OSPF_IT_PTP;
|
return OSPF_IT_PTP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u8
|
||||||
|
ospf_iface_classify(u8 type, struct ifa *addr)
|
||||||
|
{
|
||||||
|
return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_int(addr->iface, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ospf_iface *
|
struct ospf_iface *
|
||||||
ospf_iface_find(struct proto_ospf *p, struct iface *what)
|
ospf_iface_find(struct proto_ospf *p, struct iface *what)
|
||||||
{
|
{
|
||||||
|
@ -401,23 +427,69 @@ ospf_iface_add(struct object_lock *lock)
|
||||||
ospf_iface_sm(ifa, (ifa->check_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP);
|
ospf_iface_sm(ifa, (ifa->check_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static inline void
|
||||||
ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
|
add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
|
||||||
struct ospf_area_config *ac, struct ospf_iface_patt *ip)
|
|
||||||
{
|
{
|
||||||
struct proto *p = &po->proto;
|
struct nbma_node *n = mb_alloc(ifa->pool, sizeof(struct nbma_node));
|
||||||
struct pool *pool = rp_new(p->pool, "OSPF Interface");
|
add_tail(&ifa->nbma_list, NODE n);
|
||||||
|
n->ip = src->ip;
|
||||||
|
n->eligible = src->eligible;
|
||||||
|
n->found = found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
|
||||||
|
{
|
||||||
|
if (! addr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We cannot properly support multiple OSPF ifaces on real iface
|
||||||
|
* with multiple prefixes, therefore we force OSPF ifaces with
|
||||||
|
* non-primary IP prefixes to be stub.
|
||||||
|
*/
|
||||||
|
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
|
||||||
|
if (! (addr->flags & IA_PRIMARY))
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* a loopback/dummy address */
|
||||||
|
if ((addr->pxlen == MAX_PREFIX_LENGTH) && ipa_zero(addr->opposite))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return ip->stub;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
|
||||||
|
{
|
||||||
|
struct proto *p = &oa->po->proto;
|
||||||
|
struct iface *iface = addr ? addr->iface : NULL;
|
||||||
|
struct pool *pool;
|
||||||
|
|
||||||
struct ospf_iface *ifa;
|
struct ospf_iface *ifa;
|
||||||
struct nbma_node *nbma, *nb;
|
struct nbma_node *nb;
|
||||||
struct object_lock *lock;
|
struct object_lock *lock;
|
||||||
struct ospf_area *oa;
|
|
||||||
|
|
||||||
if (ip->type != OSPF_IT_VLINK)
|
if (ip->type == OSPF_IT_VLINK)
|
||||||
OSPF_TRACE(D_EVENTS, "Adding interface %s", iface->name);
|
OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef OSPFv2
|
||||||
|
OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
|
||||||
|
iface->name, addr->prefix, addr->pxlen, oa->areaid);
|
||||||
|
#else
|
||||||
|
OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
|
||||||
|
iface->name, ip->instance_id, oa->areaid);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = rp_new(p->pool, "OSPF Interface");
|
||||||
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
|
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
|
||||||
ifa->iface = iface;
|
ifa->iface = iface;
|
||||||
ifa->addr = addr;
|
ifa->addr = addr;
|
||||||
|
ifa->oa = oa;
|
||||||
|
ifa->cf = ip;
|
||||||
ifa->pool = pool;
|
ifa->pool = pool;
|
||||||
|
|
||||||
ifa->cost = ip->cost;
|
ifa->cost = ip->cost;
|
||||||
|
@ -428,7 +500,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
|
||||||
ifa->pollint = ip->pollint;
|
ifa->pollint = ip->pollint;
|
||||||
ifa->strictnbma = ip->strictnbma;
|
ifa->strictnbma = ip->strictnbma;
|
||||||
ifa->waitint = ip->waitint;
|
ifa->waitint = ip->waitint;
|
||||||
ifa->dead = (ip->dead == 0) ? ip->deadc * ifa->helloint : ip->dead;
|
ifa->deadint = ip->deadint;
|
||||||
ifa->stub = ospf_iface_stubby(ip, addr);
|
ifa->stub = ospf_iface_stubby(ip, addr);
|
||||||
ifa->ioprob = OSPF_I_OK;
|
ifa->ioprob = OSPF_I_OK;
|
||||||
ifa->rxbuf = ip->rxbuf;
|
ifa->rxbuf = ip->rxbuf;
|
||||||
|
@ -444,14 +516,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
|
||||||
ifa->instance_id = ip->instance_id;
|
ifa->instance_id = ip->instance_id;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ip->type == OSPF_IT_UNDEF)
|
ifa->type = ospf_iface_classify(ip->type, addr);
|
||||||
ifa->type = ospf_iface_classify(iface, addr);
|
|
||||||
else
|
|
||||||
ifa->type = ip->type;
|
|
||||||
|
|
||||||
/* a loopback/dummy address */
|
|
||||||
if ((addr->pxlen == MAX_PREFIX_LENGTH) && ipa_zero(addr->opposite))
|
|
||||||
ifa->stub = 1;
|
|
||||||
|
|
||||||
/* Check validity of interface type */
|
/* Check validity of interface type */
|
||||||
int old_type = ifa->type;
|
int old_type = ifa->type;
|
||||||
|
@ -479,16 +544,8 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
|
||||||
init_list(&ifa->nbma_list);
|
init_list(&ifa->nbma_list);
|
||||||
|
|
||||||
WALK_LIST(nb, ip->nbma_list)
|
WALK_LIST(nb, ip->nbma_list)
|
||||||
{
|
if (ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
|
||||||
if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
|
add_nbma_node(ifa, nb, 0);
|
||||||
continue;
|
|
||||||
|
|
||||||
nbma = mb_alloc(pool, sizeof(struct nbma_node));
|
|
||||||
nbma->ip = nb->ip;
|
|
||||||
nbma->eligible = nb->eligible;
|
|
||||||
nbma->found = 0;
|
|
||||||
add_tail(&ifa->nbma_list, NODE nbma);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
|
DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
|
||||||
ifa->hello_timer = tm_new(pool);
|
ifa->hello_timer = tm_new(pool);
|
||||||
|
@ -518,26 +575,11 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
ifa->state = OSPF_IS_DOWN;
|
ifa->state = OSPF_IS_DOWN;
|
||||||
add_tail(&po->iface_list, NODE ifa);
|
add_tail(&oa->po->iface_list, NODE ifa);
|
||||||
|
|
||||||
ifa->oa = NULL;
|
|
||||||
WALK_LIST(oa, po->area_list)
|
|
||||||
{
|
|
||||||
if (oa->areaid == ac->areaid)
|
|
||||||
{
|
|
||||||
ifa->oa = oa;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ifa->oa)
|
|
||||||
bug("Cannot add any area to accepted Interface");
|
|
||||||
else
|
|
||||||
|
|
||||||
if (ifa->type == OSPF_IT_VLINK)
|
if (ifa->type == OSPF_IT_VLINK)
|
||||||
{
|
{
|
||||||
ifa->oa = po->backbone;
|
ifa->voa = ospf_find_area(oa->po, ip->voa);
|
||||||
ifa->voa = oa;
|
|
||||||
ifa->vid = ip->vid;
|
ifa->vid = ip->vid;
|
||||||
return; /* Don't lock, don't add sockets */
|
return; /* Don't lock, don't add sockets */
|
||||||
}
|
}
|
||||||
|
@ -564,14 +606,209 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
|
||||||
olock_acquire(lock);
|
olock_acquire(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
|
||||||
|
{
|
||||||
|
struct proto *p = &ifa->oa->po->proto;
|
||||||
|
struct nbma_node *nb, *nbx;
|
||||||
|
char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink";
|
||||||
|
|
||||||
|
/* Type could be changed in ospf_iface_new(),
|
||||||
|
but if config values are same then also results are same */
|
||||||
|
int old_type = ospf_iface_classify(ifa->cf->type, ifa->addr);
|
||||||
|
int new_type = ospf_iface_classify(new->type, ifa->addr);
|
||||||
|
if (old_type != new_type)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int new_stub = ospf_iface_stubby(new, ifa->addr);
|
||||||
|
if (ifa->stub != new_stub)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ifa->cf = new;
|
||||||
|
ifa->marked = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* HELLO TIMER */
|
||||||
|
if (ifa->helloint != new->helloint)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing hello interval on interface %s from %d to %d",
|
||||||
|
ifname, ifa->helloint, new->helloint);
|
||||||
|
|
||||||
|
ifa->helloint = new->helloint;
|
||||||
|
ifa->hello_timer->recurrent = ifa->helloint;
|
||||||
|
tm_start(ifa->hello_timer, ifa->helloint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RXMT TIMER */
|
||||||
|
if (ifa->rxmtint != new->rxmtint)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing retransmit interval on interface %s from %d to %d",
|
||||||
|
ifname, ifa->rxmtint, new->rxmtint);
|
||||||
|
|
||||||
|
ifa->rxmtint = new->rxmtint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* POLL TIMER */
|
||||||
|
if (ifa->pollint != new->pollint)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing poll interval on interface %s from %d to %d",
|
||||||
|
ifname, ifa->pollint, new->pollint);
|
||||||
|
|
||||||
|
ifa->pollint = new->helloint;
|
||||||
|
ifa->poll_timer->recurrent = ifa->pollint;
|
||||||
|
tm_start(ifa->poll_timer, ifa->pollint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WAIT TIMER */
|
||||||
|
if (ifa->waitint != new->waitint)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing wait interval on interface %s from %d to %d",
|
||||||
|
ifname, ifa->waitint, new->waitint);
|
||||||
|
|
||||||
|
ifa->waitint = new->waitint;
|
||||||
|
if (ifa->wait_timer->expires != 0)
|
||||||
|
tm_start(ifa->wait_timer, ifa->waitint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DEAD TIMER */
|
||||||
|
if (ifa->deadint != new->deadint)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing dead interval on interface %s from %d to %d",
|
||||||
|
ifname, ifa->deadint, new->deadint);
|
||||||
|
ifa->deadint = new->deadint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INFTRANS */
|
||||||
|
if (ifa->inftransdelay != new->inftransdelay)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing transmit delay on interface %s from %d to %d",
|
||||||
|
ifname, ifa->inftransdelay, new->inftransdelay);
|
||||||
|
ifa->inftransdelay = new->inftransdelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OSPFv2
|
||||||
|
/* AUTHENTICATION */
|
||||||
|
if (ifa->autype != new->autype)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing authentication type on interface %s", ifname);
|
||||||
|
ifa->autype = new->autype;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update passwords */
|
||||||
|
ifa->passwords = new->passwords;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Remaining options are just for proper interfaces */
|
||||||
|
if (ifa->type == OSPF_IT_VLINK)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
|
||||||
|
/* COST */
|
||||||
|
if (ifa->cost != new->cost)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing cost on interface %s from %d to %d",
|
||||||
|
ifname, ifa->cost, new->cost);
|
||||||
|
|
||||||
|
ifa->cost = new->cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PRIORITY */
|
||||||
|
if (ifa->priority != new->priority)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing priority on interface %s from %d to %d",
|
||||||
|
ifname, ifa->priority, new->priority);
|
||||||
|
ifa->priority = new->priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* STRICT NBMA */
|
||||||
|
if (ifa->strictnbma != new->strictnbma)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing NBMA strictness on interface %s", ifname);
|
||||||
|
ifa->strictnbma = new->strictnbma;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NBMA LIST - remove or update old */
|
||||||
|
WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
|
||||||
|
{
|
||||||
|
struct nbma_node *nb2 = find_nbma_node_in(&new->nbma_list, nb->ip);
|
||||||
|
if (nb2)
|
||||||
|
{
|
||||||
|
if (nb->eligible != nb2->eligible)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing eligibility of neighbor %I on interface %s",
|
||||||
|
nb->ip, ifname);
|
||||||
|
nb->eligible = nb2->eligible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on interface %s",
|
||||||
|
nb->ip, ifname);
|
||||||
|
rem_node(NODE nb);
|
||||||
|
mb_free(nb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NBMA LIST - add new */
|
||||||
|
WALK_LIST(nb, new->nbma_list)
|
||||||
|
{
|
||||||
|
if (!ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (! find_nbma_node(ifa, nb->ip))
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on interface %s",
|
||||||
|
nb->ip, ifname);
|
||||||
|
add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RX BUFF */
|
||||||
|
if (ifa->rxbuf != new->rxbuf)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing rxbuf interface %s from %d to %d",
|
||||||
|
ifname, ifa->rxbuf, new->rxbuf);
|
||||||
|
ifa->rxbuf = new->rxbuf;
|
||||||
|
ospf_iface_change_mtu(ifa->oa->po, ifa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LINK */
|
||||||
|
if (ifa->check_link != new->check_link)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "%s link check on interface %s",
|
||||||
|
new->check_link ? "Enabling" : "Disabling", ifname);
|
||||||
|
ifa->check_link = new->check_link;
|
||||||
|
|
||||||
|
if (!(ifa->iface->flags & IF_LINK_UP))
|
||||||
|
ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ECMP weight */
|
||||||
|
if (ifa->ecmp_weight != new->ecmp_weight)
|
||||||
|
{
|
||||||
|
OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d",
|
||||||
|
ifname, (int)ifa->ecmp_weight + 1, (int)new->ecmp_weight + 1);
|
||||||
|
ifa->ecmp_weight = new->ecmp_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* instance_id is not updated - it is part of key */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef OSPFv2
|
#ifdef OSPFv2
|
||||||
|
|
||||||
|
static inline struct ospf_iface_patt *
|
||||||
|
ospf_iface_patt_find(struct ospf_area_config *ac, struct ifa *a)
|
||||||
|
{
|
||||||
|
return (struct ospf_iface_patt *) iface_patt_find(&ac->patt_list, a->iface, a);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
||||||
{
|
{
|
||||||
struct proto_ospf *po = (struct proto_ospf *) p;
|
struct proto_ospf *po = (struct proto_ospf *) p;
|
||||||
struct ospf_config *cf = (struct ospf_config *) (p->cf);
|
|
||||||
|
|
||||||
if (a->flags & IA_SECONDARY)
|
if (a->flags & IA_SECONDARY)
|
||||||
return;
|
return;
|
||||||
|
@ -583,16 +820,14 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
||||||
if (flags & IF_CHANGE_UP)
|
if (flags & IF_CHANGE_UP)
|
||||||
{
|
{
|
||||||
int done = 0;
|
int done = 0;
|
||||||
struct ospf_area_config *ac;
|
struct ospf_area *oa;
|
||||||
WALK_LIST(ac, cf->area_list)
|
WALK_LIST(oa, po->area_list)
|
||||||
{
|
{
|
||||||
struct ospf_iface_patt *ip = (struct ospf_iface_patt *)
|
struct ospf_iface_patt *ip;
|
||||||
iface_patt_find(&ac->patt_list, a->iface, a);
|
if (ip = ospf_iface_patt_find(oa->ac, a))
|
||||||
|
|
||||||
if (ip)
|
|
||||||
{
|
{
|
||||||
if (!done)
|
if (!done)
|
||||||
ospf_iface_new(po, a->iface, a, ac, ip);
|
ospf_iface_new(oa, a, ip);
|
||||||
done++;
|
done++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,23 +848,72 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* OSPFv3 */
|
static struct ospf_iface *
|
||||||
|
ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
|
||||||
static inline int iflag_test(u32 *a, u8 i)
|
|
||||||
{
|
{
|
||||||
return a[i / 32] & (1u << (i % 32));
|
struct ospf_iface *ifa;
|
||||||
|
WALK_LIST(ifa, oa->po->iface_list)
|
||||||
|
if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
|
||||||
|
return ifa;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void iflag_set(u32 *a, u8 i)
|
void
|
||||||
|
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
|
||||||
{
|
{
|
||||||
a[i / 32] |= (1u << (i % 32));
|
struct ospf_iface_patt *ip;
|
||||||
|
struct iface *iface;
|
||||||
|
struct ifa *a;
|
||||||
|
|
||||||
|
WALK_LIST(iface, iface_list)
|
||||||
|
WALK_LIST(a, iface->addrs)
|
||||||
|
{
|
||||||
|
if (a->flags & IA_SECONDARY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (a->scope <= SCOPE_LINK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ip = ospf_iface_patt_find(oa->ac, a))
|
||||||
|
{
|
||||||
|
/* Main inner loop */
|
||||||
|
struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a);
|
||||||
|
if (ifa)
|
||||||
|
{
|
||||||
|
if (ospf_iface_reconfigure(ifa, ip))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Hard restart */
|
||||||
|
ospf_iface_shutdown(ifa);
|
||||||
|
ospf_iface_remove(ifa);
|
||||||
|
}
|
||||||
|
|
||||||
|
ospf_iface_new(oa, a, ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else /* OSPFv3 */
|
||||||
|
|
||||||
|
struct ospf_iface_patt *
|
||||||
|
ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
|
||||||
|
{
|
||||||
|
struct ospf_iface_patt *pt, *res = NULL;
|
||||||
|
|
||||||
|
WALK_LIST(pt, ac->patt_list)
|
||||||
|
if ((pt->instance_id >= iid) && (iface_patt_match(&pt->i, iface, NULL)) &&
|
||||||
|
(!res || (pt->instance_id < res->instance_id)))
|
||||||
|
res = pt;
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
||||||
{
|
{
|
||||||
struct proto_ospf *po = (struct proto_ospf *) p;
|
struct proto_ospf *po = (struct proto_ospf *) p;
|
||||||
struct ospf_config *cf = (struct ospf_config *) (p->cf);
|
|
||||||
|
|
||||||
if (a->flags & IA_SECONDARY)
|
if (a->flags & IA_SECONDARY)
|
||||||
return;
|
return;
|
||||||
|
@ -643,40 +927,26 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
||||||
{
|
{
|
||||||
if (flags & IF_CHANGE_UP)
|
if (flags & IF_CHANGE_UP)
|
||||||
{
|
{
|
||||||
u32 found_all[8] = {};
|
int done0 = 0;
|
||||||
struct ospf_area_config *ac;
|
struct ospf_area *oa;
|
||||||
|
|
||||||
WALK_LIST(ac, cf->area_list)
|
WALK_LIST(oa, po->area_list)
|
||||||
{
|
{
|
||||||
u32 found_new[8] = {};
|
int iid = 0;
|
||||||
struct iface_patt *pt;
|
|
||||||
|
|
||||||
WALK_LIST(pt, ac->patt_list)
|
struct ospf_iface_patt *ip;
|
||||||
|
while (ip = ospf_iface_patt_find(oa->ac, a->iface, iid))
|
||||||
{
|
{
|
||||||
if (iface_patt_match(pt, a->iface, a))
|
ospf_iface_new(oa, a, ip);
|
||||||
{
|
if (ip->instance_id == 0)
|
||||||
struct ospf_iface_patt *ipt = (struct ospf_iface_patt *) pt;
|
done0++;
|
||||||
|
iid = ip->instance_id + 1;
|
||||||
/* If true, we already assigned that IID and we skip
|
|
||||||
this to implement first-match behavior */
|
|
||||||
if (iflag_test(found_new, ipt->instance_id))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* If true, we already assigned that in a different area,
|
|
||||||
we log collision */
|
|
||||||
if (iflag_test(found_all, ipt->instance_id))
|
|
||||||
{
|
|
||||||
log(L_WARN "%s: Interface %s (IID %d) matches for multiple areas",
|
|
||||||
p->name, a->iface->name, ipt->instance_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
iflag_set(found_all, ipt->instance_id);
|
|
||||||
iflag_set(found_new, ipt->instance_id);
|
|
||||||
ospf_iface_new(po, a->iface, a, ac, ipt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (done0 > 1)
|
||||||
|
log(L_WARN "%s: Interface %s matches for multiple areas",
|
||||||
|
p->name, a->iface->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & IF_CHANGE_DOWN)
|
if (flags & IF_CHANGE_DOWN)
|
||||||
|
@ -706,15 +976,64 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
static struct ospf_iface *
|
||||||
|
ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
|
||||||
|
{
|
||||||
|
struct ospf_iface *ifa;
|
||||||
|
WALK_LIST(ifa, oa->po->iface_list)
|
||||||
|
if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
|
||||||
|
return ifa;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
|
||||||
|
{
|
||||||
|
struct ospf_iface_patt *ip;
|
||||||
|
struct iface *iface;
|
||||||
|
struct ifa *a;
|
||||||
|
|
||||||
|
WALK_LIST(iface, iface_list)
|
||||||
|
WALK_LIST(a, iface->addrs)
|
||||||
|
{
|
||||||
|
if (a->flags & IA_SECONDARY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (a->scope != SCOPE_LINK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int iid = 0;
|
||||||
|
while (ip = ospf_iface_patt_find(nac, iface, iid))
|
||||||
|
{
|
||||||
|
iid = ip->instance_id + 1;
|
||||||
|
|
||||||
|
/* Main inner loop */
|
||||||
|
struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a, ip->instance_id);
|
||||||
|
if (ifa)
|
||||||
|
{
|
||||||
|
if (ospf_iface_reconfigure(ifa, ip))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Hard restart */
|
||||||
|
ospf_iface_shutdown(ifa);
|
||||||
|
ospf_iface_remove(ifa);
|
||||||
|
}
|
||||||
|
|
||||||
|
ospf_iface_new(oa, a, ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
|
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
|
||||||
{
|
{
|
||||||
struct proto *p = &po->proto;
|
struct proto *p = &po->proto;
|
||||||
struct ospf_packet *op;
|
struct ospf_packet *op;
|
||||||
struct ospf_neighbor *n;
|
struct ospf_neighbor *n;
|
||||||
OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s.", ifa->iface->name);
|
OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name);
|
||||||
|
|
||||||
if (ifa->sk)
|
if (ifa->sk)
|
||||||
{
|
{
|
||||||
|
@ -755,11 +1074,13 @@ void
|
||||||
ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
|
ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
|
||||||
{
|
{
|
||||||
struct proto_ospf *po = (struct proto_ospf *) p;
|
struct proto_ospf *po = (struct proto_ospf *) p;
|
||||||
|
|
||||||
|
/*
|
||||||
if (iface->flags & IF_IGNORE)
|
if (iface->flags & IF_IGNORE)
|
||||||
return;
|
return;
|
||||||
|
*/
|
||||||
|
|
||||||
/* Going up means that there are no such ifaces yet */
|
/* Going up means that there are no such ifaces yet */
|
||||||
if (flags & IF_CHANGE_UP)
|
if (flags & IF_CHANGE_UP)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -817,7 +1138,7 @@ ospf_iface_info(struct ospf_iface *ifa)
|
||||||
cli_msg(-1015, "\tPoll timer: %u", ifa->pollint);
|
cli_msg(-1015, "\tPoll timer: %u", ifa->pollint);
|
||||||
}
|
}
|
||||||
cli_msg(-1015, "\tWait timer: %u", ifa->waitint);
|
cli_msg(-1015, "\tWait timer: %u", ifa->waitint);
|
||||||
cli_msg(-1015, "\tDead timer: %u", ifa->dead);
|
cli_msg(-1015, "\tDead timer: %u", ifa->deadint);
|
||||||
cli_msg(-1015, "\tRetransmit timer: %u", ifa->rxmtint);
|
cli_msg(-1015, "\tRetransmit timer: %u", ifa->rxmtint);
|
||||||
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
|
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
|
||||||
{
|
{
|
||||||
|
@ -828,9 +1149,3 @@ ospf_iface_info(struct ospf_iface *ifa)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ospf_iface_shutdown(struct ospf_iface *ifa)
|
|
||||||
{
|
|
||||||
init_list(&ifa->neigh_list);
|
|
||||||
hello_timer_hook(ifa->hello_timer);
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,10 +16,11 @@ struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what);
|
||||||
void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface);
|
void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface);
|
||||||
void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
|
void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
|
||||||
void ospf_iface_info(struct ospf_iface *ifa);
|
void ospf_iface_info(struct ospf_iface *ifa);
|
||||||
|
void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip);
|
||||||
|
void ospf_iface_remove(struct ospf_iface *ifa);
|
||||||
void ospf_iface_shutdown(struct ospf_iface *ifa);
|
void ospf_iface_shutdown(struct ospf_iface *ifa);
|
||||||
void ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr, struct ospf_area_config *ac, struct ospf_iface_patt *ip);
|
int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
|
||||||
void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa);
|
void ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac);
|
||||||
void ospf_set_rxbuf_size(struct ospf_iface *ifa, u32 rxbuf);
|
|
||||||
|
|
||||||
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
|
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
|
||||||
|
|
||||||
|
@ -27,5 +28,4 @@ static inline struct nbma_node *
|
||||||
find_nbma_node(struct ospf_iface *ifa, ip_addr ip)
|
find_nbma_node(struct ospf_iface *ifa, ip_addr ip)
|
||||||
{ return find_nbma_node_in(&ifa->nbma_list, ip); }
|
{ return find_nbma_node_in(&ifa->nbma_list, ip); }
|
||||||
|
|
||||||
|
|
||||||
#endif /* _BIRD_OSPF_IFACE_H_ */
|
#endif /* _BIRD_OSPF_IFACE_H_ */
|
||||||
|
|
|
@ -23,6 +23,18 @@ flush_lsa(struct top_hash_entry *en, struct proto_ospf *po)
|
||||||
ospf_hash_delete(po->gr, en);
|
ospf_hash_delete(po->gr, en);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ospf_flush_area(struct proto_ospf *po, u32 areaid)
|
||||||
|
{
|
||||||
|
struct top_hash_entry *en, *nxt;
|
||||||
|
|
||||||
|
WALK_SLIST_DELSAFE(en, nxt, po->lsal)
|
||||||
|
{
|
||||||
|
if ((LSA_SCOPE(&en->lsa) == LSA_SCOPE_AREA) && (en->domain == areaid))
|
||||||
|
flush_lsa(en, po);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ospf_age
|
* ospf_age
|
||||||
* @po: ospf protocol
|
* @po: ospf protocol
|
||||||
|
|
|
@ -36,5 +36,7 @@ int lsa_validate(struct ospf_lsa_header *lsa, void *body);
|
||||||
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
|
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
|
||||||
void ospf_age(struct proto_ospf *po);
|
void ospf_age(struct proto_ospf *po);
|
||||||
void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po);
|
void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po);
|
||||||
|
void ospf_flush_area(struct proto_ospf *po, u32 areaid);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _BIRD_OSPF_LSALIB_H_ */
|
#endif /* _BIRD_OSPF_LSALIB_H_ */
|
||||||
|
|
|
@ -349,7 +349,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||||
case NEIGHBOR_DOWN:
|
case NEIGHBOR_DOWN:
|
||||||
neigh_chstate(n, NEIGHBOR_INIT);
|
neigh_chstate(n, NEIGHBOR_INIT);
|
||||||
default:
|
default:
|
||||||
tm_start(n->inactim, n->ifa->dead); /* Restart inactivity timer */
|
tm_start(n->inactim, n->ifa->deadint); /* Restart inactivity timer */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -548,16 +548,6 @@ find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ospf_area *
|
|
||||||
ospf_find_area(struct proto_ospf *po, u32 aid)
|
|
||||||
{
|
|
||||||
struct ospf_area *oa;
|
|
||||||
WALK_LIST(oa, po->area_list)
|
|
||||||
if (((struct ospf_area *) oa)->areaid == aid)
|
|
||||||
return oa;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Neighbor is inactive for a long time. Remove it. */
|
/* Neighbor is inactive for a long time. Remove it. */
|
||||||
static void
|
static void
|
||||||
neighbor_timer_hook(timer * timer)
|
neighbor_timer_hook(timer * timer)
|
||||||
|
|
|
@ -15,7 +15,6 @@ void ospf_neigh_sm(struct ospf_neighbor *n, int event);
|
||||||
void bdr_election(struct ospf_iface *ifa);
|
void bdr_election(struct ospf_iface *ifa);
|
||||||
struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid);
|
struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid);
|
||||||
struct ospf_neighbor *find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip);
|
struct ospf_neighbor *find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip);
|
||||||
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
|
|
||||||
void ospf_neigh_remove(struct ospf_neighbor *n);
|
void ospf_neigh_remove(struct ospf_neighbor *n);
|
||||||
void ospf_sh_neigh_info(struct ospf_neighbor *n);
|
void ospf_sh_neigh_info(struct ospf_neighbor *n);
|
||||||
|
|
||||||
|
|
|
@ -122,27 +122,95 @@ static void
|
||||||
add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
|
add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
|
||||||
{
|
{
|
||||||
struct proto_ospf *po = oa->po;
|
struct proto_ospf *po = oa->po;
|
||||||
struct proto *p = &po->proto;
|
struct area_net_config *anc;
|
||||||
struct area_net_config *anet;
|
struct area_net *an;
|
||||||
struct area_net *antmp;
|
|
||||||
|
|
||||||
fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 0, ospf_area_initfib);
|
fib_init(&oa->net_fib, po->proto.pool, sizeof(struct area_net), 0, ospf_area_initfib);
|
||||||
|
|
||||||
WALK_LIST(anet, ac->net_list)
|
WALK_LIST(anc, ac->net_list)
|
||||||
{
|
{
|
||||||
antmp = (struct area_net *) fib_get(&oa->net_fib, &anet->px.addr, anet->px.len);
|
an = (struct area_net *) fib_get(&oa->net_fib, &anc->px.addr, anc->px.len);
|
||||||
antmp->hidden = anet->hidden;
|
an->hidden = an->hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
|
||||||
|
{
|
||||||
|
struct proto *p = &po->proto;
|
||||||
|
struct ospf_area *oa;
|
||||||
|
|
||||||
|
OSPF_TRACE(D_EVENTS, "Adding area %R", ac->areaid);
|
||||||
|
|
||||||
|
oa = mb_allocz(p->pool, sizeof(struct ospf_area));
|
||||||
|
add_tail(&po->area_list, NODE oa);
|
||||||
|
po->areano++;
|
||||||
|
|
||||||
|
oa->ac = ac;
|
||||||
|
oa->stub = ac->stub;
|
||||||
|
oa->areaid = ac->areaid;
|
||||||
|
oa->rt = NULL;
|
||||||
|
oa->po = po;
|
||||||
|
fib_init(&oa->rtr, p->pool, sizeof(ort), 0, ospf_rt_initort);
|
||||||
|
add_area_nets(oa, ac);
|
||||||
|
|
||||||
|
if (oa->areaid == 0)
|
||||||
|
po->backbone = oa;
|
||||||
|
|
||||||
|
#ifdef OSPFv2
|
||||||
|
oa->options = (oa->stub ? 0 : OPT_E);
|
||||||
|
#else /* OSPFv3 */
|
||||||
|
oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (reconf)
|
||||||
|
ospf_ifaces_reconfigure(oa, ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ospf_area_remove(struct ospf_area *oa)
|
||||||
|
{
|
||||||
|
struct proto *p = &oa->po->proto;
|
||||||
|
OSPF_TRACE(D_EVENTS, "Removing area %R", oa->areaid);
|
||||||
|
|
||||||
|
/* We suppose that interfaces are already removed */
|
||||||
|
ospf_flush_area(oa->po, oa->areaid);
|
||||||
|
|
||||||
|
fib_free(&oa->rtr);
|
||||||
|
fib_free(&oa->net_fib);
|
||||||
|
|
||||||
|
oa->po->areano--;
|
||||||
|
rem_node(NODE oa);
|
||||||
|
mb_free(oa);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ospf_area *
|
||||||
|
ospf_find_area(struct proto_ospf *po, u32 aid)
|
||||||
|
{
|
||||||
|
struct ospf_area *oa;
|
||||||
|
WALK_LIST(oa, po->area_list)
|
||||||
|
if (((struct ospf_area *) oa)->areaid == aid)
|
||||||
|
return oa;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ospf_iface *
|
||||||
|
ospf_find_vlink(struct proto_ospf *po, u32 voa, u32 vid)
|
||||||
|
{
|
||||||
|
struct ospf_iface *ifa;
|
||||||
|
WALK_LIST(ifa, po->iface_list)
|
||||||
|
if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa->areaid == voa) && (ifa->vid == vid))
|
||||||
|
return ifa;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ospf_start(struct proto *p)
|
ospf_start(struct proto *p)
|
||||||
{
|
{
|
||||||
struct proto_ospf *po = (struct proto_ospf *) p;
|
struct proto_ospf *po = (struct proto_ospf *) p;
|
||||||
struct ospf_config *c = (struct ospf_config *) (p->cf);
|
struct ospf_config *c = (struct ospf_config *) (p->cf);
|
||||||
struct ospf_area_config *ac;
|
struct ospf_area_config *ac;
|
||||||
struct ospf_area *oa;
|
|
||||||
int vlinks = 0;
|
|
||||||
|
|
||||||
po->router_id = proto_get_router_id(p->cf);
|
po->router_id = proto_get_router_id(p->cf);
|
||||||
po->rfc1583 = c->rfc1583;
|
po->rfc1583 = c->rfc1583;
|
||||||
|
@ -165,68 +233,14 @@ ospf_start(struct proto *p)
|
||||||
po->areano = 0;
|
po->areano = 0;
|
||||||
po->gr = ospf_top_new(p->pool);
|
po->gr = ospf_top_new(p->pool);
|
||||||
s_init_list(&(po->lsal));
|
s_init_list(&(po->lsal));
|
||||||
if (EMPTY_LIST(c->area_list))
|
|
||||||
{
|
|
||||||
log(L_ERR "Cannot start, no OSPF areas configured!");
|
|
||||||
return PS_DOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
WALK_LIST(ac, c->area_list)
|
WALK_LIST(ac, c->area_list)
|
||||||
{
|
ospf_area_add(po, ac, 0);
|
||||||
oa = mb_allocz(p->pool, sizeof(struct ospf_area));
|
|
||||||
add_tail(&po->area_list, NODE oa);
|
|
||||||
po->areano++;
|
|
||||||
oa->ac = ac;
|
|
||||||
oa->stub = ac->stub;
|
|
||||||
oa->areaid = ac->areaid;
|
|
||||||
oa->rt = NULL;
|
|
||||||
oa->po = po;
|
|
||||||
add_area_nets(oa, ac);
|
|
||||||
fib_init(&oa->rtr, p->pool, sizeof(ort), 0, ospf_rt_initort);
|
|
||||||
|
|
||||||
if (oa->areaid == 0)
|
/* Add all virtual links */
|
||||||
{
|
struct ospf_iface_patt *ic;
|
||||||
po->backbone = oa;
|
WALK_LIST(ic, c->vlink_list)
|
||||||
if (oa->stub) log(L_ERR "Backbone cannot be stub. Ignoring!");
|
ospf_iface_new(po->backbone, NULL, ic);
|
||||||
oa->stub = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!EMPTY_LIST(ac->vlink_list))
|
|
||||||
vlinks = 1;
|
|
||||||
|
|
||||||
#ifdef OSPFv2
|
|
||||||
oa->options = (oa->stub ? 0 : OPT_E);
|
|
||||||
#else /* OSPFv3 */
|
|
||||||
oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ABR is always in the backbone */
|
|
||||||
if (((po->areano > 1) || vlinks) && !po->backbone)
|
|
||||||
{
|
|
||||||
oa = mb_allocz(p->pool, sizeof(struct ospf_area));
|
|
||||||
add_tail(&po->area_list, NODE oa);
|
|
||||||
po->areano++;
|
|
||||||
oa->ac = NULL;
|
|
||||||
oa->stub = 0;
|
|
||||||
oa->areaid = 0;
|
|
||||||
oa->rt = NULL;
|
|
||||||
oa->po = po;
|
|
||||||
fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 0, ospf_area_initfib);
|
|
||||||
fib_init(&oa->rtr, p->pool, sizeof(ort), 0, ospf_rt_initort);
|
|
||||||
po->backbone = oa;
|
|
||||||
#ifdef OSPFv2
|
|
||||||
oa->options = OPT_E;
|
|
||||||
#else /* OSPFv3 */
|
|
||||||
oa->options = OPT_R | OPT_E | OPT_V6;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add all virtual links as interfaces */
|
|
||||||
struct ospf_iface_patt *ipatt;
|
|
||||||
WALK_LIST(ac, c->area_list)
|
|
||||||
WALK_LIST(ipatt, ac->vlink_list)
|
|
||||||
ospf_iface_new(po, NULL, NULL, ac, ipatt);
|
|
||||||
|
|
||||||
return PS_UP;
|
return PS_UP;
|
||||||
}
|
}
|
||||||
|
@ -513,8 +527,7 @@ ospf_shutdown(struct proto *p)
|
||||||
|
|
||||||
/* And send to all my neighbors 1WAY */
|
/* And send to all my neighbors 1WAY */
|
||||||
WALK_LIST(ifa, po->iface_list)
|
WALK_LIST(ifa, po->iface_list)
|
||||||
if (ifa->state > OSPF_IS_DOWN)
|
ospf_iface_shutdown(ifa);
|
||||||
ospf_iface_shutdown(ifa);
|
|
||||||
|
|
||||||
/* Cleanup locked rta entries */
|
/* Cleanup locked rta entries */
|
||||||
FIB_WALK(&po->rtf, nftmp)
|
FIB_WALK(&po->rtf, nftmp)
|
||||||
|
@ -622,10 +635,22 @@ ospf_get_attr(eattr * a, byte * buf, int buflen UNUSED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
ospf_patt_compare(struct ospf_iface_patt *a, struct ospf_iface_patt *b)
|
ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
|
||||||
{
|
{
|
||||||
return (a->type == b->type);
|
oa->ac = nac;
|
||||||
|
oa->stub = nac->stub;
|
||||||
|
|
||||||
|
ospf_ifaces_reconfigure(oa, nac);
|
||||||
|
|
||||||
|
/* Handle net_list */
|
||||||
|
fib_free(&oa->net_fib);
|
||||||
|
add_area_nets(oa, nac);
|
||||||
|
|
||||||
|
/* No need to handle stubnet_list */
|
||||||
|
|
||||||
|
oa->marked = 0;
|
||||||
|
schedule_rt_lsa(oa);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -641,296 +666,70 @@ ospf_patt_compare(struct ospf_iface_patt *a, struct ospf_iface_patt *b)
|
||||||
static int
|
static int
|
||||||
ospf_reconfigure(struct proto *p, struct proto_config *c)
|
ospf_reconfigure(struct proto *p, struct proto_config *c)
|
||||||
{
|
{
|
||||||
|
struct proto_ospf *po = (struct proto_ospf *) p;
|
||||||
struct ospf_config *old = (struct ospf_config *) (p->cf);
|
struct ospf_config *old = (struct ospf_config *) (p->cf);
|
||||||
struct ospf_config *new = (struct ospf_config *) c;
|
struct ospf_config *new = (struct ospf_config *) c;
|
||||||
struct ospf_area_config *oldac, *newac;
|
struct ospf_area_config *nac;
|
||||||
struct proto_ospf *po = (struct proto_ospf *) p;
|
struct ospf_area *oa, *oax;
|
||||||
struct ospf_iface_patt *oldip, *newip;
|
struct ospf_iface *ifa, *ifx;
|
||||||
struct ospf_iface *ifa;
|
struct ospf_iface_patt *ip;
|
||||||
struct nbma_node *nb1, *nb2, *nbnx;
|
|
||||||
struct ospf_area *oa = NULL;
|
|
||||||
int olddead, newdead;
|
|
||||||
|
|
||||||
if (po->rfc1583 != new->rfc1583)
|
if (po->rfc1583 != new->rfc1583)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
schedule_rtcalc(po);
|
if (old->abr != new->abr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
po->tick = new->tick;
|
|
||||||
po->ecmp = new->ecmp;
|
po->ecmp = new->ecmp;
|
||||||
|
po->tick = new->tick;
|
||||||
po->disp_timer->recurrent = po->tick;
|
po->disp_timer->recurrent = po->tick;
|
||||||
tm_start(po->disp_timer, 1);
|
tm_start(po->disp_timer, 1);
|
||||||
|
|
||||||
oldac = HEAD(old->area_list);
|
/* Mark all areas and ifaces */
|
||||||
newac = HEAD(new->area_list);
|
WALK_LIST(oa, po->area_list)
|
||||||
|
oa->marked = 1;
|
||||||
|
|
||||||
/* I should get it in the same order */
|
WALK_LIST(ifa, po->iface_list)
|
||||||
|
ifa->marked = 1;
|
||||||
|
|
||||||
while (((NODE(oldac))->next != NULL) && ((NODE(newac))->next != NULL))
|
/* Add and update areas */
|
||||||
|
WALK_LIST(nac, new->area_list)
|
||||||
{
|
{
|
||||||
if (oldac->areaid != newac->areaid)
|
oa = ospf_find_area(po, nac->areaid);
|
||||||
return 0;
|
if (oa)
|
||||||
|
ospf_area_reconfigure(oa, nac);
|
||||||
WALK_LIST(oa, po->area_list)
|
else
|
||||||
if (oa->areaid == newac->areaid)
|
ospf_area_add(po, nac, 1);
|
||||||
break;
|
|
||||||
|
|
||||||
if (!oa)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
oa->ac = newac;
|
|
||||||
oa->stub = newac->stub;
|
|
||||||
if (newac->stub && (oa->areaid == 0)) oa->stub = 0;
|
|
||||||
|
|
||||||
/* Check stubnet_list */
|
|
||||||
struct ospf_stubnet_config *oldsn = HEAD(oldac->stubnet_list);
|
|
||||||
struct ospf_stubnet_config *newsn = HEAD(newac->stubnet_list);
|
|
||||||
|
|
||||||
while (((NODE(oldsn))->next != NULL) && ((NODE(newsn))->next != NULL))
|
|
||||||
{
|
|
||||||
if (!ipa_equal(oldsn->px.addr, newsn->px.addr) ||
|
|
||||||
(oldsn->px.len != newsn->px.len) ||
|
|
||||||
(oldsn->hidden != newsn->hidden) ||
|
|
||||||
(oldsn->summary != newsn->summary) ||
|
|
||||||
(oldsn->cost != newsn->cost))
|
|
||||||
break;
|
|
||||||
|
|
||||||
oldsn = (struct ospf_stubnet_config *)(NODE(oldsn))->next;
|
|
||||||
newsn = (struct ospf_stubnet_config *)(NODE(newsn))->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there is no change, both pointers should be NULL */
|
|
||||||
if (((NODE(oldsn))->next) != ((NODE(newsn))->next))
|
|
||||||
schedule_rt_lsa(oa);
|
|
||||||
|
|
||||||
/* Change net_list */
|
|
||||||
fib_free(&oa->net_fib);
|
|
||||||
add_area_nets(oa, newac);
|
|
||||||
|
|
||||||
if (!iface_patts_equal(&oldac->patt_list, &newac->patt_list,
|
|
||||||
(void *) ospf_patt_compare))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
WALK_LIST(ifa, po->iface_list)
|
|
||||||
{
|
|
||||||
/* FIXME: better handling of vlinks */
|
|
||||||
if (ifa->iface == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* FIXME: better matching of interface_id in OSPFv3 */
|
|
||||||
if (oldip = (struct ospf_iface_patt *)
|
|
||||||
iface_patt_find(&oldac->patt_list, ifa->iface, ifa->addr))
|
|
||||||
{
|
|
||||||
/* Now reconfigure interface */
|
|
||||||
if (!(newip = (struct ospf_iface_patt *)
|
|
||||||
iface_patt_find(&newac->patt_list, ifa->iface, ifa->addr)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* HELLO TIMER */
|
|
||||||
if (oldip->helloint != newip->helloint)
|
|
||||||
{
|
|
||||||
ifa->helloint = newip->helloint;
|
|
||||||
ifa->hello_timer->recurrent = ifa->helloint;
|
|
||||||
tm_start(ifa->hello_timer, ifa->helloint);
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing hello interval on interface %s from %d to %d",
|
|
||||||
ifa->iface->name, oldip->helloint, newip->helloint);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* POLL TIMER */
|
|
||||||
if ((oldip->pollint != newip->pollint) && ifa->poll_timer)
|
|
||||||
{
|
|
||||||
ifa->pollint = newip->helloint;
|
|
||||||
ifa->poll_timer->recurrent = ifa->pollint;
|
|
||||||
tm_start(ifa->poll_timer, ifa->pollint);
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing poll interval on interface %s from %d to %d",
|
|
||||||
ifa->iface->name, oldip->pollint, newip->pollint);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* COST */
|
|
||||||
if (oldip->cost != newip->cost)
|
|
||||||
{
|
|
||||||
ifa->cost = newip->cost;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing cost interface %s from %d to %d",
|
|
||||||
ifa->iface->name, oldip->cost, newip->cost);
|
|
||||||
schedule_rt_lsa(ifa->oa);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RX BUFF */
|
|
||||||
if (oldip->rxbuf != newip->rxbuf)
|
|
||||||
{
|
|
||||||
ifa->rxbuf = newip->rxbuf;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing rxbuf interface %s from %d to %d",
|
|
||||||
ifa->iface->name, oldip->rxbuf, newip->rxbuf);
|
|
||||||
ospf_iface_change_mtu(po, ifa);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* LINK */
|
|
||||||
if (oldip->check_link != newip->check_link)
|
|
||||||
{
|
|
||||||
ifa->check_link = newip->check_link;
|
|
||||||
|
|
||||||
if (!(ifa->iface->flags & IF_LINK_UP))
|
|
||||||
ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ECMP weight */
|
|
||||||
if (oldip->ecmp_weight != newip->ecmp_weight)
|
|
||||||
{
|
|
||||||
ifa->ecmp_weight = newip->ecmp_weight;
|
|
||||||
OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d",
|
|
||||||
ifa->iface->name, (int)oldip->ecmp_weight + 1, (int)newip->ecmp_weight + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* strict nbma */
|
|
||||||
if ((oldip->strictnbma == 0) && (newip->strictnbma != 0))
|
|
||||||
{
|
|
||||||
ifa->strictnbma = newip->strictnbma;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Interface %s is now strict NBMA.", ifa->iface->name);
|
|
||||||
}
|
|
||||||
if ((oldip->strictnbma != 0) && (newip->strictnbma == 0))
|
|
||||||
{
|
|
||||||
ifa->strictnbma = newip->strictnbma;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Interface %s is no longer strict NBMA.",
|
|
||||||
ifa->iface->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stub */
|
|
||||||
int old_stub = ospf_iface_stubby(oldip, ifa->addr);
|
|
||||||
int new_stub = ospf_iface_stubby(newip, ifa->addr);
|
|
||||||
if (!old_stub && new_stub)
|
|
||||||
{
|
|
||||||
ifa->stub = 1;
|
|
||||||
OSPF_TRACE(D_EVENTS, "Interface %s is now stub.", ifa->iface->name);
|
|
||||||
}
|
|
||||||
if (old_stub && !new_stub && (ifa->ioprob == OSPF_I_OK))
|
|
||||||
{
|
|
||||||
ifa->stub = 0;
|
|
||||||
OSPF_TRACE(D_EVENTS, "Interface %s is no longer stub.", ifa->iface->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef OSPFv2
|
|
||||||
/* AUTHENTICATION */
|
|
||||||
if (oldip->autype != newip->autype)
|
|
||||||
{
|
|
||||||
ifa->autype = newip->autype;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing authentication type on interface %s",
|
|
||||||
ifa->iface->name);
|
|
||||||
}
|
|
||||||
/* Add *passwords */
|
|
||||||
ifa->passwords = newip->passwords;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* priority */
|
|
||||||
if (oldip->priority != newip->priority)
|
|
||||||
{
|
|
||||||
ifa->priority = newip->priority;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing priority on interface %s from %d to %d",
|
|
||||||
ifa->iface->name, oldip->priority, newip->priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RXMT */
|
|
||||||
if (oldip->rxmtint != newip->rxmtint)
|
|
||||||
{
|
|
||||||
ifa->rxmtint = newip->rxmtint;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing retransmit interval on interface %s from %d to %d",
|
|
||||||
ifa->iface->name, oldip->rxmtint, newip->rxmtint);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* WAIT */
|
|
||||||
if ((oldip->waitint != newip->waitint) && ifa->wait_timer)
|
|
||||||
{
|
|
||||||
ifa->waitint = newip->waitint;
|
|
||||||
if (ifa->wait_timer->expires != 0)
|
|
||||||
tm_start(ifa->wait_timer, ifa->waitint);
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing wait interval on interface %s from %d to %d",
|
|
||||||
ifa->iface->name, oldip->waitint, newip->waitint);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* INFTRANS */
|
|
||||||
if (oldip->inftransdelay != newip->inftransdelay)
|
|
||||||
{
|
|
||||||
ifa->inftransdelay = newip->inftransdelay;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing transmit delay on interface %s from %d to %d",
|
|
||||||
ifa->iface->name, oldip->inftransdelay,
|
|
||||||
newip->inftransdelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DEAD */
|
|
||||||
olddead = (oldip->dead == 0) ? oldip->deadc * oldip->helloint : oldip->dead;
|
|
||||||
newdead = (newip->dead == 0) ? newip->deadc * newip->helloint : newip->dead;
|
|
||||||
if (olddead != newdead)
|
|
||||||
{
|
|
||||||
ifa->dead = newdead;
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Changing dead interval on interface %s from %d to %d",
|
|
||||||
ifa->iface->name, olddead, newdead);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NBMA LIST */
|
|
||||||
/* First remove old */
|
|
||||||
WALK_LIST_DELSAFE(nb1, nbnx, ifa->nbma_list)
|
|
||||||
{
|
|
||||||
nb2 = find_nbma_node_in(&newip->nbma_list, nb1->ip);
|
|
||||||
if (nb2)
|
|
||||||
{
|
|
||||||
if (nb1->eligible != nb2->eligible)
|
|
||||||
{
|
|
||||||
nb1->eligible = nb2->eligible;
|
|
||||||
OSPF_TRACE(D_EVENTS, "Changing neighbor eligibility %I on interface %s",
|
|
||||||
nb1->ip, ifa->iface->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Removing NBMA neighbor %I on interface %s",
|
|
||||||
nb1->ip, ifa->iface->name);
|
|
||||||
rem_node(NODE nb1);
|
|
||||||
mb_free(nb1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* And then add new */
|
|
||||||
WALK_LIST(nb2, newip->nbma_list)
|
|
||||||
{
|
|
||||||
if (!ipa_in_net(nb2->ip, ifa->addr->prefix, ifa->addr->pxlen))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (find_nbma_node(ifa, nb2->ip) == NULL)
|
|
||||||
{
|
|
||||||
nb1 = mb_alloc(ifa->pool, sizeof(struct nbma_node));
|
|
||||||
nb1->ip = nb2->ip;
|
|
||||||
nb1->eligible = nb2->eligible;
|
|
||||||
nb1->found = !!find_neigh_by_ip(ifa, nb1->ip);
|
|
||||||
add_tail(&ifa->nbma_list, NODE nb1);
|
|
||||||
OSPF_TRACE(D_EVENTS,
|
|
||||||
"Adding NBMA neighbor %I on interface %s",
|
|
||||||
nb1->ip, ifa->iface->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
oldac = (struct ospf_area_config *)(NODE(oldac))->next;
|
|
||||||
newac = (struct ospf_area_config *)(NODE(newac))->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((NODE(oldac))->next) != ((NODE(newac))->next))
|
/* Add and update vlinks */
|
||||||
return 0; /* One is not null */
|
WALK_LIST(ip, new->vlink_list)
|
||||||
|
{
|
||||||
|
ifa = ospf_find_vlink(po, ip->voa, ip->vid);
|
||||||
|
if (ifa)
|
||||||
|
ospf_iface_reconfigure(ifa, ip);
|
||||||
|
else
|
||||||
|
ospf_iface_new(po->backbone, NULL, ip);
|
||||||
|
}
|
||||||
|
|
||||||
return 1; /* Everything OK :-) */
|
/* Delete remaining ifaces and areas */
|
||||||
|
WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
|
||||||
|
if (ifa->marked)
|
||||||
|
{
|
||||||
|
ospf_iface_shutdown(ifa);
|
||||||
|
ospf_iface_remove(ifa);
|
||||||
|
}
|
||||||
|
|
||||||
|
WALK_LIST_DELSAFE(oa, oax, po->area_list)
|
||||||
|
if (oa->marked)
|
||||||
|
ospf_area_remove(oa);
|
||||||
|
|
||||||
|
schedule_rtcalc(po);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_sh_neigh(struct proto *p, char *iff)
|
ospf_sh_neigh(struct proto *p, char *iff)
|
||||||
{
|
{
|
||||||
|
|
|
@ -81,9 +81,11 @@ struct ospf_config
|
||||||
{
|
{
|
||||||
struct proto_config c;
|
struct proto_config c;
|
||||||
unsigned tick;
|
unsigned tick;
|
||||||
int rfc1583;
|
byte rfc1583;
|
||||||
|
byte abr;
|
||||||
int ecmp;
|
int ecmp;
|
||||||
list area_list;
|
list area_list;
|
||||||
|
list vlink_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nbma_node
|
struct nbma_node
|
||||||
|
@ -121,11 +123,10 @@ struct ospf_area_config
|
||||||
{
|
{
|
||||||
node n;
|
node n;
|
||||||
u32 areaid;
|
u32 areaid;
|
||||||
int stub;
|
u32 stub;
|
||||||
list patt_list;
|
list patt_list;
|
||||||
list vlink_list;
|
list net_list; /* List of aggregate networks for that area */
|
||||||
list net_list;
|
list stubnet_list; /* List of stub networks added to Router LSA */
|
||||||
list stubnet_list;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,6 +168,7 @@ struct ospf_iface
|
||||||
struct iface *iface; /* Nest's iface */
|
struct iface *iface; /* Nest's iface */
|
||||||
struct ifa *addr; /* IP prefix associated with that OSPF iface */
|
struct ifa *addr; /* IP prefix associated with that OSPF iface */
|
||||||
struct ospf_area *oa;
|
struct ospf_area *oa;
|
||||||
|
struct ospf_iface_patt *cf;
|
||||||
pool *pool;
|
pool *pool;
|
||||||
sock *sk; /* IP socket (for DD ...) */
|
sock *sk; /* IP socket (for DD ...) */
|
||||||
list neigh_list; /* List of neigbours */
|
list neigh_list; /* List of neigbours */
|
||||||
|
@ -174,7 +176,7 @@ struct ospf_iface
|
||||||
u32 waitint; /* number of sec before changing state from wait */
|
u32 waitint; /* number of sec before changing state from wait */
|
||||||
u32 rxmtint; /* number of seconds between LSA retransmissions */
|
u32 rxmtint; /* number of seconds between LSA retransmissions */
|
||||||
u32 pollint; /* Poll interval */
|
u32 pollint; /* Poll interval */
|
||||||
u32 dead; /* after "deadint" missing hellos is router dead */
|
u32 deadint; /* after "deadint" missing hellos is router dead */
|
||||||
u32 vid; /* Id of peer of virtual link */
|
u32 vid; /* Id of peer of virtual link */
|
||||||
ip_addr vip; /* IP of peer of virtual link */
|
ip_addr vip; /* IP of peer of virtual link */
|
||||||
struct ospf_iface *vifa; /* OSPF iface which the vlink goes through */
|
struct ospf_iface *vifa; /* OSPF iface which the vlink goes through */
|
||||||
|
@ -252,8 +254,8 @@ struct ospf_iface
|
||||||
#define OSPF_I_OK 0 /* Everything OK */
|
#define OSPF_I_OK 0 /* Everything OK */
|
||||||
#define OSPF_I_SK 1 /* Socket open failed */
|
#define OSPF_I_SK 1 /* Socket open failed */
|
||||||
#define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */
|
#define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */
|
||||||
// u8 sk_spf; /* Socket is a member of SPFRouters group */
|
|
||||||
u8 sk_dr; /* Socket is a member of DRouters group */
|
u8 sk_dr; /* Socket is a member of DRouters group */
|
||||||
|
u8 marked; /* Used in OSPF reconfigure */
|
||||||
u16 rxbuf; /* Buffer size */
|
u16 rxbuf; /* Buffer size */
|
||||||
u8 check_link; /* Whether iface link change is used */
|
u8 check_link; /* Whether iface link change is used */
|
||||||
u8 ecmp_weight; /* Weight used for ECMP */
|
u8 ecmp_weight; /* Weight used for ECMP */
|
||||||
|
@ -715,14 +717,15 @@ struct ospf_area
|
||||||
node n;
|
node n;
|
||||||
u32 areaid;
|
u32 areaid;
|
||||||
struct ospf_area_config *ac; /* Related area config, might be NULL */
|
struct ospf_area_config *ac; /* Related area config, might be NULL */
|
||||||
int origrt; /* Rt lsa origination scheduled? */
|
|
||||||
struct top_hash_entry *rt; /* My own router LSA */
|
struct top_hash_entry *rt; /* My own router LSA */
|
||||||
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
|
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
|
||||||
list cand; /* List of candidates for RT calc. */
|
list cand; /* List of candidates for RT calc. */
|
||||||
struct fib net_fib; /* Networks to advertise or not */
|
struct fib net_fib; /* Networks to advertise or not */
|
||||||
unsigned stub;
|
u32 stub; /* 0 or stub area cost */
|
||||||
int trcap; /* Transit capability? */
|
|
||||||
u32 options; /* Optional features */
|
u32 options; /* Optional features */
|
||||||
|
byte origrt; /* Rt lsa origination scheduled? */
|
||||||
|
byte trcap; /* Transit capability? */
|
||||||
|
byte marked; /* Used in OSPF reconfigure */
|
||||||
struct proto_ospf *po;
|
struct proto_ospf *po;
|
||||||
struct fib rtr; /* Routing tables for routers */
|
struct fib rtr; /* Routing tables for routers */
|
||||||
};
|
};
|
||||||
|
@ -753,18 +756,20 @@ struct proto_ospf
|
||||||
struct ospf_iface_patt
|
struct ospf_iface_patt
|
||||||
{
|
{
|
||||||
struct iface_patt i;
|
struct iface_patt i;
|
||||||
|
u32 type;
|
||||||
|
u32 stub;
|
||||||
u32 cost;
|
u32 cost;
|
||||||
u32 helloint;
|
u32 helloint;
|
||||||
u32 rxmtint;
|
u32 rxmtint;
|
||||||
u32 pollint;
|
u32 pollint;
|
||||||
u32 inftransdelay;
|
|
||||||
u32 priority;
|
|
||||||
u32 waitint;
|
u32 waitint;
|
||||||
u32 deadc;
|
u32 deadc;
|
||||||
u32 dead;
|
u32 deadint;
|
||||||
u32 type;
|
u32 inftransdelay;
|
||||||
|
u32 priority;
|
||||||
u32 strictnbma;
|
u32 strictnbma;
|
||||||
u32 stub;
|
list nbma_list;
|
||||||
|
u32 voa;
|
||||||
u32 vid;
|
u32 vid;
|
||||||
u16 rxbuf;
|
u16 rxbuf;
|
||||||
u8 check_link;
|
u8 check_link;
|
||||||
|
@ -772,9 +777,7 @@ struct ospf_iface_patt
|
||||||
#define OSPF_RXBUF_NORMAL 0
|
#define OSPF_RXBUF_NORMAL 0
|
||||||
#define OSPF_RXBUF_LARGE 1
|
#define OSPF_RXBUF_LARGE 1
|
||||||
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
|
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
|
||||||
list nbma_list;
|
u32 autype; /* Not really used in OSPFv3 */
|
||||||
|
|
||||||
u32 autype; /* Not really used in OSPFv3 */
|
|
||||||
#define OSPF_AUTH_NONE 0
|
#define OSPF_AUTH_NONE 0
|
||||||
#define OSPF_AUTH_SIMPLE 1
|
#define OSPF_AUTH_SIMPLE 1
|
||||||
#define OSPF_AUTH_CRYPT 2
|
#define OSPF_AUTH_CRYPT 2
|
||||||
|
@ -789,24 +792,6 @@ struct ospf_iface_patt
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
|
|
||||||
static inline int
|
|
||||||
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We cannot properly support multiple OSPF ifaces on real iface
|
|
||||||
* with multiple prefixes, therefore we force OSPF ifaces with
|
|
||||||
* non-primary IP prefixes to be stub.
|
|
||||||
*/
|
|
||||||
return ip->stub || !(addr->flags & IA_PRIMARY);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline int
|
|
||||||
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr UNUSED)
|
|
||||||
{
|
|
||||||
return ip->stub;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
|
int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
|
||||||
struct linpool *pool);
|
struct linpool *pool);
|
||||||
|
@ -816,6 +801,8 @@ void schedule_rt_lsa(struct ospf_area *oa);
|
||||||
void schedule_rtcalc(struct proto_ospf *po);
|
void schedule_rtcalc(struct proto_ospf *po);
|
||||||
void schedule_net_lsa(struct ospf_iface *ifa);
|
void schedule_net_lsa(struct ospf_iface *ifa);
|
||||||
|
|
||||||
|
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
|
||||||
|
|
||||||
#ifdef OSPFv3
|
#ifdef OSPFv3
|
||||||
void schedule_link_lsa(struct ospf_iface *ifa);
|
void schedule_link_lsa(struct ospf_iface *ifa);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1176,6 +1176,7 @@ static void *
|
||||||
originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
|
originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
|
||||||
{
|
{
|
||||||
struct proto_ospf *po = oa->po;
|
struct proto_ospf *po = oa->po;
|
||||||
|
struct ospf_config *cf = (struct ospf_config *) (po->proto.cf);
|
||||||
struct ospf_iface *ifa;
|
struct ospf_iface *ifa;
|
||||||
struct ospf_lsa_prefix *lp;
|
struct ospf_lsa_prefix *lp;
|
||||||
struct ifa *vlink_addr = NULL;
|
struct ifa *vlink_addr = NULL;
|
||||||
|
@ -1234,7 +1235,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
|
||||||
|
|
||||||
/* If there are some configured vlinks, add some global address,
|
/* If there are some configured vlinks, add some global address,
|
||||||
which will be used as a vlink endpoint. */
|
which will be used as a vlink endpoint. */
|
||||||
if (oa->ac && !EMPTY_LIST(oa->ac->vlink_list) && !host_addr && vlink_addr)
|
if (!EMPTY_LIST(cf->vlink_list) && !host_addr && vlink_addr)
|
||||||
{
|
{
|
||||||
lsa_put_prefix(po, vlink_addr->ip, MAX_PREFIX_LENGTH, 0);
|
lsa_put_prefix(po, vlink_addr->ip, MAX_PREFIX_LENGTH, 0);
|
||||||
i++;
|
i++;
|
||||||
|
|
Loading…
Reference in a new issue