static int kernel_rtm (int cmd, struct prefix *p, struct rib *rib) { switch (PREFIX_FAMILY(p)) { case AF_INET: return kernel_rtm_ipv4 (cmd, p, rib); case AF_INET6: return kernel_rtm_ipv6 (cmd, p, rib); } return 0; }
int nhrp_interface_address_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; char buf[PREFIX_STRLEN]; ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id); if (ifc == NULL) return 0; debugf(NHRP_DEBUG_IF, "if-addr-add: %s: %s", ifc->ifp->name, prefix2str(ifc->address, buf, sizeof buf)); nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0); return 0; }
struct rnh * zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid) { struct route_table *table; struct route_node *rn; table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); if (!table) return NULL; /* Make it sure prefixlen is applied to the prefix. */ apply_mask (p); /* Lookup route node.*/ rn = route_node_lookup (table, p); if (!rn) return NULL; route_unlock_node (rn); return (rn->info); }
static struct route_node *nhrp_route_update_get(const struct prefix *p, int create) { struct route_node *rn; afi_t afi = family2afi(PREFIX_FAMILY(p)); if (!zebra_rib[afi]) return NULL; if (create) { rn = route_node_get(zebra_rib[afi], p); if (!rn->info) { rn->info = XCALLOC(MTYPE_NHRP_ROUTE, sizeof(struct route_info)); route_lock_node(rn); } return rn; } else { return route_node_lookup(zebra_rib[afi], p); } }
struct rnh * zebra_add_rnh (struct prefix *p, vrf_id_t vrfid) { struct route_table *table; struct route_node *rn; struct rnh *rnh = NULL; if (IS_ZEBRA_DEBUG_NHT) { char buf[INET6_ADDRSTRLEN]; prefix2str(p, buf, INET6_ADDRSTRLEN); zlog_debug("add rnh %s in vrf %d", buf, vrfid); } table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); if (!table) { zlog_debug("add_rnh: rnh table not found\n"); return NULL; } /* Make it sure prefixlen is applied to the prefix. */ apply_mask (p); /* Lookup (or add) route node.*/ rn = route_node_get (table, p); if (!rn->info) { rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); rnh->client_list = list_new(); route_lock_node (rn); rn->info = rnh; rnh->node = rn; } route_unlock_node (rn); return (rn->info); }
static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, int force) { const int family = afi2family(afi); struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad = &nifp->afi[afi]; struct nhrp_cache *nc; struct connected *c, *best; struct listnode *cnode; union sockunion addr; char buf[PREFIX_STRLEN]; /* Select new best match preferring primary address */ best = NULL; for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { if (PREFIX_FAMILY(c->address) != family) continue; if (best == NULL) { best = c; continue; } if ((best->flags & ZEBRA_IFA_SECONDARY) && !(c->flags & ZEBRA_IFA_SECONDARY)) { best = c; continue; } if (!(best->flags & ZEBRA_IFA_SECONDARY) && (c->flags & ZEBRA_IFA_SECONDARY)) continue; if (best->address->prefixlen > c->address->prefixlen) { best = c; continue; } if (best->address->prefixlen < c->address->prefixlen) continue; } /* On NHRP interfaces a host prefix is required */ if (best && if_ad->configured && best->address->prefixlen != 8 * prefix_blen(best->address)) { zlog_notice("%s: %s is not a host prefix", ifp->name, prefix2str(best->address, buf, sizeof buf)); best = NULL; } /* Update address if it changed */ if (best) prefix2sockunion(best->address, &addr); else memset(&addr, 0, sizeof(addr)); if (!force && sockunion_same(&if_ad->addr, &addr)) return; if (sockunion_family(&if_ad->addr) != AF_UNSPEC) { nc = nhrp_cache_get(ifp, &if_ad->addr, 0); if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, -1, NULL, 0, NULL); } debugf(NHRP_DEBUG_KERNEL, "%s: IPv%d address changed to %s", ifp->name, afi == AFI_IP ? 4 : 6, best ? prefix2str(best->address, buf, sizeof buf) : "(none)"); if_ad->addr = addr; if (if_ad->configured && sockunion_family(&if_ad->addr) != AF_UNSPEC) { nc = nhrp_cache_get(ifp, &addr, 1); if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL); } notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED); }
/* Install or uninstall specified rule for a specific interface. * Form netlink message and ship it. Currently, notify status after * waiting for netlink status. */ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) { int family; int bytelen; struct { struct nlmsghdr n; struct fib_rule_hdr frh; char buf[NL_PKT_BUF_SIZE]; } req; struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); struct sockaddr_nl snl; char buf1[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE); family = PREFIX_FAMILY(&rule->rule.filter.src_ip); bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_type = cmd; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; req.frh.family = family; req.frh.action = FR_ACT_TO_TBL; /* rule's pref # */ addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority); /* interface on which applied */ if (rule->ifp) addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifp->name, strlen(rule->ifp->name) + 1); /* source IP, if specified */ if (IS_RULE_FILTERING_ON_SRC_IP(rule)) { req.frh.src_len = rule->rule.filter.src_ip.prefixlen; addattr_l(&req.n, sizeof(req), FRA_SRC, &rule->rule.filter.src_ip.u.prefix, bytelen); } /* destination IP, if specified */ if (IS_RULE_FILTERING_ON_DST_IP(rule)) { req.frh.dst_len = rule->rule.filter.dst_ip.prefixlen; addattr_l(&req.n, sizeof(req), FRA_DST, &rule->rule.filter.dst_ip.u.prefix, bytelen); } /* fwmark, if specified */ if (IS_RULE_FILTERING_ON_FWMARK(rule)) { addattr32(&req.n, sizeof(req), FRA_FWMARK, rule->rule.filter.fwmark); } /* Route table to use to forward, if filter criteria matches. */ if (rule->rule.action.table < 256) req.frh.table = rule->rule.action.table; else { req.frh.table = RT_TABLE_UNSPEC; addattr32(&req.n, sizeof(req), FRA_TABLE, rule->rule.action.table); } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u", nl_msg_type_to_str(cmd), nl_family_to_str(family), rule->ifp ? rule->ifp->name : "Unknown", rule->ifp ? rule->ifp->ifindex : 0, rule->rule.priority, rule->rule.filter.fwmark, prefix2str(&rule->rule.filter.src_ip, buf1, sizeof(buf1)), prefix2str(&rule->rule.filter.dst_ip, buf2, sizeof(buf2)), rule->rule.action.table); /* Ship off the message. * Note: Currently, netlink_talk() is a blocking call which returns * back the status. */ memset(&snl, 0, sizeof(snl)); snl.nl_family = AF_NETLINK; return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); }