Unnumbered interface support.

This commit is contained in:
Donald Sharp 2015-05-19 17:58:13 -07:00
parent c8a1cb5c9d
commit 525c183906
12 changed files with 217 additions and 44 deletions

View File

@ -315,6 +315,36 @@ if_lookup_address (struct in_addr src)
return match;
}
/* Lookup anchor interface by IPv4 address. */
struct connected *
if_anchor_lookup_by_address (struct in_addr src)
{
struct listnode *node;
struct listnode *cnode;
struct interface *ifp;
struct prefix *p;
struct connected *c;
for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
{
if (CHECK_FLAG(c->flags, ZEBRA_IFA_UNNUMBERED) ||
!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
continue;
p = c->address;
if (p && p->family == AF_INET)
{
if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
return c;
}
}
}
return NULL;
}
/* Lookup interface by prefix */
struct interface *
if_lookup_prefix (struct prefix *prefix)

View File

@ -90,7 +90,7 @@ struct interface
#define ZEBRA_INTERFACE_ACTIVE (1 << 0)
#define ZEBRA_INTERFACE_SUB (1 << 1)
#define ZEBRA_INTERFACE_LINKDETECTION (1 << 2)
/* Interface flags. */
uint64_t flags;
@ -173,6 +173,7 @@ struct connected
u_char flags;
#define ZEBRA_IFA_SECONDARY (1 << 0)
#define ZEBRA_IFA_PEER (1 << 1)
#define ZEBRA_IFA_UNNUMBERED (1 << 2)
/* N.B. the ZEBRA_IFA_PEER flag should be set if and only if
a peer address has been configured. If this flag is set,
the destination field must contain the peer address.
@ -187,6 +188,12 @@ struct connected
Note: destination may be NULL if ZEBRA_IFA_PEER is not set. */
struct prefix *destination;
/* A list of unnumbered IFCs borrowing the address from me */
struct list *unnumbered;
/* Pointer to the anchor IFC if I'm unnumbered */
struct connected *anchor;
/* Label for Linux 2.2.X and upper. */
char *label;
};
@ -262,6 +269,7 @@ extern struct interface *if_lookup_by_index (unsigned int);
extern struct interface *if_lookup_exact_address (struct in_addr);
extern struct interface *if_lookup_address (struct in_addr);
extern struct interface *if_lookup_prefix (struct prefix *prefix);
extern struct connected *if_anchor_lookup_by_address (struct in_addr src);
/* These 2 functions are to be used when the ifname argument is terminated
by a '\0' character: */

View File

@ -482,6 +482,7 @@ extern const char *zserv_command_string (unsigned int command);
#define ZEBRA_FLAG_CHANGED 0x20
#define ZEBRA_FLAG_STATIC 0x40
#define ZEBRA_FLAG_REJECT 0x80
#define ZEBRA_FLAG_SCOPE_LINK 0x100
/* Zebra nexthop flags. */
#define ZEBRA_NEXTHOP_IFINDEX 1

View File

@ -353,7 +353,12 @@ ospf_if_is_configured (struct ospf *ospf, struct in_addr *address)
for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
{
if (oi->type == OSPF_IFTYPE_POINTOPOINT)
if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
{
if (htonl(oi->ifp->ifindex) == address->s_addr)
return oi;
}
else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
{
/* special leniency: match if addr is anywhere on peer subnet */
if (prefix_match(CONNECTED_PREFIX(oi->connected),
@ -477,8 +482,10 @@ ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr src,
if (if_is_loopback (oi->ifp))
continue;
if (prefix_match (CONNECTED_PREFIX(oi->connected),
(struct prefix *) &addr))
if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
match = oi;
else if (prefix_match (CONNECTED_PREFIX(oi->connected),
(struct prefix *) &addr))
{
if ( (match == NULL) ||
(match->address->prefixlen < oi->address->prefixlen)

View File

@ -532,7 +532,7 @@ lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi)
{
int links = 0;
struct ospf_neighbor *nbr;
struct in_addr id, mask;
struct in_addr id, mask, data;
u_int16_t cost = ospf_link_cost (oi);
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
@ -541,19 +541,34 @@ lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi)
if ((nbr = ospf_nbr_lookup_ptop (oi)))
if (nbr->state == NSM_Full)
{
/* For unnumbered point-to-point networks, the Link Data field
should specify the interface's MIB-II ifIndex value. */
links += link_info_set (s, nbr->router_id, oi->address->u.prefix4,
LSA_LINK_TYPE_POINTOPOINT, 0, cost);
if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
{
/* For unnumbered point-to-point networks, the Link Data field
should specify the interface's MIB-II ifIndex value. */
data.s_addr = htonl(oi->ifp->ifindex);
links += link_info_set (s, nbr->router_id, data,
LSA_LINK_TYPE_POINTOPOINT, 0, cost);
}
else
{
links += link_info_set (s, nbr->router_id,
oi->address->u.prefix4,
LSA_LINK_TYPE_POINTOPOINT, 0, cost);
}
}
/* Regardless of the state of the neighboring router, we must
add a Type 3 link (stub network).
N.B. Options 1 & 2 share basically the same logic. */
masklen2ip (oi->address->prefixlen, &mask);
id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & mask.s_addr;
links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
oi->output_cost);
/* no need for a stub link for unnumbered interfaces */
if (!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
{
/* Regardless of the state of the neighboring router, we must
add a Type 3 link (stub network).
N.B. Options 1 & 2 share basically the same logic. */
masklen2ip (oi->address->prefixlen, &mask);
id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & mask.s_addr;
links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
oi->output_cost);
}
return links;
}

View File

@ -611,6 +611,8 @@ ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link,
path = ospf_path_new ();
path->nexthop.s_addr = 0;
path->ifindex = oi->ifp->ifindex;
if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
path->unnumbered = 1;
listnode_add (or->paths, path);
}
else
@ -783,6 +785,8 @@ ospf_route_copy_nexthops_from_vertex (struct ospf_route *to,
path = ospf_path_new ();
path->nexthop = nexthop->router;
path->ifindex = nexthop->oi->ifp->ifindex;
if (CHECK_FLAG(nexthop->oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
path->unnumbered = 1;
listnode_add (to->paths, path);
}
}

View File

@ -40,6 +40,7 @@ struct ospf_path
struct in_addr nexthop;
struct in_addr adv_router;
unsigned int ifindex;
unsigned char unnumbered;
};
/* Below is the structure linked to every

View File

@ -2889,30 +2889,37 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf,
if (oi == NULL)
continue;
/* Show OSPF interface information. */
vty_out (vty, " Internet Address %s/%d,",
inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen);
if (oi->connected->destination || oi->type == OSPF_IFTYPE_VIRTUALLINK)
if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
{
struct in_addr *dest;
const char *dstr;
if (CONNECTED_PEER(oi->connected)
|| oi->type == OSPF_IFTYPE_VIRTUALLINK)
dstr = "Peer";
else
dstr = "Broadcast";
/* For Vlinks, showing the peer address is probably more
* informative than the local interface that is being used
*/
if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
dest = &oi->vl_data->peer_addr;
else
dest = &oi->connected->destination->u.prefix4;
vty_out (vty, " %s %s,", dstr, inet_ntoa (*dest));
vty_out (vty, " This interface is UNNUMBERED,");
}
else
{
/* Show OSPF interface information. */
vty_out (vty, " Internet Address %s/%d,",
inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen);
if (oi->connected->destination || oi->type == OSPF_IFTYPE_VIRTUALLINK)
{
struct in_addr *dest;
const char *dstr;
if (CONNECTED_PEER(oi->connected)
|| oi->type == OSPF_IFTYPE_VIRTUALLINK)
dstr = "Peer";
else
dstr = "Broadcast";
/* For Vlinks, showing the peer address is probably more
* informative than the local interface that is being used
*/
if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
dest = &oi->vl_data->peer_addr;
else
dest = &oi->connected->destination->u.prefix4;
vty_out (vty, " %s %s,", dstr, inet_ntoa (*dest));
}
}
vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area),
@ -2964,7 +2971,7 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf,
inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE);
}
}
/* Next network-LSA sequence number we'll use, if we're elected DR */
if (oi->params && ntohl (oi->params->network_lsa_seqnum)
!= OSPF_INITIAL_SEQUENCE_NUMBER)

View File

@ -383,6 +383,9 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
struct stream *s;
struct ospf_path *path;
struct listnode *node;
#ifdef HAVE_NETLINK
int ol_cnt = 0, not_ol_cnt = 0;
#endif /* HAVE_NETLINK */
if (zclient->redist[ZEBRA_ROUTE_OSPF])
{
@ -426,6 +429,40 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
/* Nexthop, ifindex, distance and metric information. */
for (ALL_LIST_ELEMENTS_RO (or->paths, node, path))
{
#ifdef HAVE_NETLINK
if (path->unnumbered)
{
stream_putc (s, ZEBRA_NEXTHOP_IPV4_ONLINK);
stream_put_in_addr (s, &path->nexthop);
if (path->ifindex)
stream_putl (s, path->ifindex);
else
stream_putl (s, 0);
}
else
{
if (path->nexthop.s_addr != INADDR_ANY &&
path->ifindex != 0)
{
stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX);
stream_put_in_addr (s, &path->nexthop);
stream_putl (s, path->ifindex);
}
else if (path->nexthop.s_addr != INADDR_ANY)
{
stream_putc (s, ZEBRA_NEXTHOP_IPV4);
stream_put_in_addr (s, &path->nexthop);
}
else
{
stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
if (path->ifindex)
stream_putl (s, path->ifindex);
else
stream_putl (s, 0);
}
}
#else /* HAVE_NETLINK */
if (path->nexthop.s_addr != INADDR_ANY &&
path->ifindex != 0)
{
@ -446,16 +483,18 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
else
stream_putl (s, 0);
}
#endif /* HAVE_NETLINK */
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
{
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra: Route add %s/%d nexthop %s",
zlog_debug("Zebra: Route add %s/%d nexthop %s, ifindex=%d",
inet_ntop(AF_INET, &p->prefix,
buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET, &path->nexthop,
buf[1], sizeof(buf[1])));
buf[1], sizeof(buf[1])),
path->ifindex);
}
}

View File

@ -77,7 +77,23 @@ connected_announce (struct interface *ifp, struct connected *ifc)
{
if (!ifc)
return;
if (ifc->address->family == AF_INET)
{
if (ifc->anchor = if_anchor_lookup_by_address(ifc->address->u.prefix4))
{
/* found an anchor, so I'm unnumbered */
SET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED);
listnode_add (ifc->anchor->unnumbered, ifc);
}
else
{
/* I'm numbered */
UNSET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED);
ifc->unnumbered = list_new();
}
}
listnode_add (ifp->connected, ifc);
/* Update interface address information to protocol daemon. */
@ -314,6 +330,42 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
rib_update ();
}
void
connected_delete_ipv4_unnumbered (struct connected *ifc)
{
struct connected *new_anchor, *iter;
struct listnode *node;
if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED))
{
listnode_delete (ifc->anchor->unnumbered, ifc);
ifc->anchor = NULL;
}
else /* I'm a numbered interface */
{
if (!list_isempty (ifc->unnumbered))
{
new_anchor = listgetdata (listhead (ifc->unnumbered));
new_anchor->unnumbered = ifc->unnumbered;
listnode_delete (new_anchor->unnumbered, new_anchor);
new_anchor->anchor = NULL;
/* new_anchor changed from unnumbered to numbered, notify clients */
zebra_interface_address_delete_update (new_anchor->ifp, new_anchor);
UNSET_FLAG (new_anchor->flags, ZEBRA_IFA_UNNUMBERED);
zebra_interface_address_add_update (new_anchor->ifp, new_anchor);
for (ALL_LIST_ELEMENTS_RO(new_anchor->unnumbered, node, iter))
iter->anchor = new_anchor;
}
else
{
list_free (ifc->unnumbered);
ifc->unnumbered = NULL;
}
}
}
/* Delete connected IPv4 route to the interface. */
void
connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
@ -330,7 +382,9 @@ connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
ifc = connected_check (ifp, (struct prefix *) &p);
if (! ifc)
return;
connected_delete_ipv4_unnumbered (ifc);
connected_withdraw (ifc);
rib_update();

View File

@ -35,6 +35,9 @@ extern void
connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
u_char prefixlen, struct in_addr *broad);
extern void
connected_delete_ipv4_unnumbered (struct connected *ifc);
extern void connected_up_ipv4 (struct interface *, struct connected *);
extern void connected_down_ipv4 (struct interface *, struct connected *);

View File

@ -472,6 +472,7 @@ if_delete_update (struct interface *ifp)
UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
connected_delete_ipv4_unnumbered(ifc);
/* Remove from subnet chain. */
list_delete_node (addr_list, anode);
@ -654,6 +655,9 @@ connected_dump_vty (struct vty *vty, struct connected *connected)
if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY))
vty_out (vty, " secondary");
if (CHECK_FLAG (connected->flags, ZEBRA_IFA_UNNUMBERED))
vty_out (vty, " unnumbered");
if (connected->label)
vty_out (vty, " %s", connected->label);