The FIP_VN2VN option is used to indicate that the node should respond to VN2VN FIP requests to facilitate VLAN discovery in VN2VN environments.
Signed-off-by: Mark Rustad <[email protected]> Tested-by: Jack Morgan <[email protected]> --- fcoemon.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- fipvlan.c | 2 - include/fip.h | 17 +++++++ lib/fip.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 270 insertions(+), 18 deletions(-) diff --git a/fcoemon.c b/fcoemon.c index 558e2c0..7f20a7b 100644 --- a/fcoemon.c +++ b/fcoemon.c @@ -104,6 +104,7 @@ #define CFG_IF_VAR_DCBREQUIRED "DCB_REQUIRED" #define CFG_IF_VAR_AUTOVLAN "AUTO_VLAN" #define CFG_IF_VAR_MODE "MODE" +#define CFG_IF_VAR_FIP_RESP "FIP_RESP" enum fcoe_mode { FCOE_MODE_FABRIC = 0, @@ -130,6 +131,7 @@ struct fcoe_port { int fcoe_enable; int dcb_required; enum fcoe_mode mode; + bool fip_resp; int auto_vlan; int auto_created; int ready; @@ -145,6 +147,7 @@ struct fcoe_port { struct sa_timer vlan_disc_timer; int vlan_disc_count; int fip_socket; + int fip_responder_socket; char fchost[FCHOSTBUFLEN]; char ctlr[FCHOSTBUFLEN]; uint32_t last_fc_event_num; @@ -331,6 +334,7 @@ static void fcm_link_recv(void *); 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 fcoe_vid_from_ifname(const char *ifname); /* * Table for getopt_long(3). @@ -454,6 +458,7 @@ static struct fcoe_port *alloc_fcoe_port(char *ifname) */ p->last_action = FCP_DESTROY_IF; p->fip_socket = -1; + p->fip_responder_socket = -1; p->fchost[0] = '\0'; p->last_fc_event_num = 0; sa_timer_init(&p->vlan_disc_timer, fcm_vlan_disc_timeout, p); @@ -570,6 +575,23 @@ static int fcm_read_config_files(void) if (!strncasecmp(val, "yes", 3) && rc == 1) next->auto_vlan = 1; + /* FIP_RESP */ + rc = fcm_read_config_variable(file, val, sizeof(val), + fp, CFG_IF_VAR_FIP_RESP); + if (rc < 0) { + FCM_LOG("Invalid format for %s variable in %s", + CFG_IF_VAR_FIP_RESP, file); + fclose(fp); + free(next); + continue; + } + /* if not found, default to "none" */ + next->fip_resp = false; + if (!strcasecmp(val, "yes") && rc == 1) { + FCM_LOG("Starting FIP responder on %s", next->ifname); + next->fip_resp = true; + } + /* MODE */ rc = fcm_read_config_variable(file, val, sizeof(val), fp, CFG_IF_VAR_MODE); @@ -958,12 +980,17 @@ int fcm_vlan_disc_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg) return -1; if (fh->fip_subcode == FIP_VLAN_NOTE_VN2VN && - (!p->auto_vlan || p->mode != FCOE_MODE_VN2VN)) + (!p->auto_vlan || p->mode != FCOE_MODE_VN2VN)) { + FCM_LOG_DBG("%s: vn2vn vlan notif: auto_vlan=%d, mode=%d\n", + __func__, p->auto_vlan, p->mode); return -1; + } if (fh->fip_subcode != FIP_VLAN_NOTE && - fh->fip_subcode != FIP_VLAN_NOTE_VN2VN) + fh->fip_subcode != FIP_VLAN_NOTE_VN2VN) { + FCM_LOG_DBG("%s: fip_subcode=%d\n", __func__, fh->fip_subcode); return -1; + } if (fh->fip_subcode == FIP_VLAN_NOTE_VN2VN) vn2vn = true; @@ -985,7 +1012,7 @@ int fcm_vlan_disc_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg) break; } vid = ntohs(((struct fip_tlv_vlan *)tlv)->vlan); - + FCM_LOG_DBG("%s: vid=%d\n", __func__, vid); if (vid) { vp = fcm_new_vlan(sa->sll_ifindex, vid, vn2vn); vp->dcb_required = p->dcb_required; @@ -1027,7 +1054,7 @@ static int fcm_vlan_disc_socket(struct fcoe_port *p) int fd; int origdev = 1; - fd = fip_socket(p->ifindex); + fd = fip_socket(p->ifindex, FIP_NONE); if (fd < 0) { FCM_LOG_ERR(errno, "socket error"); return fd; @@ -1386,6 +1413,100 @@ static void fcm_dcbd_state_set(struct fcm_netif *ff, ff->response_pending = 0; } +static int fip_recv_vlan_req(struct fiphdr *fh, struct sockaddr_ll *ssa, + struct fcoe_port *sp) +{ + struct fip_tlv_vlan *vlan_tlvs = NULL; + int vlan_count = 0; + struct fcoe_port *p; + int rc; + + /* Handle all FCoE ports which are on VLANs over this ifname. */ + p = fcm_find_fcoe_port(sp->real_ifname, FCP_REAL_IFNAME); + for (; p; p = fcm_find_next_fcoe_port(p, sp->real_ifname)) { + int vid; + struct fip_tlv_vlan *vtp; + + if (!p->ready) + continue; + if (p->mode != FCOE_MODE_VN2VN) + continue; + vid = fcoe_vid_from_ifname(p->ifname); + if (vid < 0) + continue; + vtp = realloc(vlan_tlvs, sizeof(*vlan_tlvs)); + if (!vtp) + break; + memset(&vtp[vlan_count], 0, sizeof(*vtp)); + vtp[vlan_count].hdr.tlv_type = FIP_TLV_VLAN; + vtp[vlan_count].hdr.tlv_len = 1; + vtp[vlan_count].vlan = htons(vid); + ++vlan_count; + vlan_tlvs = vtp; + } + + FCM_LOG_DBG("%s: %d vlans found\n", __func__, vlan_count); + rc = fip_send_vlan_notification(sp->fip_responder_socket, + ssa->sll_ifindex, sp->mac, + ssa->sll_addr, vlan_tlvs, vlan_count); + if (rc < 0) { + FCM_LOG_ERR(-rc, "%s: fip_send_vlan_notification error\n", + __func__); + } + if (vlan_tlvs) + free(vlan_tlvs); + return rc; +} + +static int fip_vlan_disc_handler(struct fiphdr *fh, struct sockaddr_ll *sa, + void *arg) +{ + struct fcoe_port *p = arg; + int rc = -1; + + if (ntohs(fh->fip_proto) != FIP_PROTO_VLAN) { + FCM_LOG_DBG("ignoring FIP packet, protocol %d\n", + ntohs(fh->fip_proto)); + return -1; + } + + switch (fh->fip_subcode) { + case FIP_VLAN_REQ: + FCM_LOG_DBG("received VLAN req, subcode=%d\n", fh->fip_subcode); + rc = fip_recv_vlan_req(fh, sa, p); + break; + default: + FCM_LOG_DBG("ignored FIP VLAN packet with subcode %d\n", + fh->fip_subcode); + break; + } + return rc; +} + +static void fip_responder(void *arg) +{ + struct fcoe_port *p = arg; + + fip_recv(p->fip_responder_socket, fip_vlan_disc_handler, p); +} + +static void init_fip_vn2vn_responder(struct fcoe_port *p) +{ + int s; + + if (p->fip_responder_socket >= 0) + return; + + s = fip_socket(p->ifindex, FIP_ALL_VN2VN); + if (s < 0) { + FCM_LOG_ERR(errno, "%s: Failed to get fip socket\n", p->ifname); + return; + } + p->fip_responder_socket = s; + FCM_LOG_DBG("%s: Adding FIP responder socket\n", p->ifname); + sa_select_add_fd(s, fip_responder, NULL, NULL, p); +} + static void update_fcoe_port_state(struct fcoe_port *p, unsigned int type, u_int8_t operstate, enum fcoeport_ifname t) { @@ -1409,6 +1530,9 @@ static void update_fcoe_port_state(struct fcoe_port *p, unsigned int type, (operstate == IF_OPER_UP))) ff->ff_operstate = operstate; + if (t == FCP_REAL_IFNAME && p->fip_resp) + init_fip_vn2vn_responder(p); + if (!p->fcoe_enable) { fcp_set_next_action(p, FCP_DESTROY_IF); return; diff --git a/fipvlan.c b/fipvlan.c index 98e7a22..edefe2f 100644 --- a/fipvlan.c +++ b/fipvlan.c @@ -710,7 +710,7 @@ static int probe_fip_interface(struct iff *iff) return 0; if (!iff->fip_ready) { - iff->ps = fip_socket(iff->ifindex); + iff->ps = fip_socket(iff->ifindex, FIP_NONE); setsockopt(iff->ps, SOL_PACKET, PACKET_ORIGDEV, &origdev, sizeof(origdev)); pfd_add(iff->ps); diff --git a/include/fip.h b/include/fip.h index 7dc2463..443d3c4 100644 --- a/include/fip.h +++ b/include/fip.h @@ -37,6 +37,7 @@ * the corresponding FIP multicast MAC address. */ enum fip_multi { + FIP_NONE = -1, FIP_ALL_FCOE = 0, FIP_ALL_ENODE = 1, FIP_ALL_FCF = 2, @@ -143,7 +144,7 @@ struct fip_tlv_vlan { /* libutil / fip.c functionality */ -int fip_socket(int ifindex); +int fip_socket(int ifindex, enum fip_multi multi); /* FIP message handler, passed into fip_recv */ typedef int fip_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg); @@ -166,4 +167,18 @@ int fip_recv(int s, fip_handler *fn, void *arg); ssize_t fip_send_vlan_request(int s, int ifindex, const unsigned char *mac, enum fip_multi); +/** + * fip_send_vlan_notification - send a FIP VLAN notification + * @s: ETH_P_FIP packet socket to send on + * @ifindex: network interface to send on + * @mac: mac address of the netif + * @dest: destination mac address + * @vtlvs: pointer to vlan tlvs to send + * @vlan_count: Number of vlan tlvs to send + */ +int +fip_send_vlan_notification(int s, int ifindex, const __u8 *mac, + const __u8 *dest, struct fip_tlv_vlan *, + int vlan_count); + #endif /* FIP_H */ diff --git a/lib/fip.c b/lib/fip.c index 1acc388..7a5d836 100644 --- a/lib/fip.c +++ b/lib/fip.c @@ -88,29 +88,62 @@ static int fip_get_sanmac(int ifindex, unsigned char *addr) } /** - * fip_socket_sanmac - add SAN MAC to the unicast list for input socket + * fip_socket_add_addr - add a MAC address to the 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 + * @add: true to add false to del + * @mac: MAC address to add or delete + * @multi: false if unicast, true if multicast address */ -static void fip_socket_sanmac(int s, int ifindex, int add) +static void +fip_socket_add_addr(int s, int ifindex, bool add, const __u8 *mac, bool multi) { 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_type = multi ? PACKET_MR_MULTICAST : PACKET_MR_UNICAST; mr.mr_alen = ETHER_ADDR_LEN; - memcpy(mr.mr_address, smac, ETHER_ADDR_LEN); + memcpy(mr.mr_address, mac, ETHER_ADDR_LEN); if (setsockopt(s, SOL_PACKET, - (add) ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, + add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0) FIP_LOG_DBG("PACKET_%s_MEMBERSHIP:failed\n", - (add) ? "ADD" : "DROP"); + add ? "ADD" : "DROP"); +} + +/** + * 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) +{ + unsigned char smac[ETHER_ADDR_LEN]; + + if (fip_get_sanmac(ifindex, smac)) { + FIP_LOG_DBG("%s: no sanmac, ifindex %d\n", __func__, ifindex); + return; + } + + fip_socket_add_addr(s, ifindex, add, smac, false); +} + +/** + * fip_socket_multi - add multicast MAC address to the input socket + * @s: ETH_P_FIP packet socket to setsockopt on + * @ifindex: network interface index to send on + * @add: true to add, false to del + * @multi: Multicast destination + */ +static void +fip_socket_multi(int s, int ifindex, bool add, enum fip_multi multi) +{ + __u8 smac[ETHER_ADDR_LEN] = FIP_ALL_FCOE_MACS; + + smac[ETHER_ADDR_LEN - 1] = multi; + fip_socket_add_addr(s, ifindex, add, smac, true); } /** @@ -160,8 +193,10 @@ static void drain_socket(int s) /** * fip_socket - create and bind a packet socket for FIP + * @ifindex: ifindex of netdevice to bind to + * @multi: Indication of any multicast address to bind to */ -int fip_socket(int ifindex) +int fip_socket(int ifindex, enum fip_multi multi) { struct sockaddr_ll sa = { .sll_family = AF_PACKET, @@ -176,6 +211,8 @@ int fip_socket(int ifindex) return s; fip_socket_sanmac(s, ifindex, 1); + if (multi != FIP_NONE) + fip_socket_multi(s, ifindex, true, multi); rc = bind(s, (struct sockaddr *) &sa, sizeof(sa)); if (rc < 0) { @@ -257,6 +294,82 @@ ssize_t fip_send_vlan_request(int s, int ifindex, const unsigned char *mac, } /** + * fip_send_vlan_notification - send a FIP VLAN notification + * @s: ETH_P_FIP packet socket to send on + * @ifindex: network interface index to send on + * @mac: mac address of the sending network interface + * @dest: destination mac address + * @tlvs: pointer to vlan tlvs to send + * @tlv_count: number of vlan tlvs to send + */ +int +fip_send_vlan_notification(int s, int ifindex, const __u8 *mac, + const __u8 *dest, struct fip_tlv_vlan *vtlvs, + int vlan_count) +{ + struct sockaddr_ll dsa = { + .sll_family = AF_PACKET, + .sll_protocol = htons(ETH_P_FIP), + .sll_ifindex = ifindex, + .sll_hatype = ARPHRD_ETHER, + .sll_pkttype = PACKET_OTHERHOST, + .sll_halen = ETHER_ADDR_LEN, + }; + struct fiphdr sfh = { + .fip_version = FIP_VERSION(1), + .fip_proto = htons(FIP_PROTO_VLAN), + .fip_subcode = FIP_VLAN_NOTE_VN2VN, + .fip_desc_len = htons(2), + .fip_flags = 0, + }; + struct { + struct fip_tlv_mac_addr mac; + } tlvs = { + .mac = { + .hdr.tlv_type = FIP_TLV_MAC_ADDR, + .hdr.tlv_len = 2, + }, + }; + struct ethhdr eh; + struct iovec iov[] = { + { .iov_base = &eh, .iov_len = sizeof(eh), }, + { .iov_base = &sfh, .iov_len = sizeof(sfh), }, + { .iov_base = &tlvs, .iov_len = sizeof(tlvs), }, + { .iov_base = NULL, .iov_len = 0, }, + }; + struct msghdr msg = { + .msg_name = &dsa, + .msg_namelen = sizeof(dsa), + .msg_iov = iov, + .msg_iovlen = ARRAY_SIZE(iov) - 1, + }; + int rc; + + if (vlan_count) { + sfh.fip_desc_len = htons(3); + iov[3].iov_base = vtlvs; + iov[3].iov_len = vlan_count * sizeof(*vtlvs); + msg.msg_iovlen = ARRAY_SIZE(iov); + } + + if (fip_get_sanmac(ifindex, eh.h_source)) + memcpy(eh.h_source, mac, ETHER_ADDR_LEN); + eh.h_proto = htons(ETH_P_FIP); + memcpy(dsa.sll_addr, dest, ETHER_ADDR_LEN); + memcpy(eh.h_dest, dest, ETHER_ADDR_LEN); + memcpy(tlvs.mac.mac_addr, eh.h_source, ETHER_ADDR_LEN); + rc = sendmsg(s, &msg, 0); + if (rc < 0) { + rc = -errno; + FIP_LOG_ERR(errno, "%s:sendmsg error\n", __func__); + } else { + FIP_LOG_DBG("%s: sent %d bytes to ifindex %d\n", + __func__, rc, ifindex); + } + return rc; +} + +/** * fip_recv - receive from a FIP packet socket * @s: packet socket with data ready to be received * @fn: FIP receive callback to process the payload _______________________________________________ fcoe-devel mailing list [email protected] http://lists.open-fcoe.org/mailman/listinfo/fcoe-devel
