static int rule_compare(struct nl_object *_a, struct nl_object *_b, uint32_t attrs, int flags) { struct rtnl_rule *a = (struct rtnl_rule *) _a; struct rtnl_rule *b = (struct rtnl_rule *) _b; int diff = 0; #define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR) diff |= RULE_DIFF(FAMILY, a->r_family != b->r_family); diff |= RULE_DIFF(TABLE, a->r_table != b->r_table); diff |= RULE_DIFF(REALMS, a->r_realms != b->r_realms); diff |= RULE_DIFF(DSFIELD, a->r_dsfield != b->r_dsfield); diff |= RULE_DIFF(TYPE, a->r_type != b->r_type); diff |= RULE_DIFF(PRIO, a->r_prio != b->r_prio); diff |= RULE_DIFF(MARK, a->r_mark != b->r_mark); diff |= RULE_DIFF(SRC_LEN, a->r_src_len != b->r_src_len); diff |= RULE_DIFF(DST_LEN, a->r_dst_len != b->r_dst_len); diff |= RULE_DIFF(SRC, nl_addr_cmp(a->r_src, b->r_src)); diff |= RULE_DIFF(DST, nl_addr_cmp(a->r_dst, b->r_dst)); diff |= RULE_DIFF(IIF, strcmp(a->r_iif, b->r_iif)); #undef RULE_DIFF return diff; }
static int rule_compare(struct nl_object *_a, struct nl_object *_b, uint32_t attrs, int flags) { struct rtnl_rule *a = (struct rtnl_rule *) _a; struct rtnl_rule *b = (struct rtnl_rule *) _b; int diff = 0; #define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR) diff |= RULE_DIFF(FAMILY, a->r_family != b->r_family); diff |= RULE_DIFF(TABLE, a->r_table != b->r_table); diff |= RULE_DIFF(ACTION, a->r_action != b->r_action); diff |= RULE_DIFF(IIFNAME, strcmp(a->r_iifname, b->r_iifname)); diff |= RULE_DIFF(OIFNAME, strcmp(a->r_oifname, b->r_oifname)); diff |= RULE_DIFF(PRIO, a->r_prio != b->r_prio); diff |= RULE_DIFF(MARK, a->r_mark != b->r_mark); diff |= RULE_DIFF(MASK, a->r_mask != b->r_mask); diff |= RULE_DIFF(GOTO, a->r_goto != b->r_goto); diff |= RULE_DIFF(SRC, nl_addr_cmp(a->r_src, b->r_src)); diff |= RULE_DIFF(DST, nl_addr_cmp(a->r_dst, b->r_dst)); diff |= RULE_DIFF(DSFIELD, a->r_dsfield != b->r_dsfield); diff |= RULE_DIFF(FLOW, a->r_flow != b->r_flow); #undef RULE_DIFF return diff; }
static int addr_filter(struct nl_object *obj, struct nl_object *filter) { struct rtnl_addr *o = (struct rtnl_addr *) obj; struct rtnl_addr *f = (struct rtnl_addr *) filter; #define REQ(F) (f->a_mask & ADDR_ATTR_##F) #define AVAIL(F) (o->a_mask & ADDR_ATTR_##F) #define _O(F, EXPR) (REQ(F) && (!AVAIL(F) || (EXPR))) #define _C(F, N) (REQ(F) && (!AVAIL(F) || (o->N != f->N))) if (_C(IFINDEX, a_ifindex) || _C(FAMILY, a_family) || _C(SCOPE, a_scope) || _O(FLAGS, f->a_flags ^ (o->a_flags & f->a_flag_mask)) || _O(LABEL, strcmp(o->a_label, f->a_label)) || _O(PEER, nl_addr_cmp(o->a_peer, f->a_peer)) || _O(LOCAL, nl_addr_cmp(o->a_local, f->a_local)) || _O(ANYCAST, nl_addr_cmp(o->a_anycast, f->a_anycast)) || _O(MULTICAST, nl_addr_cmp(o->a_multicast, f->a_multicast)) || _O(BROADCAST, nl_addr_cmp(o->a_bcast, f->a_bcast))) return 0; #undef REQ #undef AVAIL #undef _O #undef _C return 1; }
static int addr_compare(struct nl_object *_a, struct nl_object *_b, uint32_t attrs, int flags) { struct rtnl_addr *a = (struct rtnl_addr *) _a; struct rtnl_addr *b = (struct rtnl_addr *) _b; int diff = 0; #define ADDR_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ADDR_ATTR_##ATTR, a, b, EXPR) diff |= ADDR_DIFF(IFINDEX, a->a_ifindex != b->a_ifindex); diff |= ADDR_DIFF(FAMILY, a->a_family != b->a_family); diff |= ADDR_DIFF(SCOPE, a->a_scope != b->a_scope); diff |= ADDR_DIFF(LABEL, strcmp(a->a_label, b->a_label)); diff |= ADDR_DIFF(PEER, nl_addr_cmp(a->a_peer, b->a_peer)); diff |= ADDR_DIFF(LOCAL, nl_addr_cmp(a->a_local, b->a_local)); diff |= ADDR_DIFF(ANYCAST, nl_addr_cmp(a->a_anycast,b->a_anycast)); diff |= ADDR_DIFF(MULTICAST, nl_addr_cmp(a->a_multicast, b->a_multicast)); diff |= ADDR_DIFF(BROADCAST, nl_addr_cmp(a->a_bcast, b->a_bcast)); if (flags & LOOSE_FLAG_COMPARISON) diff |= ADDR_DIFF(FLAGS, (a->a_flags ^ b->a_flags) & b->a_flag_mask); else diff |= ADDR_DIFF(FLAGS, a->a_flags != b->a_flags); #undef ADDR_DIFF return diff; }
static uint64_t xfrm_ae_compare(struct nl_object *_a, struct nl_object *_b, uint64_t attrs, int flags) { struct xfrmnl_ae* a = (struct xfrmnl_ae *) _a; struct xfrmnl_ae* b = (struct xfrmnl_ae *) _b; uint64_t diff = 0; int found = 0; #define XFRM_AE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, XFRM_AE_ATTR_##ATTR, a, b, EXPR) diff |= XFRM_AE_DIFF(DADDR, nl_addr_cmp(a->sa_id.daddr, b->sa_id.daddr)); diff |= XFRM_AE_DIFF(SPI, a->sa_id.spi != b->sa_id.spi); diff |= XFRM_AE_DIFF(PROTO, a->sa_id.proto != b->sa_id.proto); diff |= XFRM_AE_DIFF(SADDR, nl_addr_cmp(a->saddr, b->saddr)); diff |= XFRM_AE_DIFF(FLAGS, a->flags != b->flags); diff |= XFRM_AE_DIFF(REQID, a->reqid != b->reqid); diff |= XFRM_AE_DIFF(MARK, (a->mark.v & a->mark.m) != (b->mark.v & b->mark.m)); diff |= XFRM_AE_DIFF(REPLAY_MAXAGE, a->replay_maxage != b->replay_maxage); diff |= XFRM_AE_DIFF(REPLAY_MAXDIFF, a->replay_maxdiff != b->replay_maxdiff); /* Compare replay states */ found = AVAILABLE_MISMATCH (a, b, XFRM_AE_ATTR_REPLAY_STATE); if (found == 0) // attribute exists in both objects { if (((a->replay_state_esn != NULL) && (b->replay_state_esn == NULL)) || ((a->replay_state_esn == NULL) && (b->replay_state_esn != NULL))) found |= 1; if (found == 0) // same replay type. compare actual values { if (a->replay_state_esn) { if (a->replay_state_esn->bmp_len != b->replay_state_esn->bmp_len) diff |= 1; else { uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * a->replay_state_esn->bmp_len); diff |= memcmp (a->replay_state_esn, b->replay_state_esn, len); } } else { if ((a->replay_state.oseq != b->replay_state.oseq) || (a->replay_state.seq != b->replay_state.seq) || (a->replay_state.bitmap != b->replay_state.bitmap)) diff |= 1; } } } #undef XFRM_AE_DIFF return diff; }
static gint _j4status_nl_address_compare(gconstpointer a, gconstpointer b) { if ( a == b ) return 0; return nl_addr_cmp(a, b); }
static void change_cb(struct nl_cache *cache, struct nl_object *obj, int action) { struct nfnl_ct *ct = (struct nfnl_ct *) obj; static struct nl_addr *hack = NULL; if (!hack) hack = nl_addr_parse("194.88.212.233", AF_INET); if (!nl_addr_cmp(hack, nfnl_ct_get_src(ct, 1)) || !nl_addr_cmp(hack, nfnl_ct_get_dst(ct, 1))) { struct nl_dump_params dp = { .dp_type = NL_DUMP_LINE, .dp_fd = stdout, }; printf("UPDATE "); nl_object_dump(obj, &dp); } }
static void ct_dump_tuples(struct nfnl_ct *ct, struct nl_dump_params *p) { struct nl_addr *orig_src, *orig_dst, *reply_src, *reply_dst; int orig_sport = 0, orig_dport = 0, reply_sport = 0, reply_dport = 0; int sync = 0; orig_src = nfnl_ct_get_src(ct, 0); orig_dst = nfnl_ct_get_dst(ct, 0); reply_src = nfnl_ct_get_src(ct, 1); reply_dst = nfnl_ct_get_dst(ct, 1); if (nfnl_ct_test_src_port(ct, 0)) orig_sport = nfnl_ct_get_src_port(ct, 0); if (nfnl_ct_test_dst_port(ct, 0)) orig_dport = nfnl_ct_get_dst_port(ct, 0); if (nfnl_ct_test_src_port(ct, 1)) reply_sport = nfnl_ct_get_src_port(ct, 1); if (nfnl_ct_test_dst_port(ct, 1)) reply_dport = nfnl_ct_get_dst_port(ct, 1); if (orig_src && orig_dst && reply_src && reply_dst && orig_sport == reply_dport && orig_dport == reply_sport && !nl_addr_cmp(orig_src, reply_dst) && !nl_addr_cmp(orig_dst, reply_src)) sync = 1; dump_addr(p, orig_src, orig_sport); nl_dump(p, sync ? "<-> " : "-> "); dump_addr(p, orig_dst, orig_dport); dump_icmp(p, ct, 0); if (!sync) { dump_addr(p, reply_src, reply_sport); nl_dump(p, "<- "); dump_addr(p, reply_dst, reply_dport); dump_icmp(p, ct, 1); } }
/* Given an interface's MAC address, return the name (e.g., eth0) in human * readable format. Return NULL for no match */ char *iface_mac2device(char *mac) { struct nl_handle *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL; struct nl_addr *mac_as_nl_addr = NULL; char *retval = NULL; int i, n; if (mac == NULL) { return NULL; } if ((mac_as_nl_addr = nl_addr_parse(mac, AF_LLC)) == NULL) { return NULL; } if ((cache = _iface_get_link_cache(&handle)) == NULL) { return NULL; } n = nl_cache_nitems(cache); for (i = 0; i <= n; i++) { struct nl_addr *addr; if ((link = rtnl_link_get(cache, i)) == NULL) { continue; } addr = rtnl_link_get_addr(link); if (!nl_addr_cmp(mac_as_nl_addr, addr)) { retval = strdup(rtnl_link_get_name(link)); rtnl_link_put(link); break; } rtnl_link_put(link); } nl_close(handle); nl_handle_destroy(handle); return retval; }
static int request_compare(struct nl_object *_a, struct nl_object *_b, uint32_t attrs, int flags) { struct flnl_request *a = (struct flnl_request *) _a; struct flnl_request *b = (struct flnl_request *) _b; int diff = 0; #define REQ_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, REQUEST_ATTR_##ATTR, a, b, EXPR) diff |= REQ_DIFF(FWMARK, a->lr_fwmark != b->lr_fwmark); diff |= REQ_DIFF(TOS, a->lr_tos != b->lr_tos); diff |= REQ_DIFF(SCOPE, a->lr_scope != b->lr_scope); diff |= REQ_DIFF(TABLE, a->lr_table != b->lr_table); diff |= REQ_DIFF(ADDR, nl_addr_cmp(a->lr_addr, b->lr_addr)); #undef REQ_DIFF return diff; }
int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b, uint32_t attrs, int loose) { int diff = 0; #define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR) diff |= NH_DIFF(IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex); diff |= NH_DIFF(WEIGHT, a->rtnh_weight != b->rtnh_weight); diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms); diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway, b->rtnh_gateway)); if (loose) diff |= NH_DIFF(FLAGS, (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask); else diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags); #undef NH_DIFF return diff; }
void nl_bridge::remove_neigh_from_fdb(rtnl_neigh *neigh) { assert(sw); nl_addr *addr = rtnl_neigh_get_lladdr(neigh); if (nl_addr_cmp(rtnl_link_get_addr(bridge), addr) == 0) { // ignore ll addr of bridge on slave return; } // lookup l2_cache as well std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> n_lookup( NEIGH_CAST(nl_cache_search(l2_cache.get(), OBJ_CAST(neigh))), rtnl_neigh_put); if (n_lookup) { nl_cache_remove(OBJ_CAST(n_lookup.get())); } const uint32_t port = nl->get_port_id(rtnl_neigh_get_ifindex(neigh)); rofl::caddress_ll mac((uint8_t *)nl_addr_get_binary_addr(addr), nl_addr_get_len(addr)); sw->l2_addr_remove(port, rtnl_neigh_get_vlan(neigh), mac); }
static int addr_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh, void *arg) { struct rtnl_addr *addr; struct nl_parser_param *pp = arg; struct ifaddrmsg *ifa; struct nlattr *tb[IFA_MAX+1]; int err = -ENOMEM, peer_prefix = 0; addr = rtnl_addr_alloc(); if (!addr) { err = nl_errno(ENOMEM); goto errout; } addr->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy); if (err < 0) goto errout_free; ifa = nlmsg_data(nlh); addr->a_family = ifa->ifa_family; addr->a_prefixlen = ifa->ifa_prefixlen; addr->a_flags = ifa->ifa_flags; addr->a_scope = ifa->ifa_scope; addr->a_ifindex = ifa->ifa_index; addr->a_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN | ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX); if (tb[IFA_LABEL]) { nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ); addr->a_mask |= ADDR_ATTR_LABEL; } if (tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ca; ca = nla_data(tb[IFA_CACHEINFO]); addr->a_cacheinfo.aci_prefered = ca->ifa_prefered; addr->a_cacheinfo.aci_valid = ca->ifa_valid; addr->a_cacheinfo.aci_cstamp = ca->cstamp; addr->a_cacheinfo.aci_tstamp = ca->tstamp; addr->a_mask |= ADDR_ATTR_CACHEINFO; } if (tb[IFA_LOCAL]) { addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family); if (!addr->a_local) goto errout_free; addr->a_mask |= ADDR_ATTR_LOCAL; } if (tb[IFA_ADDRESS]) { struct nl_addr *a; a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family); if (!a) goto errout_free; /* IPv6 sends the local address as IFA_ADDRESS with * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS * with IFA_ADDRESS being the peer address if they differ */ if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) { nl_addr_put(addr->a_local); addr->a_local = a; addr->a_mask |= ADDR_ATTR_LOCAL; } else { addr->a_peer = a; addr->a_mask |= ADDR_ATTR_PEER; peer_prefix = 1; } } nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local, addr->a_prefixlen); if (tb[IFA_BROADCAST]) { addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family); if (!addr->a_bcast) goto errout_free; addr->a_mask |= ADDR_ATTR_BROADCAST; } if (tb[IFA_ANYCAST]) { addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family); if (!addr->a_anycast) goto errout_free; addr->a_mask |= ADDR_ATTR_ANYCAST; } if (tb[IFA_MULTICAST]) { addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST], addr->a_family); if (!addr->a_multicast) goto errout_free; addr->a_mask |= ADDR_ATTR_MULTICAST; } err = pp->pp_cb((struct nl_object *) addr, pp); if (err < 0) goto errout_free; return P_ACCEPT; errout_free: rtnl_addr_free(addr); errout: return err; }
struct rtnl_addr *rtnl_addr_alloc_from_msg(struct nl_msg *msg) { struct nlattr *tb[IFA_MAX+1]; struct rtnl_addr *addr; struct ifaddrmsg *ifa; struct nlmsghdr *nlh; int err, peer_prefix = 0; nlh = nlmsg_hdr(msg); addr = rtnl_addr_alloc(); if (!addr) goto errout; err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy); if (err < 0) goto errout_free; ifa = nlmsg_data(nlh); addr->a_family = ifa->ifa_family; addr->a_prefixlen = ifa->ifa_prefixlen; addr->a_flags = ifa->ifa_flags; addr->a_scope = ifa->ifa_scope; addr->a_ifindex = ifa->ifa_index; addr->a_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN | ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX); if (tb[IFA_LABEL]) { nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ); addr->a_mask |= ADDR_ATTR_LABEL; } if (tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ca; ca = nla_data(tb[IFA_CACHEINFO]); addr->a_cacheinfo.aci_prefered = ca->ifa_prefered; addr->a_cacheinfo.aci_valid = ca->ifa_valid; addr->a_cacheinfo.aci_cstamp = ca->cstamp; addr->a_cacheinfo.aci_tstamp = ca->tstamp; addr->a_mask |= ADDR_ATTR_CACHEINFO; } if (tb[IFA_LOCAL]) { addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family); if (!addr->a_local) goto errout_free; addr->a_mask |= ADDR_ATTR_LOCAL; } if (tb[IFA_ADDRESS]) { struct nl_addr *a; a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family); if (!a) goto errout_free; /* IPv6 sends the local address as IFA_ADDRESS with * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS * with IFA_ADDRESS being the peer address if they differ */ if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) { addr->a_local = a; addr->a_mask |= ADDR_ATTR_LOCAL; } else { addr->a_peer = a; addr->a_mask |= ADDR_ATTR_PEER; peer_prefix = 1; } } nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local, addr->a_prefixlen); if (tb[IFA_BROADCAST]) { addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family); if (!addr->a_bcast) goto errout_free; addr->a_mask |= ADDR_ATTR_BROADCAST; } if (tb[IFA_ANYCAST]) { addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family); if (!addr->a_anycast) goto errout_free; addr->a_mask |= ADDR_ATTR_ANYCAST; } if (tb[IFA_MULTICAST]) { addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST], addr->a_family); if (!addr->a_multicast) goto errout_free; addr->a_mask |= ADDR_ATTR_MULTICAST; } return addr; errout_free: rtnl_addr_free(addr); errout: return NULL; }
void nl_bridge::update_access_ports(rtnl_link *vxlan_link, rtnl_link *br_link, const uint16_t vid, const uint32_t tunnel_id, const std::deque<rtnl_link *> &bridge_ports, bool add) { // XXX pvid is currently not taken into account for (auto _br_port : bridge_ports) { auto br_port_vlans = rtnl_link_bridge_get_port_vlan(_br_port); if (rtnl_link_get_ifindex(vxlan_link) == rtnl_link_get_ifindex(_br_port)) continue; if (br_port_vlans == nullptr) continue; if (!is_vid_set(vid, br_port_vlans->vlan_bitmap)) continue; bool untagged = is_vid_set(vid, br_port_vlans->untagged_bitmap); int ifindex = rtnl_link_get_ifindex(_br_port); uint32_t pport_no = nl->get_port_id(ifindex); if (pport_no == 0) { LOG(WARNING) << __FUNCTION__ << ": ignoring unknown port " << OBJ_CAST(_br_port); continue; } rtnl_link *link = nl->get_link(rtnl_link_get_ifindex(_br_port), AF_UNSPEC); VLOG(2) << __FUNCTION__ << ": vid=" << vid << ", untagged=" << untagged << ", tunnel_id=" << tunnel_id << ", add=" << add << ", ifindex=" << ifindex << ", pport_no=" << pport_no << ", port: " << OBJ_CAST(_br_port); if (add) { std::string port_name = std::string(rtnl_link_get_name(_br_port)); // this is no longer a normal bridge interface thus we delete all the // bridging entries sw->l2_addr_remove_all_in_vlan(pport_no, vid); vxlan->create_access_port(_br_port, tunnel_id, port_name, pport_no, vid, untagged, nullptr); auto neighs = get_fdb_entries_of_port(_br_port, vid); for (auto n : neighs) { // ignore ll addr of bridge on slave if (nl_addr_cmp(rtnl_link_get_addr(bridge), rtnl_neigh_get_lladdr(n)) == 0) { continue; } VLOG(3) << ": needs to be updated " << OBJ_CAST(n); vxlan->add_l2_neigh(n, link, br_link); } } else { // delete access port and all bridging entries vxlan->delete_access_port(_br_port, pport_no, vid, true); // XXX FIXME check if we have to add the VLANs again (ingress/egress) } } }