/* Interface's address information get. */ int ifam_read (struct ifa_msghdr *ifam) { struct interface *ifp; union sockunion addr, mask, gate; /* Check does this interface exist or not. */ ifp = if_lookup_by_index (ifam->ifam_index); if (ifp == NULL) { zlog_warn ("no interface for index %d", ifam->ifam_index); return -1; } /* Allocate and read address information. */ ifam_read_mesg (ifam, &addr, &mask, &gate); /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); /* Add connected address. */ switch (sockunion_family (&addr)) { case AF_INET: if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &gate.sin.sin_addr, NULL); else connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &gate.sin.sin_addr, NULL); break; #ifdef HAVE_IPV6 case AF_INET6: /* Unset interface index from link-local address when IPv6 stack is KAME. */ if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &gate.sin6.sin6_addr); else connected_delete_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &gate.sin6.sin6_addr); break; #endif /* HAVE_IPV6 */ default: /* Unsupported family silently ignore... */ break; } return 0; }
static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry) { struct prefix prefix; struct in_addr tmpaddr; struct nexthop nh; uint8_t zebra_flags = 0; if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) return; if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT) zebra_flags |= ZEBRA_FLAG_SELFROUTE; prefix.family = AF_INET; tmpaddr.s_addr = routeEntry->ipRouteDest; prefix.u.prefix4 = tmpaddr; tmpaddr.s_addr = routeEntry->ipRouteMask; prefix.prefixlen = ip_masklen(tmpaddr); memset(&nh, 0, sizeof(nh)); nh.vrf_id = VRF_DEFAULT; nh.type = NEXTHOP_TYPE_IPV4; nh.gate.ipv4.s_addr = routeEntry->ipRouteNextHop; rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0, 0); }
/* Utility function of convert between struct prefix <=> union sockunion. * FIXME This function isn't used anywhere. */ struct prefix * sockunion2prefix (const union sockunion *dest, const union sockunion *mask) { if (dest->sa.sa_family == AF_INET) { struct prefix_ipv4 *p; p = prefix_ipv4_new (); p->family = AF_INET; p->prefix = dest->sin.sin_addr; p->prefixlen = ip_masklen (mask->sin.sin_addr); return (struct prefix *) p; } #ifdef HAVE_IPV6 if (dest->sa.sa_family == AF_INET6) { struct prefix_ipv6 *p; p = prefix_ipv6_new (); p->family = AF_INET6; p->prefixlen = ip6_masklen (mask->sin6.sin6_addr); memcpy (&p->prefix, &dest->sin6.sin6_addr, sizeof (struct in6_addr)); return (struct prefix *) p; } #endif /* HAVE_IPV6 */ return NULL; }
/* Check LSA is related to external info. */ struct external_info * ospf_external_info_check (struct ospf_lsa *lsa) { struct as_external_lsa *al; struct prefix_ipv4 p; struct route_node *rn; int type; al = (struct as_external_lsa *) lsa->data; p.family = AF_INET; p.prefix = lsa->data->id; p.prefixlen = ip_masklen (al->mask); for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { int redist_type = is_prefix_default (&p) ? DEFAULT_ROUTE : type; if (ospf_is_type_redistributed (redist_type)) if (EXTERNAL_INFO (type)) { rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); if (rn) { route_unlock_node (rn); if (rn->info != NULL) return (struct external_info *) rn->info; } } } return NULL; }
void handle_route_entry (mib2_ipRouteEntry_t *routeEntry) { struct prefix_ipv4 prefix; struct in_addr tmpaddr, gateway; u_char zebra_flags = 0; if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) return; if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT) zebra_flags |= ZEBRA_FLAG_SELFROUTE; prefix.family = AF_INET; tmpaddr.s_addr = routeEntry->ipRouteDest; prefix.prefix = tmpaddr; tmpaddr.s_addr = routeEntry->ipRouteMask; prefix.prefixlen = ip_masklen (tmpaddr); gateway.s_addr = routeEntry->ipRouteNextHop; rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, &gateway, 0, 0, 0, 0); }
static int process_transit_summary_lsa(struct ospf_area *area, struct route_table *rt, struct route_table *rtrs, struct ospf_lsa *lsa) { struct ospf *ospf = area->ospf; struct summary_lsa *sl; struct prefix_ipv4 p; uint32_t metric; if (lsa == NULL) return 0; sl = (struct summary_lsa *)lsa->data; if (IS_DEBUG_OSPF_EVENT) zlog_debug("process_transit_summaries(): LS ID: %s", inet_ntoa(lsa->data->id)); metric = GET_METRIC(sl->metric); if (metric == OSPF_LS_INFINITY) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( "process_transit_summaries(): metric is infinity, skip"); return 0; } if (IS_LSA_MAXAGE(lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( "process_transit_summaries(): This LSA is too old"); return 0; } if (ospf_lsa_is_self_originated(area->ospf, lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( "process_transit_summaries(): This LSA is mine, skip"); return 0; } p.family = AF_INET; p.prefix = sl->header.id; if (sl->header.type == OSPF_SUMMARY_LSA) p.prefixlen = ip_masklen(sl->mask); else p.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4(&p); if (sl->header.type == OSPF_SUMMARY_LSA) ospf_update_network_route(ospf, rt, rtrs, sl, &p, area); else ospf_update_router_route(ospf, rtrs, sl, &p, area); return 0; }
int process_transit_summary_lsa (struct ospf_lsa *l, void *v, int i) { struct summary_lsa *sl; struct prefix_ipv4 p; u_int32_t metric; struct ia_args *args; if (l == NULL) return 0; args = (struct ia_args *) v; sl = (struct summary_lsa *) l->data; if (IS_DEBUG_OSPF_EVENT) zlog_info ("process_transit_summaries(): LS ID: %s", inet_ntoa (l->data->id)); metric = GET_METRIC (sl->metric); if (metric == OSPF_LS_INFINITY) { if (IS_DEBUG_OSPF_EVENT) zlog_info ("process_transit_summaries(): metric is infinity, skip"); return 0; } if (IS_LSA_MAXAGE (l)) { if (IS_DEBUG_OSPF_EVENT) zlog_info ("process_transit_summaries(): This LSA is too old"); return 0; } if (ospf_lsa_is_self_originated (l)) { if (IS_DEBUG_OSPF_EVENT) zlog_info ("process_transit_summaries(): This LSA is mine, skip"); return 0; } p.family = AF_INET; p.prefix = sl->header.id; if (sl->header.type == OSPF_SUMMARY_LSA) p.prefixlen = ip_masklen (sl->mask); else p.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&p); if (sl->header.type == OSPF_SUMMARY_LSA) ospf_update_network_route (args->rt, args->rtrs, sl, &p, args->area); else ospf_update_router_route (args->rtrs, sl, &p, args->area); return 0; }
/* Kernel routing table read up by /proc filesystem. */ int proc_route_read () { FILE *fp; char buf[RT_BUFSIZ]; char iface[INTERFACE_NAMSIZ], dest[9], gate[9], mask[9]; int flags, refcnt, use, metric, mtu, window, rtt; /* Open /proc filesystem */ fp = fopen (_PATH_PROCNET_ROUTE, "r"); if (fp == NULL) { zlog_warn ("Can't open %s : %s\n", _PATH_PROCNET_ROUTE, strerror (errno)); return -1; } /* Drop first label line. */ fgets (buf, RT_BUFSIZ, fp); while (fgets (buf, RT_BUFSIZ, fp) != NULL) { int n; struct prefix_ipv4 p; struct in_addr tmpmask; struct in_addr gateway; u_char zebra_flags = 0; n = sscanf (buf, "%s %s %s %x %d %d %d %s %d %d %d", iface, dest, gate, &flags, &refcnt, &use, &metric, mask, &mtu, &window, &rtt); if (n != 11) { zlog_warn ("can't read all of routing information\n"); continue; } if (! (flags & RTF_UP)) continue; if (! (flags & RTF_GATEWAY)) continue; if (flags & RTF_DYNAMIC) zebra_flags |= ZEBRA_FLAG_SELFROUTE; p.family = AF_INET; sscanf (dest, "%lX", (unsigned long *)&p.prefix); sscanf (mask, "%lX", (unsigned long *)&tmpmask); p.prefixlen = ip_masklen (tmpmask); sscanf (gate, "%lX", (unsigned long *)&gateway); //2006/4/13 trenchen : when kernel route, save metric info. //rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, 0, 0); rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, metric, 0); } return 0; }
/* Check LSA is related to external info. */ struct external_info *ospf_external_info_check(struct ospf *ospf, struct ospf_lsa *lsa) { struct as_external_lsa *al; struct prefix_ipv4 p; struct route_node *rn; int type; al = (struct as_external_lsa *)lsa->data; p.family = AF_INET; p.prefix = lsa->data->id; p.prefixlen = ip_masklen(al->mask); for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { int redist_on = 0; redist_on = is_prefix_default(&p) ? vrf_bitmap_check(zclient->default_information, ospf->vrf_id) : (zclient->mi_redist[AFI_IP][type].enabled || vrf_bitmap_check( zclient->redist[AFI_IP][type], ospf->vrf_id)); // Pending: check for MI above. if (redist_on) { struct list *ext_list; struct listnode *node; struct ospf_external *ext; ext_list = ospf->external[type]; if (!ext_list) continue; for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { rn = NULL; if (ext->external_info) rn = route_node_lookup( ext->external_info, (struct prefix *)&p); if (rn) { route_unlock_node(rn); if (rn->info != NULL) return (struct external_info *) rn->info; } } } } return NULL; }
/* Utility function to convert ipv4 netmask to prefixes ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16" ex.) "1.0.0.0" NULL => "1.0.0.0/8" */ int netmask_str2prefix_str (const char *net_str, const char *mask_str, char *prefix_str) { struct in_addr network; struct in_addr mask; u_char prefixlen; u_int32_t destination; int ret; ret = inet_aton (net_str, &network); if (! ret) return 0; if (mask_str) { ret = inet_aton (mask_str, &mask); if (! ret) return 0; prefixlen = ip_masklen (mask); } else { destination = ntohl (network.s_addr); if (network.s_addr == 0) prefixlen = 0; else if (IN_CLASSC (destination)) prefixlen = 24; else if (IN_CLASSB (destination)) prefixlen = 16; else if (IN_CLASSA (destination)) prefixlen = 8; else return 0; } sprintf (prefix_str, "%s/%d", net_str, prefixlen); return 1; }
/* * C.2.6 Step 1 */ static int isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, uint32_t cost, uint16_t depth, int family) { struct listnode *node, *fragnode = NULL; u_int16_t dist; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct ipv4_reachability *ipreach; struct te_ipv4_reachability *te_ipv4_reach; enum vertextype vtype; struct prefix prefix; #ifdef HAVE_IPV6 struct ipv6_reachability *ip6reach; #endif /* HAVE_IPV6 */ if (!lsp->adj) return ISIS_WARNING; if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family)) return ISIS_OK; lspfragloop: if (lsp->lsp_header->seq_num == 0) { zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num" " - do not process"); return ISIS_WARNING; } if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) { if (lsp->tlv_data.is_neighs) { for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) { /* C.2.6 a) */ /* Two way connectivity */ if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + is_neigh->metrics.metric_default; vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS : VTYPE_NONPSEUDO_IS; process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, depth + 1, lsp->adj, family); } } if (lsp->tlv_data.te_is_neighs) { for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh)) { uint32_t metric; if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) continue; memcpy (&metric, te_is_neigh->te_metric, 3); dist = cost + ntohl (metric << 8); vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS : VTYPE_NONPSEUDO_TE_IS; process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, depth + 1, lsp->adj, family); } } if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach)) { dist = cost + ipreach->metrics.metric_default; vtype = VTYPE_IPREACH_INTERNAL; prefix.u.prefix4 = ipreach->prefix; prefix.prefixlen = ip_masklen (ipreach->mask); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, lsp->adj, family); } } if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach)) { dist = cost + ipreach->metrics.metric_default; vtype = VTYPE_IPREACH_EXTERNAL; prefix.u.prefix4 = ipreach->prefix; prefix.prefixlen = ip_masklen (ipreach->mask); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, lsp->adj, family); } }
/* General fucntion for static route. */ int zebra_static_ipv4 (struct vty *vty, int add_cmd, char *dest_str, char *mask_str, char *gate_str, char *distance_str) { int ret; u_char distance; struct prefix p; struct in_addr gate; struct in_addr mask; char *ifname; ret = str2prefix (dest_str, &p); if (ret <= 0) { vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } /* Cisco like mask notation. */ if (mask_str) { ret = inet_aton (mask_str, &mask); if (ret == 0) { vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } p.prefixlen = ip_masklen (mask); } /* Apply mask for given prefix. */ apply_mask (&p); /* Administrative distance. */ if (distance_str) distance = atoi (distance_str); else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; /* Null0 static route. */ if (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0) { if (add_cmd) static_add_ipv4 (&p, NULL, NULL, distance, 0); else static_delete_ipv4 (&p, NULL, NULL, distance, 0); return CMD_SUCCESS; } /* When gateway is A.B.C.D format, gate is treated as nexthop address other case gate is treated as interface name. */ ret = inet_aton (gate_str, &gate); if (ret) ifname = NULL; else ifname = gate_str; if (add_cmd) static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); else static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); return CMD_SUCCESS; }
int if_getaddrs () { int ret; struct ifaddrs *ifap; struct ifaddrs *ifapfree; struct interface *ifp; int prefixlen; ret = getifaddrs (&ifap); if (ret != 0) { #ifdef BRCM_RIP_DEBUG zlog_err ("getifaddrs(): %s", strerror (errno)); #endif return -1; } for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) { ifp = if_lookup_by_name (ifap->ifa_name); if (ifp == NULL) { #ifdef BRCM_RIP_DEBUG zlog_err ("if_getaddrs(): Can't lookup interface %s\n", ifap->ifa_name); #endif continue; } if (ifap->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *addr; struct sockaddr_in *mask; struct sockaddr_in *dest; struct in_addr *dest_pnt; addr = (struct sockaddr_in *) ifap->ifa_addr; mask = (struct sockaddr_in *) ifap->ifa_netmask; prefixlen = ip_masklen (mask->sin_addr); dest_pnt = NULL; if (ifap->ifa_flags & IFF_POINTOPOINT) { dest = (struct sockaddr_in *) ifap->ifa_dstaddr; dest_pnt = &dest->sin_addr; } if (ifap->ifa_flags & IFF_BROADCAST) { dest = (struct sockaddr_in *) ifap->ifa_broadaddr; dest_pnt = &dest->sin_addr; } connected_add_ipv4 (ifp, 0, &addr->sin_addr, prefixlen, dest_pnt, NULL); } #ifdef HAVE_IPV6 if (ifap->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr; struct sockaddr_in6 *mask; struct sockaddr_in6 *dest; struct in6_addr *dest_pnt; addr = (struct sockaddr_in6 *) ifap->ifa_addr; mask = (struct sockaddr_in6 *) ifap->ifa_netmask; prefixlen = ip6_masklen (mask->sin6_addr); dest_pnt = NULL; if (ifap->ifa_flags & IFF_POINTOPOINT) { if (ifap->ifa_dstaddr) { dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; dest_pnt = &dest->sin6_addr; } } if (ifap->ifa_flags & IFF_BROADCAST) { if (ifap->ifa_broadaddr) { dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; dest_pnt = &dest->sin6_addr; } } connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt); } #endif /* HAVE_IPV6 */ } freeifaddrs (ifapfree); return 0; }
void rtm_read (struct rt_msghdr *rtm) { int flags; u_char zebra_flags; union sockunion dest, mask, gate; char ifname[INTERFACE_NAMSIZ + 1]; short ifnlen = 0; zebra_flags = 0; /* Read destination and netmask and gateway from rtm message structure. */ flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen); if (!(flags & RTF_DONE)) return; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: got rtm of type %d (%s)", __func__, rtm->rtm_type, lookup (rtm_type_str, rtm->rtm_type)); #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/ if (flags & RTF_CLONED) return; #endif #ifdef RTF_WASCLONED /*freebsd*/ if (flags & RTF_WASCLONED) return; #endif if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP)) return; /* This is connected route. */ if (! (flags & RTF_GATEWAY)) return; if (flags & RTF_PROTO1) SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE); /* This is persistent route. */ if (flags & RTF_STATIC) SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC); /* This is a reject or blackhole route */ if (flags & RTF_REJECT) SET_FLAG (zebra_flags, ZEBRA_FLAG_REJECT); if (flags & RTF_BLACKHOLE) SET_FLAG (zebra_flags, ZEBRA_FLAG_BLACKHOLE); if (dest.sa.sa_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; p.prefix = dest.sin.sin_addr; if (flags & RTF_HOST) p.prefixlen = IPV4_MAX_PREFIXLEN; else p.prefixlen = ip_masklen (mask.sin.sin_addr); /* Catch self originated messages and match them against our current RIB. * At the same time, ignore unconfirmed messages, they should be tracked * by rtm_write() and kernel_rtm_ipv4(). */ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) { char buf[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN]; int ret; if (! IS_ZEBRA_DEBUG_RIB) return; ret = rib_lookup_ipv4_route (&p, &gate); inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN); switch (rtm->rtm_type) { case RTM_ADD: case RTM_GET: case RTM_CHANGE: /* The kernel notifies us about a new route in FIB created by us. Do we have a correspondent entry in our RIB? */ switch (ret) { case ZEBRA_RIB_NOTFOUND: zlog_debug ("%s: %s %s/%d: desync: RR isn't yet in RIB, while already in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: inet_ntop (AF_INET, &gate.sin.sin_addr, gate_buf, INET_ADDRSTRLEN); zlog_debug ("%s: %s %s/%d: desync: RR is in RIB, but gate differs (ours is %s)", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen, gate_buf); break; case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s/%d: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); return; break; } break; case RTM_DELETE: /* The kernel notifies us about a route deleted by us. Do we still have it in the RIB? Do we have anything instead? */ switch (ret) { case ZEBRA_RIB_FOUND_EXACT: zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, while already not in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, plus gate differs", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s/%d: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); return; break; } break; default: zlog_debug ("%s: %s/%d: warning: loopback RTM of type %s received", __func__, buf, p.prefixlen, lookup (rtm_type_str, rtm->rtm_type)); } return; } /* Change, delete the old prefix, we have no further information * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, NULL, 0, 0); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0, rtm->rtm_protocol); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, 0); } #ifdef HAVE_IPV6 if (dest.sa.sa_family == AF_INET6) { /* One day we might have a debug section here like one in the * IPv4 case above. Just ignore own messages at the moment. */ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) return; struct prefix_ipv6 p; unsigned int ifindex = 0; p.family = AF_INET6; p.prefix = dest.sin6.sin6_addr; if (flags & RTF_HOST) p.prefixlen = IPV6_MAX_PREFIXLEN; else p.prefixlen = ip6_masklen (mask.sin6.sin6_addr); #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr)) { ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr); SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0); } #endif /* KAME */ /* CHANGE: delete the old prefix, we have no further information * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, NULL, 0, 0); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0); } #endif /* HAVE_IPV6 */ }
/* Interface's address information get. */ int ifam_read (struct ifa_msghdr *ifam) { struct interface *ifp = NULL; union sockunion addr, mask, brd; char ifname[INTERFACE_NAMSIZ]; short ifnlen = 0; char isalias = 0; int flags = 0; ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0'; /* Allocate and read address information. */ ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen); if ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL) { zlog_warn ("%s: no interface for ifname %s, index %d", __func__, ifname, ifam->ifam_index); return -1; } if (ifnlen && strncmp (ifp->name, ifname, INTERFACE_NAMSIZ)) isalias = 1; /* N.B. The info in ifa_msghdr does not tell us whether the RTA_BRD field contains a broadcast address or a peer address, so we are forced to rely upon the interface type. */ if (if_is_pointopoint(ifp)) SET_FLAG(flags, ZEBRA_IFA_PEER); #if 0 /* it might seem cute to grab the interface metric here, however * we're processing an address update message, and so some systems * (e.g. FBSD) dont bother to fill in ifam_metric. Disabled, but left * in deliberately, as comment. */ ifp->metric = ifam->ifam_metric; #endif /* Add connected address. */ switch (sockunion_family (&addr)) { case AF_INET: if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr, (isalias ? ifname : NULL)); else connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr); break; #ifdef HAVE_IPV6 case AF_INET6: /* Unset interface index from link-local address when IPv6 stack is KAME. */ if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr, (isalias ? ifname : NULL)); else connected_delete_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr); break; #endif /* HAVE_IPV6 */ default: /* Unsupported family silently ignore... */ break; } /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); #ifdef SUNOS_5 /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. * See comments for SUNOS_5 in interface.c::if_flags_mangle. * * Here we take care of case where the real IFF_UP was previously * unset (as kept in struct zebra_if.primary_state) and the mangled * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned * to unset due to the lost non-primary address having DELADDR'd. * * we must delete the interface, because in between here and next * event for this interface-name the administrator could unplumb * and replumb the interface. */ if (!if_is_up (ifp)) if_delete_update (ifp); #endif /* SUNOS_5 */ return 0; }
/* Address read from struct ifa_msghdr. */ static void ifam_read_mesg (struct ifa_msghdr *ifm, union sockunion *addr, union sockunion *mask, union sockunion *brd, char *ifname, short *ifnlen) { caddr_t pnt, end; union sockunion dst; union sockunion gateway; pnt = (caddr_t)(ifm + 1); end = ((caddr_t)ifm) + ifm->ifam_msglen; /* Be sure structure is cleared */ memset (mask, 0, sizeof (union sockunion)); memset (addr, 0, sizeof (union sockunion)); memset (brd, 0, sizeof (union sockunion)); memset (&dst, 0, sizeof (union sockunion)); memset (&gateway, 0, sizeof (union sockunion)); /* We fetch each socket variable into sockunion. */ RTA_ADDR_GET (&dst, RTA_DST, ifm->ifam_addrs, pnt); RTA_ADDR_GET (&gateway, RTA_GATEWAY, ifm->ifam_addrs, pnt); RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt); RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt); RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen); RTA_ADDR_GET (addr, RTA_IFA, ifm->ifam_addrs, pnt); RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt); RTA_ADDR_GET (brd, RTA_BRD, ifm->ifam_addrs, pnt); if (IS_ZEBRA_DEBUG_KERNEL) { switch (sockunion_family(addr)) { case AF_INET: { char buf[4][INET_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, inet_ntop(AF_INET,&addr->sin.sin_addr, buf[0],sizeof(buf[0])), ip_masklen(mask->sin.sin_addr), inet_ntop(AF_INET,&brd->sin.sin_addr, buf[1],sizeof(buf[1])), inet_ntop(AF_INET,&dst.sin.sin_addr, buf[2],sizeof(buf[2])), inet_ntop(AF_INET,&gateway.sin.sin_addr, buf[3],sizeof(buf[3]))); } break; #ifdef HAVE_IPV6 case AF_INET6: { char buf[4][INET6_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, inet_ntop(AF_INET6,&addr->sin6.sin6_addr, buf[0],sizeof(buf[0])), ip6_masklen(mask->sin6.sin6_addr), inet_ntop(AF_INET6,&brd->sin6.sin6_addr, buf[1],sizeof(buf[1])), inet_ntop(AF_INET6,&dst.sin6.sin6_addr, buf[2],sizeof(buf[2])), inet_ntop(AF_INET6,&gateway.sin6.sin6_addr, buf[3],sizeof(buf[3]))); } break; #endif /* HAVE_IPV6 */ default: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs); break; } } /* Assert read up end point matches to end point */ if (pnt != end) zlog_warn ("ifam_read() does't read all socket data"); }
void rtm_read (struct rt_msghdr *rtm) { int flags; u_char zebra_flags; union sockunion dest, mask, gate; char ifname[INTERFACE_NAMSIZ + 1]; short ifnlen = 0; zebra_flags = 0; /* Discard self send message. */ if (rtm->rtm_type != RTM_GET && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid)) return; /* Read destination and netmask and gateway from rtm message structure. */ flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen); #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/ if (flags & RTF_CLONED) return; #endif #ifdef RTF_WASCLONED /*freebsd*/ if (flags & RTF_WASCLONED) return; #endif if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP)) return; /* This is connected route. */ if (! (flags & RTF_GATEWAY)) return; if (flags & RTF_PROTO1) SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE); /* This is persistent route. */ if (flags & RTF_STATIC) SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC); /* This is a reject or blackhole route */ if (flags & RTF_REJECT) SET_FLAG (zebra_flags, ZEBRA_FLAG_REJECT); if (flags & RTF_BLACKHOLE) SET_FLAG (zebra_flags, ZEBRA_FLAG_BLACKHOLE); if (dest.sa.sa_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; p.prefix = dest.sin.sin_addr; if (flags & RTF_HOST) p.prefixlen = IPV4_MAX_PREFIXLEN; else p.prefixlen = ip_masklen (mask.sin.sin_addr); /* Change, delete the old prefix, we have no further information * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, NULL, 0, 0); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, 0, 0, 0); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, 0); } #ifdef HAVE_IPV6 if (dest.sa.sa_family == AF_INET6) { struct prefix_ipv6 p; unsigned int ifindex = 0; p.family = AF_INET6; p.prefix = dest.sin6.sin6_addr; if (flags & RTF_HOST) p.prefixlen = IPV6_MAX_PREFIXLEN; else p.prefixlen = ip6_masklen (mask.sin6.sin6_addr); #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr)) { ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr); SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0); } #endif /* KAME */ /* CHANGE: delete the old prefix, we have no further information * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, NULL, 0, 0); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0); } #endif /* HAVE_IPV6 */ }
/* Interface address lookup by ioctl. This function only looks up IPv4 address. */ int if_get_addr (struct interface *ifp) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct sockaddr_in mask; struct sockaddr_in dest; struct in_addr *dest_pnt; u_char prefixlen; /* Interface's name and address family. */ strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); ifreq.ifr_addr.sa_family = AF_INET; /* Interface's address. */ ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno)); return ret; } return 0; } memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); /* Interface's network mask. */ ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno)); return ret; } return 0; } #ifdef ifr_netmask memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in)); #else memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); #endif /* ifr_netmask */ prefixlen = ip_masklen (mask.sin_addr); /* Point to point or borad cast address pointer init. */ dest_pnt = NULL; if (ifp->flags & IFF_POINTOPOINT) { ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno)); return ret; } return 0; } memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in)); dest_pnt = &dest.sin_addr; } if (ifp->flags & IFF_BROADCAST) { ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno)); return ret; } return 0; } memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = &dest.sin_addr; } /* Set address to the interface. */ connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL); return 0; }
/* Retrieve address information for the given ifp */ static int if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label) { int ret; struct lifreq lifreq; struct sockaddr_storage mask, dest; char *dest_pnt = NULL; u_char prefixlen = 0; afi_t af; int flags = 0; /* Interface's name and address family. * We need to use the logical interface name / label, if we've been * given one, in order to get the right address */ strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ); /* Interface's address. */ memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr)); af = addr->sa_family; /* Point to point or broad cast address pointer init. */ dest_pnt = NULL; if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0) { memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr)); if (af == AF_INET) dest_pnt = (char *) &(SIN (&dest)->sin_addr); else dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr); flags = ZEBRA_IFA_PEER; } if (af == AF_INET) { ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name, safe_strerror (errno)); return ret; } return 0; } memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr)); prefixlen = ip_masklen (SIN (&mask)->sin_addr); if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0)) { memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = (char *) &SIN (&dest)->sin_addr; } } #ifdef HAVE_IPV6 else if (af == AF_INET6) { if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0) { if (ifp->flags & IFF_POINTOPOINT) prefixlen = IPV6_MAX_BITLEN; else zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s", ifp->name, safe_strerror (errno)); } else { prefixlen = lifreq.lifr_addrlen; } } #endif /* HAVE_IPV6 */ /* Set address to the interface. */ if (af == AF_INET) connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen, (struct in_addr *) dest_pnt, label); #ifdef HAVE_IPV6 else if (af == AF_INET6) connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen, (struct in6_addr *) dest_pnt, label); #endif /* HAVE_IPV6 */ return 0; }
static int process_summary_lsa (struct ospf_area *area, struct route_table *rt, struct route_table *rtrs, struct ospf_lsa *lsa) { struct ospf *ospf = area->ospf; struct ospf_area_range *range; struct ospf_route *abr_or, *new_or; struct summary_lsa *sl; struct prefix_ipv4 p, abr; u_int32_t metric; if (lsa == NULL) return 0; sl = (struct summary_lsa *) lsa->data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("process_summary_lsa(): LS ID: %s", inet_ntoa (sl->header.id)); metric = GET_METRIC (sl->metric); if (metric == OSPF_LS_INFINITY) return 0; if (IS_LSA_MAXAGE (lsa)) return 0; if (ospf_lsa_is_self_originated (area->ospf, lsa)) return 0; p.family = AF_INET; p.prefix = sl->header.id; if (sl->header.type == OSPF_SUMMARY_LSA) p.prefixlen = ip_masklen (sl->mask); else p.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&p); if (sl->header.type == OSPF_SUMMARY_LSA && (range = ospf_area_range_match_any (ospf, &p)) && ospf_area_range_active (range)) return 0; /* XXX: This check seems dubious to me. If an ABR has already decided * to consider summaries received in this area, then why would one wish * to exclude default? */ if (IS_OSPF_ABR(ospf) && ospf->abr_type != OSPF_ABR_STAND && area->external_routing != OSPF_AREA_DEFAULT && p.prefix.s_addr == OSPF_DEFAULT_DESTINATION && p.prefixlen == 0) return 0; /* Ignore summary default from a stub area */ abr.family = AF_INET; abr.prefix = sl->header.adv_router; abr.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&abr); abr_or = ospf_find_abr_route (rtrs, &abr, area); if (abr_or == NULL) return 0; new_or = ospf_route_new (); new_or->type = OSPF_DESTINATION_NETWORK; new_or->id = sl->header.id; new_or->mask = sl->mask; new_or->u.std.options = sl->header.options; new_or->u.std.origin = (struct lsa_header *) sl; new_or->cost = abr_or->cost + metric; new_or->u.std.area_id = area->area_id; new_or->u.std.external_routing = area->external_routing; new_or->path_type = OSPF_PATH_INTER_AREA; if (sl->header.type == OSPF_SUMMARY_LSA) ospf_ia_network_route (ospf, rt, &p, new_or, abr_or); else { new_or->type = OSPF_DESTINATION_ROUTER; new_or->u.std.flags = ROUTER_LSA_EXTERNAL; ospf_ia_router_route (ospf, rtrs, &p, new_or, abr_or); } return 0; }
int process_summary_lsa (struct ospf_lsa *l, void *v, int i) { struct ospf_area_range *range; struct ospf_route *abr_or, *new_or; struct summary_lsa *sl; struct prefix_ipv4 p, abr; u_int32_t metric; struct ia_args *args; if (l == NULL) return 0; args = (struct ia_args *) v; sl = (struct summary_lsa *) l->data; if (IS_DEBUG_OSPF_EVENT) zlog_info ("process_summary_lsa(): LS ID: %s", inet_ntoa (sl->header.id)); metric = GET_METRIC (sl->metric); if (metric == OSPF_LS_INFINITY) return 0; if (IS_LSA_MAXAGE (l)) return 0; if (ospf_lsa_is_self_originated (l)) return 0; p.family = AF_INET; p.prefix = sl->header.id; if (sl->header.type == OSPF_SUMMARY_LSA) p.prefixlen = ip_masklen (sl->mask); else p.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&p); if (sl->header.type == OSPF_SUMMARY_LSA && (range = ospf_area_range_match_any (ospf_top, &p)) && ospf_area_range_active (range)) return 0; if (ospf_top->abr_type != OSPF_ABR_STAND && args->area->external_routing != OSPF_AREA_DEFAULT && p.prefix.s_addr == OSPF_DEFAULT_DESTINATION && p.prefixlen == 0) return 0; /* Ignore summary default from a stub area */ abr.family = AF_INET; abr.prefix = sl->header.adv_router; abr.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&abr); abr_or = ospf_find_abr_route (args->rtrs, &abr, args->area); if (abr_or == NULL) return 0; new_or = ospf_route_new (); new_or->type = OSPF_DESTINATION_NETWORK; new_or->id = sl->header.id; new_or->mask = sl->mask; new_or->u.std.options = sl->header.options; new_or->u.std.origin = (struct lsa_header *) sl; new_or->cost = abr_or->cost + metric; new_or->u.std.area_id = args->area->area_id; #ifdef HAVE_NSSA new_or->u.std.external_routing = args->area->external_routing; #endif /* HAVE_NSSA */ new_or->path_type = OSPF_PATH_INTER_AREA; if (sl->header.type == OSPF_SUMMARY_LSA) ospf_ia_network_route (args->rt, &p, new_or, abr_or); else { new_or->type = OSPF_DESTINATION_ROUTER; new_or->u.std.flags = ROUTER_LSA_EXTERNAL; ospf_ia_router_route (args->rtrs, &p, new_or, abr_or); } return 0; }
void rtm_read (struct rt_msghdr *rtm) { int flags; u_char zebra_flags; union sockunion dest, mask, gate; zebra_flags = 0; /* Discard self send message. */ if (rtm->rtm_type != RTM_GET && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid)) return; /* Read destination and netmask and gateway from rtm message structure. */ flags = rtm_read_mesg (rtm, &dest, &mask, &gate); #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/ if (flags & RTF_CLONED) return; #endif #ifdef RTF_WASCLONED /*freebsd*/ if (flags & RTF_WASCLONED) return; #endif if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP)) return; /* Ignore route which has both HOST and GATEWAY attribute. */ if ((flags & RTF_GATEWAY) && (flags & RTF_HOST)) return; /* This is connected route. */ if (! (flags & RTF_GATEWAY)) return; if (flags & RTF_PROTO1) SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE); /* This is persistent route. */ if (flags & RTF_STATIC) SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC); if (dest.sa.sa_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; p.prefix = dest.sin.sin_addr; p.prefixlen = ip_masklen (mask.sin.sin_addr); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, 0, 0, 0); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, 0); } #ifdef HAVE_IPV6 if (dest.sa.sa_family == AF_INET6) { struct prefix_ipv6 p; unsigned int ifindex = 0; p.family = AF_INET6; p.prefix = dest.sin6.sin6_addr; p.prefixlen = ip6_masklen (mask.sin6.sin6_addr); #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr)) { ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr); SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0); } #endif /* KAME */ if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0); } #endif /* HAVE_IPV6 */ }
static int if_getaddrs (void) { int ret; struct ifaddrs *ifap; struct ifaddrs *ifapfree; struct interface *ifp; int prefixlen; ret = getifaddrs (&ifap); if (ret != 0) { zlog_err ("getifaddrs(): %s", safe_strerror (errno)); return -1; } for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) { if (ifap->ifa_addr == NULL) { zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s", __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)")); continue; } ifp = if_lookup_by_name (ifap->ifa_name); if (ifp == NULL) { zlog_err ("if_getaddrs(): Can't lookup interface %s\n", ifap->ifa_name); continue; } if (ifap->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *addr; struct sockaddr_in *mask; struct sockaddr_in *dest; struct in_addr *dest_pnt; addr = (struct sockaddr_in *) ifap->ifa_addr; mask = (struct sockaddr_in *) ifap->ifa_netmask; prefixlen = ip_masklen (mask->sin_addr); dest_pnt = NULL; if (ifap->ifa_flags & IFF_POINTOPOINT) { dest = (struct sockaddr_in *) ifap->ifa_dstaddr; dest_pnt = &dest->sin_addr; } if (ifap->ifa_flags & IFF_BROADCAST) { dest = (struct sockaddr_in *) ifap->ifa_broadaddr; dest_pnt = &dest->sin_addr; } connected_add_ipv4 (ifp, 0, &addr->sin_addr, prefixlen, dest_pnt, NULL); } #ifdef HAVE_IPV6 if (ifap->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr; struct sockaddr_in6 *mask; struct sockaddr_in6 *dest; struct in6_addr *dest_pnt; addr = (struct sockaddr_in6 *) ifap->ifa_addr; mask = (struct sockaddr_in6 *) ifap->ifa_netmask; prefixlen = ip6_masklen (mask->sin6_addr); dest_pnt = NULL; if (ifap->ifa_flags & IFF_POINTOPOINT) { if (ifap->ifa_dstaddr) { dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; dest_pnt = &dest->sin6_addr; } } if (ifap->ifa_flags & IFF_BROADCAST) { if (ifap->ifa_broadaddr) { dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; dest_pnt = &dest->sin6_addr; } } #if defined(KAME) if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { addr->sin6_scope_id = ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]); addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0; } #endif connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt, NULL); } #endif /* HAVE_IPV6 */ } freeifaddrs (ifapfree); return 0; }