From 525c183906c47c491611f294db218d53a561a3b9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 19 May 2015 17:58:13 -0700 Subject: [PATCH] Unnumbered interface support. --- lib/if.c | 30 ++++++++++++++++++++++ lib/if.h | 10 +++++++- lib/zebra.h | 1 + ospfd/ospf_interface.c | 13 +++++++--- ospfd/ospf_lsa.c | 39 +++++++++++++++++++--------- ospfd/ospf_route.c | 4 +++ ospfd/ospf_route.h | 1 + ospfd/ospf_vty.c | 55 ++++++++++++++++++++++----------------- ospfd/ospf_zebra.c | 43 +++++++++++++++++++++++++++++-- zebra/connected.c | 58 ++++++++++++++++++++++++++++++++++++++++-- zebra/connected.h | 3 +++ zebra/interface.c | 4 +++ 12 files changed, 217 insertions(+), 44 deletions(-) diff --git a/lib/if.c b/lib/if.c index b3decf3be9..4800105dc0 100644 --- a/lib/if.c +++ b/lib/if.c @@ -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) diff --git a/lib/if.h b/lib/if.h index 287d26cf97..8014fb56cd 100644 --- a/lib/if.h +++ b/lib/if.h @@ -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: */ diff --git a/lib/zebra.h b/lib/zebra.h index 4e976eb107..6e73ee3dbf 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -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 diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 0f02cc821a..6c330e95dc 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -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) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index eabfa7b689..1de03440ce 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -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; } diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index eb7829acdf..7efba7a8c0 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -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); } } diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h index 6c202b0ccd..4de3a3da16 100644 --- a/ospfd/ospf_route.h +++ b/ospfd/ospf_route.h @@ -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 diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 872318e974..84251fe44b 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -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) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 3785278241..9a35253795 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -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); } } diff --git a/zebra/connected.c b/zebra/connected.c index 4d6224cc9b..ef1792c2f5 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -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(); diff --git a/zebra/connected.h b/zebra/connected.h index 9595ddb1bf..55709440c6 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -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 *); diff --git a/zebra/interface.c b/zebra/interface.c index 9f7ec0a527..9a1259c73a 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -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); -- 2.39.5