2 * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "dpif-linux.h"
27 #include <linux/types.h>
28 #include <linux/ethtool.h>
29 #include <linux/pkt_sched.h>
30 #include <linux/rtnetlink.h>
31 #include <linux/sockios.h>
33 #include <sys/ioctl.h>
37 #include "dpif-provider.h"
39 #include "netdev-vport.h"
42 #include "openvswitch/tunnel.h"
44 #include "poll-loop.h"
45 #include "rtnetlink.h"
46 #include "rtnetlink-link.h"
52 VLOG_DEFINE_THIS_MODULE(dpif_linux
);
54 /* Datapath interface for the openvswitch Linux kernel module. */
59 /* Used by dpif_linux_get_all_names(). */
63 /* Change notification. */
64 int local_ifindex
; /* Ifindex of local port. */
65 struct shash changed_ports
; /* Ports that have changed. */
66 struct rtnetlink_notifier port_notifier
;
70 static struct vlog_rate_limit error_rl
= VLOG_RATE_LIMIT_INIT(9999, 5);
72 static int do_ioctl(const struct dpif
*, int cmd
, const void *arg
);
73 static int lookup_internal_device(const char *name
, int *dp_idx
, int *port_no
);
74 static int lookup_minor(const char *name
, int *minor
);
75 static int finish_open(struct dpif
*, const char *local_ifname
);
76 static int get_openvswitch_major(void);
77 static int create_minor(const char *name
, int minor
, struct dpif
**dpifp
);
78 static int open_minor(int minor
, struct dpif
**dpifp
);
79 static int make_openvswitch_device(int minor
, char **fnp
);
80 static void dpif_linux_port_changed(const struct rtnetlink_link_change
*,
83 static struct dpif_linux
*
84 dpif_linux_cast(const struct dpif
*dpif
)
86 dpif_assert_class(dpif
, &dpif_linux_class
);
87 return CONTAINER_OF(dpif
, struct dpif_linux
, dpif
);
91 dpif_linux_enumerate(struct svec
*all_dps
)
97 /* Check that the Open vSwitch module is loaded. */
98 major
= get_openvswitch_major();
104 for (i
= 0; i
< ODP_MAX
; i
++) {
109 sprintf(devname
, "dp%d", i
);
110 retval
= dpif_open(devname
, "system", &dpif
);
112 svec_add(all_dps
, devname
);
113 dpif_uninit(dpif
, true);
114 } else if (retval
!= ENODEV
&& !error
) {
122 dpif_linux_open(const struct dpif_class
*class OVS_UNUSED
, const char *name
,
123 bool create
, struct dpif
**dpifp
)
127 minor
= !strncmp(name
, "dp", 2)
128 && isdigit((unsigned char)name
[2]) ? atoi(name
+ 2) : -1;
131 return create_minor(name
, minor
, dpifp
);
133 /* Scan for unused minor number. */
134 for (minor
= 0; minor
< ODP_MAX
; minor
++) {
135 int error
= create_minor(name
, minor
, dpifp
);
136 if (error
!= EBUSY
) {
141 /* All datapath numbers in use. */
145 struct dpif_linux
*dpif
;
146 struct odp_port port
;
150 error
= lookup_minor(name
, &minor
);
156 error
= open_minor(minor
, dpifp
);
160 dpif
= dpif_linux_cast(*dpifp
);
162 /* We need the local port's ifindex for the poll function. Start by
163 * getting the local port's name. */
164 memset(&port
, 0, sizeof port
);
165 port
.port
= ODPP_LOCAL
;
166 if (ioctl(dpif
->fd
, ODP_VPORT_QUERY
, &port
)) {
168 if (error
!= ENODEV
) {
169 VLOG_WARN("%s: probe returned unexpected error: %s",
170 dpif_name(*dpifp
), strerror(error
));
172 dpif_uninit(*dpifp
, true);
176 /* Then use that to finish up opening. */
177 return finish_open(&dpif
->dpif
, port
.devname
);
182 dpif_linux_close(struct dpif
*dpif_
)
184 struct dpif_linux
*dpif
= dpif_linux_cast(dpif_
);
185 rtnetlink_link_notifier_unregister(&dpif
->port_notifier
);
186 shash_destroy(&dpif
->changed_ports
);
187 free(dpif
->local_ifname
);
193 dpif_linux_get_all_names(const struct dpif
*dpif_
, struct svec
*all_names
)
195 struct dpif_linux
*dpif
= dpif_linux_cast(dpif_
);
197 svec_add_nocopy(all_names
, xasprintf("dp%d", dpif
->minor
));
198 svec_add(all_names
, dpif
->local_ifname
);
203 dpif_linux_destroy(struct dpif
*dpif_
)
205 return do_ioctl(dpif_
, ODP_DP_DESTROY
, NULL
);
209 dpif_linux_get_stats(const struct dpif
*dpif_
, struct odp_stats
*stats
)
211 memset(stats
, 0, sizeof *stats
);
212 return do_ioctl(dpif_
, ODP_DP_STATS
, stats
);
216 dpif_linux_get_drop_frags(const struct dpif
*dpif_
, bool *drop_fragsp
)
221 error
= do_ioctl(dpif_
, ODP_GET_DROP_FRAGS
, &drop_frags
);
223 *drop_fragsp
= drop_frags
& 1;
229 dpif_linux_set_drop_frags(struct dpif
*dpif_
, bool drop_frags
)
231 int drop_frags_int
= drop_frags
;
232 return do_ioctl(dpif_
, ODP_SET_DROP_FRAGS
, &drop_frags_int
);
236 vport_type_to_netdev_type(const struct odp_port
*odp_port
)
238 struct tnl_port_config tnl_config
;
240 switch (odp_port
->type
) {
241 case ODP_VPORT_TYPE_UNSPEC
:
244 case ODP_VPORT_TYPE_NETDEV
:
247 case ODP_VPORT_TYPE_INTERNAL
:
250 case ODP_VPORT_TYPE_PATCH
:
253 case ODP_VPORT_TYPE_GRE
:
254 memcpy(&tnl_config
, odp_port
->config
, sizeof tnl_config
);
255 return tnl_config
.flags
& TNL_F_IPSEC
? "ipsec_gre" : "gre";
257 case ODP_VPORT_TYPE_CAPWAP
:
260 case __ODP_VPORT_TYPE_MAX
:
264 VLOG_WARN_RL(&error_rl
, "dp%d: port `%s' has unsupported type %"PRIu32
,
265 odp_port
->dp_idx
, odp_port
->devname
, odp_port
->type
);
269 static enum odp_vport_type
270 netdev_type_to_vport_type(const char *type
)
272 return (!strcmp(type
, "system") ? ODP_VPORT_TYPE_NETDEV
273 : !strcmp(type
, "internal") ? ODP_VPORT_TYPE_INTERNAL
274 : !strcmp(type
, "patch") ? ODP_VPORT_TYPE_PATCH
275 : (!strcmp(type
, "gre")
276 || !strcmp(type
, "ipsec_gre")) ? ODP_VPORT_TYPE_GRE
277 : !strcmp(type
, "capwap") ? ODP_VPORT_TYPE_CAPWAP
278 : ODP_VPORT_TYPE_UNSPEC
);
282 dpif_linux_port_add(struct dpif
*dpif
, struct netdev
*netdev
,
285 const char *name
= netdev_get_name(netdev
);
286 const char *type
= netdev_get_type(netdev
);
287 struct odp_port port
;
290 memset(&port
, 0, sizeof port
);
291 strncpy(port
.devname
, name
, sizeof port
.devname
);
292 netdev_vport_get_config(netdev
, port
.config
);
294 port
.type
= netdev_type_to_vport_type(type
);
295 if (port
.type
== ODP_VPORT_TYPE_UNSPEC
) {
296 VLOG_WARN_RL(&error_rl
, "%s: cannot create port `%s' because it has "
297 "unsupported type `%s'",
298 dpif_name(dpif
), name
, type
);
302 error
= do_ioctl(dpif
, ODP_VPORT_ATTACH
, &port
);
304 *port_nop
= port
.port
;
311 dpif_linux_port_del(struct dpif
*dpif_
, uint16_t port_no_
)
313 int port_no
= port_no_
; /* Kernel expects an "int". */
314 return do_ioctl(dpif_
, ODP_VPORT_DETACH
, &port_no
);
318 dpif_linux_port_query__(const struct dpif
*dpif
, uint32_t port_no
,
319 const char *port_name
, struct dpif_port
*dpif_port
)
321 struct odp_port odp_port
;
324 memset(&odp_port
, 0, sizeof odp_port
);
325 odp_port
.port
= port_no
;
326 strncpy(odp_port
.devname
, port_name
, sizeof odp_port
.devname
);
328 error
= do_ioctl(dpif
, ODP_VPORT_QUERY
, &odp_port
);
331 } else if (odp_port
.dp_idx
!= dpif_linux_cast(dpif
)->minor
) {
332 /* A vport named 'port_name' exists but in some other datapath. */
335 dpif_port
->name
= xstrdup(odp_port
.devname
);
336 dpif_port
->type
= xstrdup(vport_type_to_netdev_type(&odp_port
));
337 dpif_port
->port_no
= odp_port
.port
;
343 dpif_linux_port_query_by_number(const struct dpif
*dpif
, uint16_t port_no
,
344 struct dpif_port
*dpif_port
)
346 return dpif_linux_port_query__(dpif
, port_no
, "", dpif_port
);
350 dpif_linux_port_query_by_name(const struct dpif
*dpif
, const char *devname
,
351 struct dpif_port
*dpif_port
)
353 return dpif_linux_port_query__(dpif
, 0, devname
, dpif_port
);
357 dpif_linux_flow_flush(struct dpif
*dpif_
)
359 return do_ioctl(dpif_
, ODP_FLOW_FLUSH
, NULL
);
363 dpif_linux_port_dump_start(const struct dpif
*dpif OVS_UNUSED
, void **statep
)
365 *statep
= xzalloc(sizeof(struct odp_port
));
370 dpif_linux_port_dump_next(const struct dpif
*dpif
, void *state
,
371 struct dpif_port
*dpif_port
)
373 struct odp_port
*odp_port
= state
;
374 struct odp_vport_dump dump
;
377 dump
.port
= odp_port
;
378 dump
.port_no
= odp_port
->port
;
379 error
= do_ioctl(dpif
, ODP_VPORT_DUMP
, &dump
);
382 } else if (odp_port
->devname
[0] == '\0') {
385 dpif_port
->name
= odp_port
->devname
;
386 dpif_port
->type
= (char *) vport_type_to_netdev_type(odp_port
);
387 dpif_port
->port_no
= odp_port
->port
;
394 dpif_linux_port_dump_done(const struct dpif
*dpif OVS_UNUSED
, void *state
)
401 dpif_linux_port_poll(const struct dpif
*dpif_
, char **devnamep
)
403 struct dpif_linux
*dpif
= dpif_linux_cast(dpif_
);
405 if (dpif
->change_error
) {
406 dpif
->change_error
= false;
407 shash_clear(&dpif
->changed_ports
);
409 } else if (!shash_is_empty(&dpif
->changed_ports
)) {
410 struct shash_node
*node
= shash_first(&dpif
->changed_ports
);
411 *devnamep
= shash_steal(&dpif
->changed_ports
, node
);
419 dpif_linux_port_poll_wait(const struct dpif
*dpif_
)
421 struct dpif_linux
*dpif
= dpif_linux_cast(dpif_
);
422 if (!shash_is_empty(&dpif
->changed_ports
) || dpif
->change_error
) {
423 poll_immediate_wake();
425 rtnetlink_link_notifier_wait();
430 dpif_linux_flow_get(const struct dpif
*dpif_
, struct odp_flow flows
[], int n
)
432 struct odp_flowvec fv
;
435 return do_ioctl(dpif_
, ODP_FLOW_GET
, &fv
);
439 dpif_linux_flow_put(struct dpif
*dpif_
, struct odp_flow_put
*put
)
441 return do_ioctl(dpif_
, ODP_FLOW_PUT
, put
);
445 dpif_linux_flow_del(struct dpif
*dpif_
, struct odp_flow
*flow
)
447 return do_ioctl(dpif_
, ODP_FLOW_DEL
, flow
);
451 dpif_linux_flow_dump_start(const struct dpif
*dpif OVS_UNUSED
, void **statep
)
453 *statep
= xzalloc(sizeof(struct odp_flow_dump
));
458 dpif_linux_flow_dump_next(const struct dpif
*dpif
, void *state
,
459 struct odp_flow
*flow
)
461 struct odp_flow_dump
*dump
= state
;
465 error
= do_ioctl(dpif
, ODP_FLOW_DUMP
, dump
);
466 return error
? error
: flow
->flags
& ODPFF_EOF
? EOF
: 0;
470 dpif_linux_flow_dump_done(const struct dpif
*dpif OVS_UNUSED
, void *state
)
477 dpif_linux_execute(struct dpif
*dpif_
,
478 const struct nlattr
*actions
, size_t actions_len
,
479 const struct ofpbuf
*buf
)
481 struct odp_execute execute
;
482 memset(&execute
, 0, sizeof execute
);
483 execute
.actions
= (struct nlattr
*) actions
;
484 execute
.actions_len
= actions_len
;
485 execute
.data
= buf
->data
;
486 execute
.length
= buf
->size
;
487 return do_ioctl(dpif_
, ODP_EXECUTE
, &execute
);
491 dpif_linux_recv_get_mask(const struct dpif
*dpif_
, int *listen_mask
)
493 return do_ioctl(dpif_
, ODP_GET_LISTEN_MASK
, listen_mask
);
497 dpif_linux_recv_set_mask(struct dpif
*dpif_
, int listen_mask
)
499 return do_ioctl(dpif_
, ODP_SET_LISTEN_MASK
, &listen_mask
);
503 dpif_linux_get_sflow_probability(const struct dpif
*dpif_
,
504 uint32_t *probability
)
506 return do_ioctl(dpif_
, ODP_GET_SFLOW_PROBABILITY
, probability
);
510 dpif_linux_set_sflow_probability(struct dpif
*dpif_
, uint32_t probability
)
512 return do_ioctl(dpif_
, ODP_SET_SFLOW_PROBABILITY
, &probability
);
516 dpif_linux_queue_to_priority(const struct dpif
*dpif OVS_UNUSED
,
517 uint32_t queue_id
, uint32_t *priority
)
519 if (queue_id
< 0xf000) {
520 *priority
= TC_H_MAKE(1 << 16, queue_id
+ 1);
528 parse_odp_packet(struct ofpbuf
*buf
, struct dpif_upcall
*upcall
)
530 static const struct nl_policy odp_packet_policy
[] = {
531 /* Always present. */
532 [ODP_PACKET_ATTR_TYPE
] = { .type
= NL_A_U32
},
533 [ODP_PACKET_ATTR_PACKET
] = { .type
= NL_A_UNSPEC
,
534 .min_len
= ETH_HEADER_LEN
},
535 [ODP_PACKET_ATTR_KEY
] = { .type
= NL_A_NESTED
},
537 /* _ODPL_ACTION_NR only. */
538 [ODP_PACKET_ATTR_USERDATA
] = { .type
= NL_A_U64
, .optional
= true },
540 /* _ODPL_SFLOW_NR only. */
541 [ODP_PACKET_ATTR_SAMPLE_POOL
] = { .type
= NL_A_U32
, .optional
= true },
542 [ODP_PACKET_ATTR_ACTIONS
] = { .type
= NL_A_NESTED
, .optional
= true },
545 struct odp_packet
*odp_packet
= buf
->data
;
546 struct nlattr
*a
[ARRAY_SIZE(odp_packet_policy
)];
548 if (!nl_policy_parse(buf
, sizeof *odp_packet
, odp_packet_policy
,
549 a
, ARRAY_SIZE(odp_packet_policy
))) {
553 memset(upcall
, 0, sizeof *upcall
);
554 upcall
->type
= nl_attr_get_u32(a
[ODP_PACKET_ATTR_TYPE
]);
555 upcall
->packet
= buf
;
556 upcall
->packet
->data
= (void *) nl_attr_get(a
[ODP_PACKET_ATTR_PACKET
]);
557 upcall
->packet
->size
= nl_attr_get_size(a
[ODP_PACKET_ATTR_PACKET
]);
558 upcall
->key
= (void *) nl_attr_get(a
[ODP_PACKET_ATTR_KEY
]);
559 upcall
->key_len
= nl_attr_get_size(a
[ODP_PACKET_ATTR_KEY
]);
560 upcall
->userdata
= (a
[ODP_PACKET_ATTR_USERDATA
]
561 ? nl_attr_get_u64(a
[ODP_PACKET_ATTR_USERDATA
])
563 upcall
->sample_pool
= (a
[ODP_PACKET_ATTR_SAMPLE_POOL
]
564 ? nl_attr_get_u32(a
[ODP_PACKET_ATTR_SAMPLE_POOL
])
566 if (a
[ODP_PACKET_ATTR_ACTIONS
]) {
567 upcall
->actions
= (void *) nl_attr_get(a
[ODP_PACKET_ATTR_ACTIONS
]);
568 upcall
->actions_len
= nl_attr_get_size(a
[ODP_PACKET_ATTR_ACTIONS
]);
575 dpif_linux_recv(struct dpif
*dpif_
, struct dpif_upcall
*upcall
)
577 struct dpif_linux
*dpif
= dpif_linux_cast(dpif_
);
582 buf
= ofpbuf_new(65536);
583 retval
= read(dpif
->fd
, ofpbuf_tail(buf
), ofpbuf_tailroom(buf
));
586 if (error
!= EAGAIN
) {
587 VLOG_WARN_RL(&error_rl
, "%s: read failed: %s",
588 dpif_name(dpif_
), strerror(error
));
590 } else if (retval
>= sizeof(struct odp_packet
)) {
591 struct odp_packet
*odp_packet
= buf
->data
;
594 if (odp_packet
->len
<= retval
) {
595 error
= parse_odp_packet(buf
, upcall
);
597 VLOG_WARN_RL(&error_rl
, "%s: discarding message truncated "
598 "from %"PRIu32
" bytes to %d",
599 dpif_name(dpif_
), odp_packet
->len
, retval
);
602 } else if (!retval
) {
603 VLOG_WARN_RL(&error_rl
, "%s: unexpected end of file", dpif_name(dpif_
));
606 VLOG_WARN_RL(&error_rl
, "%s: discarding too-short message (%d bytes)",
607 dpif_name(dpif_
), retval
);
618 dpif_linux_recv_wait(struct dpif
*dpif_
)
620 struct dpif_linux
*dpif
= dpif_linux_cast(dpif_
);
621 poll_fd_wait(dpif
->fd
, POLLIN
);
624 const struct dpif_class dpif_linux_class
= {
628 dpif_linux_enumerate
,
631 dpif_linux_get_all_names
,
633 dpif_linux_get_stats
,
634 dpif_linux_get_drop_frags
,
635 dpif_linux_set_drop_frags
,
638 dpif_linux_port_query_by_number
,
639 dpif_linux_port_query_by_name
,
640 dpif_linux_port_dump_start
,
641 dpif_linux_port_dump_next
,
642 dpif_linux_port_dump_done
,
643 dpif_linux_port_poll
,
644 dpif_linux_port_poll_wait
,
648 dpif_linux_flow_flush
,
649 dpif_linux_flow_dump_start
,
650 dpif_linux_flow_dump_next
,
651 dpif_linux_flow_dump_done
,
653 dpif_linux_recv_get_mask
,
654 dpif_linux_recv_set_mask
,
655 dpif_linux_get_sflow_probability
,
656 dpif_linux_set_sflow_probability
,
657 dpif_linux_queue_to_priority
,
659 dpif_linux_recv_wait
,
662 static int get_openvswitch_major(void);
663 static int get_major(const char *target
);
666 do_ioctl(const struct dpif
*dpif_
, int cmd
, const void *arg
)
668 struct dpif_linux
*dpif
= dpif_linux_cast(dpif_
);
669 return ioctl(dpif
->fd
, cmd
, arg
) ? errno
: 0;
673 lookup_internal_device(const char *name
, int *dp_idx
, int *port_no
)
675 struct odp_port odp_port
;
676 static int dp0_fd
= -1;
682 error
= make_openvswitch_device(0, &fn
);
687 dp0_fd
= open(fn
, O_RDONLY
| O_NONBLOCK
);
689 VLOG_WARN_RL(&error_rl
, "%s: open failed (%s)",
690 fn
, strerror(errno
));
697 memset(&odp_port
, 0, sizeof odp_port
);
698 strncpy(odp_port
.devname
, name
, sizeof odp_port
.devname
);
699 if (ioctl(dp0_fd
, ODP_VPORT_QUERY
, &odp_port
)) {
700 if (errno
!= ENODEV
) {
701 VLOG_WARN_RL(&error_rl
, "%s: vport query failed (%s)",
702 name
, strerror(errno
));
705 } else if (odp_port
.type
== ODP_VPORT_TYPE_INTERNAL
) {
706 *dp_idx
= odp_port
.dp_idx
;
707 *port_no
= odp_port
.port
;
715 lookup_minor(const char *name
, int *minorp
)
720 error
= lookup_internal_device(name
, &minor
, &port_no
);
723 } else if (port_no
!= ODPP_LOCAL
) {
724 /* This is an Open vSwitch device but not the local port. We
725 * intentionally support only using the name of the local port as the
726 * name of a datapath; otherwise, it would be too difficult to
727 * enumerate all the names of a datapath. */
736 dpif_linux_is_internal_device(const char *name
)
740 return !lookup_internal_device(name
, &minor
, &port_no
);
744 make_openvswitch_device(int minor
, char **fnp
)
746 const char dirname
[] = "/dev/net";
754 major
= get_openvswitch_major();
758 dev
= makedev(major
, minor
);
760 sprintf(fn
, "%s/dp%d", dirname
, minor
);
762 if (!S_ISCHR(s
.st_mode
)) {
763 VLOG_WARN_RL(&error_rl
, "%s is not a character device, fixing",
765 } else if (s
.st_rdev
!= dev
) {
766 VLOG_WARN_RL(&error_rl
,
767 "%s is device %u:%u but should be %u:%u, fixing",
768 fn
, major(s
.st_rdev
), minor(s
.st_rdev
),
769 major(dev
), minor(dev
));
774 VLOG_WARN_RL(&error_rl
, "%s: unlink failed (%s)",
775 fn
, strerror(errno
));
778 } else if (errno
== ENOENT
) {
779 if (stat(dirname
, &s
)) {
780 if (errno
== ENOENT
) {
781 if (mkdir(dirname
, 0755)) {
782 VLOG_WARN_RL(&error_rl
, "%s: mkdir failed (%s)",
783 dirname
, strerror(errno
));
787 VLOG_WARN_RL(&error_rl
, "%s: stat failed (%s)",
788 dirname
, strerror(errno
));
793 VLOG_WARN_RL(&error_rl
, "%s: stat failed (%s)", fn
, strerror(errno
));
797 /* The device needs to be created. */
798 if (mknod(fn
, S_IFCHR
| 0700, dev
)) {
799 VLOG_WARN_RL(&error_rl
,
800 "%s: creating character device %u:%u failed (%s)",
801 fn
, major(dev
), minor(dev
), strerror(errno
));
810 /* Return the major device number of the Open vSwitch device. If it
811 * cannot be determined, a negative errno is returned. */
813 get_openvswitch_major(void)
815 static int openvswitch_major
= -1;
816 if (openvswitch_major
< 0) {
817 openvswitch_major
= get_major("openvswitch");
819 return openvswitch_major
;
823 get_major(const char *target
)
825 const char fn
[] = "/proc/devices";
830 file
= fopen(fn
, "r");
832 VLOG_ERR("opening %s failed (%s)", fn
, strerror(errno
));
836 for (ln
= 1; fgets(line
, sizeof line
, file
); ln
++) {
840 if (!strncmp(line
, "Character", 9) || line
[0] == '\0') {
842 } else if (!strncmp(line
, "Block", 5)) {
843 /* We only want character devices, so skip the rest of the file. */
845 } else if (sscanf(line
, "%d %63s", &major
, name
)) {
846 if (!strcmp(name
, target
)) {
851 VLOG_WARN_ONCE("%s:%d: syntax error", fn
, ln
);
857 VLOG_ERR("%s: %s major not found (is the module loaded?)", fn
, target
);
862 finish_open(struct dpif
*dpif_
, const char *local_ifname
)
864 struct dpif_linux
*dpif
= dpif_linux_cast(dpif_
);
865 dpif
->local_ifname
= xstrdup(local_ifname
);
866 dpif
->local_ifindex
= if_nametoindex(local_ifname
);
867 if (!dpif
->local_ifindex
) {
869 dpif_uninit(dpif_
, true);
870 VLOG_WARN("could not get ifindex of %s device: %s",
871 local_ifname
, strerror(errno
));
878 create_minor(const char *name
, int minor
, struct dpif
**dpifp
)
880 int error
= open_minor(minor
, dpifp
);
882 error
= do_ioctl(*dpifp
, ODP_DP_CREATE
, name
);
884 error
= finish_open(*dpifp
, name
);
886 dpif_uninit(*dpifp
, true);
893 open_minor(int minor
, struct dpif
**dpifp
)
899 error
= make_openvswitch_device(minor
, &fn
);
904 fd
= open(fn
, O_RDONLY
| O_NONBLOCK
);
906 struct dpif_linux
*dpif
= xmalloc(sizeof *dpif
);
907 error
= rtnetlink_link_notifier_register(&dpif
->port_notifier
,
908 dpif_linux_port_changed
,
913 name
= xasprintf("dp%d", minor
);
914 dpif_init(&dpif
->dpif
, &dpif_linux_class
, name
, minor
, minor
);
918 dpif
->local_ifname
= NULL
;
920 dpif
->local_ifindex
= 0;
921 shash_init(&dpif
->changed_ports
);
922 dpif
->change_error
= false;
923 *dpifp
= &dpif
->dpif
;
929 VLOG_WARN("%s: open failed (%s)", fn
, strerror(error
));
937 dpif_linux_port_changed(const struct rtnetlink_link_change
*change
,
940 struct dpif_linux
*dpif
= dpif_
;
943 if (change
->master_ifindex
== dpif
->local_ifindex
944 && (change
->nlmsg_type
== RTM_NEWLINK
945 || change
->nlmsg_type
== RTM_DELLINK
))
947 /* Our datapath changed, either adding a new port or deleting an
949 shash_add_once(&dpif
->changed_ports
, change
->ifname
, NULL
);
952 dpif
->change_error
= true;