Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:lafenghu
open-fcoe
fcoe-utils-use-san-mac-and-fix
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File fcoe-utils-use-san-mac-and-fix of Package open-fcoe
fcoe-utils: use SAN MAC and fix VLAN discovery to be per interface with bond This patch combines following patches from Chris and Yi to fix SAN MAC and VLAN discovery with bond:- fcoe-utils: use SAN MAC if available for FIP VLAN Request in lib/fip fcoe-utils: add getting SAN MAC via dcbnl interface to lib /rtnetlink fcoemon: use a separate packet socket per-interface for vlan discovery fipvlan: use a seperate packet socket for each interface fcoe-utils: fix VLAN discovery when the interface is also part of a bond --- fcoemon.c | 29 +++++++----- fipvlan.c | 106 +++++++++++++++++++++++++++++++------------ include/fip.h | 2 + include/rtnetlink.h | 1 lib/fip.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++-- lib/rtnetlink.c | 72 +++++++++++++++++++++++++++++ 6 files changed, 289 insertions(+), 46 deletions(-) diff --git a/fcoemon.c b/fcoemon.c index cae308c..42ad99e 100644 --- a/fcoemon.c +++ b/fcoemon.c @@ -130,6 +130,7 @@ struct fcoe_port { unsigned char mac[ETHER_ADDR_LEN]; struct sa_timer vlan_disc_timer; int vlan_disc_count; + int fip_socket; }; enum fcoeport_ifname { @@ -174,8 +175,6 @@ static void fcm_link_getlink(void); static int fcm_link_buf_check(size_t); static void clear_dcbd_info(struct fcm_netif *ff); -static int fcm_fip_socket; - /* * Table for getopt_long(3). */ @@ -568,21 +567,23 @@ int fcm_vlan_disc_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg) static void fcm_fip_recv(void *arg) { - fip_recv(fcm_fip_socket, fcm_vlan_disc_handler, NULL); + struct fcoe_port *p = arg; + fip_recv(p->fip_socket, fcm_vlan_disc_handler, NULL); } -static int fcm_vlan_disc_init(void) +static int fcm_vlan_disc_socket(struct fcoe_port *p) { int fd; + int origdev = 1; - fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_FIP)); + fd = fip_socket(p->ifindex); if (fd < 0) { FCM_LOG_ERR(errno, "socket error"); return fd; } - fcm_fip_socket = fd; - sa_select_add_fd(fd, fcm_fip_recv, NULL, NULL, NULL); - return 0; + setsockopt(fd, SOL_PACKET, PACKET_ORIGDEV, &origdev, sizeof(origdev)); + sa_select_add_fd(fd, fcm_fip_recv, NULL, NULL, p); + return fd; } @@ -1974,14 +1975,21 @@ void fcm_vlan_disc_timeout(void *arg) fcp_set_next_action(p, FCP_ACTIVATE_IF); return; } - fip_send_vlan_request(fcm_fip_socket, p->ifindex, p->mac); + fip_send_vlan_request(p->fip_socket, p->ifindex, p->mac); sa_timer_set(&p->vlan_disc_timer, FCM_VLAN_DISC_TIMEOUT); } int fcm_start_vlan_disc(struct fcoe_port *p) { + int s; + if (!p->fip_socket) { + s = fcm_vlan_disc_socket(p); + if (s < 0) + return s; + p->fip_socket = s; + } p->vlan_disc_count = 1; - fip_send_vlan_request(fcm_fip_socket, p->ifindex, p->mac); + fip_send_vlan_request(p->fip_socket, p->ifindex, p->mac); sa_timer_set(&p->vlan_disc_timer, FCM_VLAN_DISC_TIMEOUT); return 0; } @@ -2625,7 +2633,6 @@ int main(int argc, char **argv) fcm_fcoe_init(); fcm_link_init(); /* NETLINK_ROUTE protocol */ fcm_dcbd_init(); - fcm_vlan_disc_init(); fcm_srv_create(&srv_info); sa_select_set_callback(fcm_handle_changes); diff --git a/fipvlan.c b/fipvlan.c index 1f5556b..432ff84 100644 --- a/fipvlan.c +++ b/fipvlan.c @@ -34,10 +34,10 @@ #include <net/if.h> #include <net/if_arp.h> #include <net/ethernet.h> -#include <netpacket/packet.h> #include <arpa/inet.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> +#include <linux/if_packet.h> #include <sys/stat.h> #include <fcntl.h> @@ -72,9 +72,45 @@ struct { char *exe; +static struct pollfd *pfd = NULL; +static int pfd_len = 0; + +void pfd_add(int fd) +{ + struct pollfd *npfd; + + npfd = realloc(pfd, (pfd_len + 1) * sizeof(struct pollfd)); + if (!npfd) { + perror("realloc fail"); + return; + } + pfd = npfd; + pfd[pfd_len].fd = fd; + pfd[pfd_len].events = POLLIN; + pfd_len++; +} + +void pfd_remove(int fd) +{ + struct pollfd *npfd; + int i; + + for (i = 0; i < pfd_len; i++) { + if (pfd[i].fd == fd) + break; + } + if (i == pfd_len) + return; + memmove(&pfd[i], &pfd[i+1], (--pfd_len - i) * sizeof(struct pollfd)); + npfd = realloc(pfd, pfd_len * sizeof(struct pollfd)); + if (npfd) + pfd = npfd; +} + TAILQ_HEAD(iff_list_head, iff); struct iff { + int ps; /* packet socket file descriptor */ int ifindex; int iflink; char ifname[IFNAMSIZ]; @@ -266,6 +302,7 @@ void rtnl_recv_newlink(struct nlmsghdr *nh) struct rtattr *linkinfo[__IFLA_INFO_MAX]; struct rtattr *vlan[__IFLA_VLAN_MAX]; struct iff *iff, *real_dev; + int origdev = 1; FIP_LOG_DBG("RTM_NEWLINK: ifindex %d, type %d", ifm->ifi_index, ifm->ifi_type); @@ -302,6 +339,7 @@ void rtnl_recv_newlink(struct nlmsghdr *nh) if (ifla[IFLA_LINKINFO]) { parse_linkinfo(linkinfo, ifla[IFLA_LINKINFO]); + /* Track VLAN devices separately */ if (linkinfo[IFLA_INFO_KIND] && !strcmp(RTA_DATA(linkinfo[IFLA_INFO_KIND]), "vlan")) { iff->is_vlan = true; @@ -315,7 +353,17 @@ void rtnl_recv_newlink(struct nlmsghdr *nh) TAILQ_INSERT_TAIL(&real_dev->vlans, iff, list_node); return; } + /* ignore bonding interfaces */ + if (linkinfo[IFLA_INFO_KIND] && + !strcmp(RTA_DATA(linkinfo[IFLA_INFO_KIND]), "bond")) { + free(iff); + return; + } } + iff->ps = fip_socket(iff->ifindex); + setsockopt(iff->ps, SOL_PACKET, PACKET_ORIGDEV, + &origdev, sizeof(origdev)); + pfd_add(iff->ps); TAILQ_INSERT_TAIL(&interfaces, iff, list_node); } @@ -488,18 +536,13 @@ void print_results() printf("\n"); } -void recv_loop(int ns, int ps, int timeout) +void recv_loop(struct pollfd *pfd, int pfd_len, int timeout) { - struct pollfd pfd[2] = { - [0].fd = ns, - [0].events = POLLIN, - [1].fd = ps, - [1].events = POLLIN, - }; + int i; int rc; while (1) { - rc = poll(pfd, ARRAY_SIZE(pfd), timeout); + rc = poll(pfd, pfd_len, timeout); FIP_LOG_DBG("return from poll %d", rc); if (rc == 0) /* timeout */ break; @@ -507,12 +550,16 @@ void recv_loop(int ns, int ps, int timeout) FIP_LOG_ERRNO("poll error"); break; } + /* pfd[0] must be the netlink socket */ if (pfd[0].revents) - rtnl_recv(ns, rtnl_listener_handler, NULL); - if (pfd[1].revents) - fip_recv(ps, fip_vlan_handler, NULL); + rtnl_recv(pfd[0].fd, rtnl_listener_handler, NULL); pfd[0].revents = 0; - pfd[1].revents = 0; + /* everything else should be FIP packet sockets */ + for (i = 1; i < pfd_len; i++) { + if (pfd[i].revents) + fip_recv(pfd[i].fd, fip_vlan_handler, NULL); + pfd[i].revents = 0; + } } } @@ -522,7 +569,7 @@ void find_interfaces(int ns) rtnl_recv(ns, rtnl_listener_handler, NULL); } -int send_vlan_requests(int ps) +int send_vlan_requests(void) { struct iff *iff; int i; @@ -537,7 +584,9 @@ int send_vlan_requests(int ps) iff->req_sent = false; continue; } - fip_send_vlan_request(ps, iff->ifindex, iff->mac_addr); + fip_send_vlan_request(iff->ps, + iff->ifindex, + iff->mac_addr); iff->req_sent = true; } } else { @@ -554,29 +603,31 @@ int send_vlan_requests(int ps) iff->req_sent = false; continue; } - fip_send_vlan_request(ps, iff->ifindex, iff->mac_addr); + fip_send_vlan_request(iff->ps, + iff->ifindex, + iff->mac_addr); iff->req_sent = true; } } return skipped; } -void do_vlan_discovery(ns, ps) +void do_vlan_discovery(void) { struct iff *iff; int retry_count = 0; int skip_retry_count = 0; int skipped = 0; retry: - skipped += send_vlan_requests(ps); + skipped += send_vlan_requests(); if (skipped && skip_retry_count++ < 30) { FIP_LOG_DBG("waiting for IFF_RUNNING [%d]\n", skip_retry_count); - recv_loop(ns, ps, 500); + recv_loop(pfd, pfd_len, 500); skipped = 0; retry_count = 0; goto retry; } - recv_loop(ns, ps, 200); + recv_loop(pfd, pfd_len, 200); TAILQ_FOREACH(iff, &interfaces, list_node) /* if we did not receive a response, retry */ if (iff->req_sent && !iff->resp_recv && retry_count++ < 10) { @@ -587,7 +638,7 @@ retry: int main(int argc, char **argv) { - int ps, ns; + int ns; int rc = 0; exe = strrchr(argv[0], '/'); @@ -601,26 +652,21 @@ int main(int argc, char **argv) sa_log_flags = 0; enable_debug_log(0); - ps = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_FIP)); - if (ps < 0) { - rc = ps; - goto ps_err; - } ns = rtnl_socket(); if (ns < 0) { rc = ns; goto ns_err; } + pfd_add(ns); find_interfaces(ns); if (TAILQ_EMPTY(&interfaces)) { FIP_LOG_ERR(ENODEV, "no interfaces to perform discovery on"); - close(ps); exit(1); } - do_vlan_discovery(ns, ps); + do_vlan_discovery(); print_results(); if (config.create) { @@ -629,14 +675,12 @@ int main(int argc, char **argv) * need to listen for the RTM_NETLINK messages * about the new VLAN devices */ - recv_loop(ns, ps, 500); + recv_loop(pfd, pfd_len, 500); } if (config.start) start_fcoe(); close(ns); ns_err: - close(ps); -ps_err: exit(rc); } diff --git a/include/fip.h b/include/fip.h index 5f39763..ae8a365 100644 --- a/include/fip.h +++ b/include/fip.h @@ -129,6 +129,8 @@ struct fip_tlv_vlan { /* libutil / fip.c functionality */ +int fip_socket(int ifindex); + /* FIP message handler, passed into fip_recv */ typedef int fip_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg); diff --git a/include/rtnetlink.h b/include/rtnetlink.h index 167748e..13e54a4 100644 --- a/include/rtnetlink.h +++ b/include/rtnetlink.h @@ -28,6 +28,7 @@ int rtnl_set_iff_up(int ifindex, char *ifname); int vlan_create(int ifindex, int vid, char *name); int rtnl_find_vlan(int ifindex, int vid, char *ifname); int rtnl_get_linkname(int ifindex, char *name); +int rtnl_get_sanmac(const char *ifname, unsigned char *addr); static inline void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) { diff --git a/lib/fip.c b/lib/fip.c index b0bf07d..4db245f 100644 --- a/lib/fip.c +++ b/lib/fip.c @@ -35,12 +35,13 @@ #include <net/if.h> #include <net/if_arp.h> #include <net/ethernet.h> -#include <netpacket/packet.h> #include <arpa/inet.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> +#include <linux/if_packet.h> #include "fip.h" #include "fcoemon_utils.h" +#include "rtnetlink.h" #define FIP_LOG(...) sa_log(__VA_ARGS__) #define FIP_LOG_ERR(error, ...) sa_log_err(error, __func__, __VA_ARGS__) @@ -49,6 +50,120 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +static int fip_mac_is_valid(unsigned char *mac) +{ + if (0x01 & mac[0]) + return 0; + return !!(mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5]); +} + +/** + * fip_get_sanmac - get SAN MAC through dcbnl interface + * @ifindex: network interface index to send on + * @addr: output buffer to the SAN MAC address + * + * Returns 0 for success, none 0 for failure + */ +static int fip_get_sanmac(int ifindex, unsigned char *addr) +{ + int s; + int rc = -EIO; + struct ifreq ifr; + + memset(addr, 0, ETHER_ADDR_LEN); + s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (s < 0) + return s; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_ifindex = ifindex; + rc = ioctl(s, SIOCGIFNAME, &ifr); + close(s); + if (rc) + return rc; + + rc = rtnl_get_sanmac(ifr.ifr_name, addr); + if (rc) + return rc; + + return !fip_mac_is_valid(addr); +} + +/** + * fip_socket_sanmac - add SAN MAC to the unicast list for input socket + * @s: ETH_P_FIP packet socket to setsockopt on + * @ifindex: network interface index to send on + * @add: 1 to add 0 to del + */ +static void fip_socket_sanmac(int s, int ifindex, int add) +{ + struct packet_mreq mr; + unsigned char smac[ETHER_ADDR_LEN]; + + if (fip_get_sanmac(ifindex, smac)) + return; + + memset(&mr, 0, sizeof(mr)); + mr.mr_ifindex = ifindex; + mr.mr_type = PACKET_MR_UNICAST; + mr.mr_alen = ETHER_ADDR_LEN; + memcpy(mr.mr_address, smac, ETHER_ADDR_LEN); + if (setsockopt(s, SOL_PACKET, + (add) ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, + &mr, sizeof(mr)) < 0) + FIP_LOG_DBG("PACKET_%s_MEMBERSHIP:failed\n", + (add) ? "ADD" : "DROP"); +} + +/** + * fip_ethhdr - fills up the ethhdr for FIP + * @ifindex: network interface index to send on + * @mac: mac address of the sending network interface + * @eh: buffer for ether header + * + * Note: assuming no VLAN + */ +static void fip_ethhdr(int ifindex, unsigned char *mac, struct ethhdr *eh) +{ + unsigned char smac[ETHER_ADDR_LEN]; + unsigned char dmac[ETHER_ADDR_LEN] = FIP_ALL_FCF_MACS; + if (fip_get_sanmac(ifindex, smac)) + memcpy(smac, mac, ETHER_ADDR_LEN); + + eh->h_proto = htons(ETH_P_FIP); + memcpy(eh->h_source, smac, ETHER_ADDR_LEN); + memcpy(eh->h_dest, dmac, ETHER_ADDR_LEN); +} + +/** + * fip_socket - create and bind a packet socket for FIP + */ +int fip_socket(int ifindex) +{ + struct sockaddr_ll sa = { + .sll_family = AF_PACKET, + .sll_protocol = htons(ETH_P_FIP), + .sll_ifindex = ifindex, + }; + int s; + int rc; + + s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_FIP)); + if (s < 0) + return s; + + fip_socket_sanmac(s, ifindex, 1); + + rc = bind(s, (struct sockaddr *) &sa, sizeof(sa)); + if (rc < 0) { + close(s); + return rc; + } + + return s; +} + + /** * fip_send_vlan_request - send a FIP VLAN request * @s: ETH_P_FIP packet socket to send on @@ -83,7 +198,9 @@ ssize_t fip_send_vlan_request(int s, int ifindex, unsigned char *mac) .hdr.tlv_len = 2, }, }; + struct ethhdr eh; struct iovec iov[] = { + { .iov_base = &eh, .iov_len = sizeof(eh), }, { .iov_base = &fh, .iov_len = sizeof(fh), }, { .iov_base = &tlvs, .iov_len = sizeof(tlvs), }, }; @@ -95,8 +212,8 @@ ssize_t fip_send_vlan_request(int s, int ifindex, unsigned char *mac) }; int rc; - memcpy(tlvs.mac.mac_addr, mac, ETHER_ADDR_LEN); - + fip_ethhdr(ifindex, mac, &eh); + memcpy(tlvs.mac.mac_addr, eh.h_source, ETHER_ADDR_LEN); FIP_LOG_DBG("sending FIP VLAN request"); rc = sendmsg(s, &msg, 0); if (rc < 0) { @@ -139,7 +256,7 @@ int fip_recv(int s, fip_handler *fn, void *arg) return -1; } - fh = (struct fiphdr *) buf; + fh = (struct fiphdr *) (buf + sizeof(struct ethhdr)); desc_len = ntohs(fh->fip_desc_len); if (len < (sizeof(*fh) + (desc_len << 2))) { diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c index a8a8b0c..118979e 100644 --- a/lib/rtnetlink.c +++ b/lib/rtnetlink.c @@ -38,6 +38,7 @@ #include <arpa/inet.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> +#include <linux/dcbnl.h> #include "rtnetlink.h" #include "fcoemon_utils.h" @@ -46,6 +47,8 @@ #define RTNL_LOG_ERRNO(...) sa_log_err(errno, __func__, __VA_ARGS__) #define RTNL_LOG_DBG(...) sa_log_debug(__VA_ARGS__) +#define NLA_DATA(nla) ((void *)((char*)(nla) + NLA_HDRLEN)) + /** * rtnl_socket - create and bind a routing netlink socket */ @@ -426,3 +429,72 @@ out: close(s); return rc; } + +int rtnl_get_sanmac(const char *ifname, unsigned char *addr) +{ + int s; + int rc = -EIO; + struct { + struct nlmsghdr nh; + struct dcbmsg dcb; + char attrbuf[1204]; + } req = { + .nh = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct dcbmsg)), + .nlmsg_type = RTM_GETDCB, + .nlmsg_pid = getpid(), + .nlmsg_flags = NLM_F_REQUEST, + }, + .dcb = { + .cmd = DCB_CMD_GPERM_HWADDR, + .dcb_family = AF_UNSPEC, + .dcb_pad = 0, + }, + }; + + struct nlmsghdr *nh = &req.nh; + struct dcbmsg *dcb; + struct rtattr *rta; + unsigned char *smac; + + /* prep the message */ + memset((void *)req.attrbuf, 0, sizeof(req.attrbuf)); + add_rtattr(nh, DCB_ATTR_IFNAME, (void *)ifname, strlen(ifname) + 1); + add_rtattr(nh, DCB_ATTR_PERM_HWADDR, NULL, 0); + + s = rtnl_socket(); + if (s < 0) { + RTNL_LOG_ERRNO("failed to create the socket"); + return s; + } + + rc = send(s, (void *)nh, nh->nlmsg_len, 0); + if (rc < 0) { + RTNL_LOG_ERRNO("failed to send to the socket"); + goto err_close; + } + + memset((void *)&req, 0, sizeof(req)); + rc = recv(s, (void *)&req, sizeof(req), 0); + if (rc < 0) { + RTNL_LOG_ERRNO("failed to recv from the socket"); + rc = -EIO; + goto err_close; + } + + dcb = (struct dcbmsg *)NLMSG_DATA(nh); + rta = (struct rtattr *)(((char *)dcb) + + NLMSG_ALIGN(sizeof(struct dcbmsg))); + if ((nh->nlmsg_type != RTM_GETDCB) || + (dcb->cmd != DCB_CMD_GPERM_HWADDR) || + (rta->rta_type != DCB_ATTR_PERM_HWADDR)) { + RTNL_LOG_DBG("Unexpected netlink response for GPERM_HWADDR\n"); + rc = -EIO; + goto err_close; + } + memcpy(addr, NLA_DATA(rta) + ETH_ALEN, ETH_ALEN); + rc = 0; +err_close: + close(s); + return rc; +}
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor